//**************************************************************************************************
//                                         SimnGnuCap.cpp                                          *
//                                        ----------------                                         *
// Started     : 2008-05-07                                                                        *
// Last Update : 2018-10-30                                                                        *
// Copyright   : (C) 2008-2017 MSWaters                                                            *
//**************************************************************************************************

//**************************************************************************************************
//                                                                                                 *
//      This program is free software; you can redistribute it and/or modify it under the          *
//      terms of the GNU General Public License as published by the Free Software Foundation;      *
//      either version 3 of the License, or (at your option) any later version.                    *
//                                                                                                 *
//**************************************************************************************************

#include "SimnGnuCap.hpp"

//**************************************************************************************************
// Constructor.

SimnGnuCap::SimnGnuCap( void ) : SimnBase( )
{
  m_eSimEng = eSIMR_GNUCAP;

  // Initialize all object attributes
  bClear( );
}

//**************************************************************************************************
// Destructor.

SimnGnuCap::~SimnGnuCap( )
{
}

//**************************************************************************************************
// Extract the simulator engine and return true if it's GNU-Cap.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bLoadSimEng( void )
{
  wxString  os1;
  size_t    sz1;

  // Scan the circuit description for simulator type
  for( sz1=0; sz1<NetList::m_osaNetLst.GetCount( ); sz1++ )
  {
    os1 = NetList::m_osaNetLst.Item( sz1 );
    if( os1.IsEmpty( ) ) continue;
    if( os1.Upper( ).Contains( wxT("GNU-CAP") ) ) return( true );
  }

  return( false );
}

//**************************************************************************************************
// Extract all the simulator command lines from the circuit description.
// The following commands are currently detected and extracted :
//
//   .OPTIONS
//   .IC
//   .OP
//   .DC
//   .AC
//   .TRANSIENT
//   .FOURIER
//   .PRINT
//   .GENERATOR
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bLoadSimCmds( void )
{
  bool      bRtn=false;
  wxString  os1;
  size_t    sz1;

  // Scan the circuit description for simulation commands
  for( sz1=0; sz1<NetList::m_osaNetLst.GetCount( ); sz1++ )
  {
    os1 = NetList::m_osaNetLst.Item( sz1 );

    if( os1.IsEmpty( ) )               continue;
    if( ! os1.StartsWith( wxT(".") ) ) continue;

    os1.MakeUpper( );

    if(      os1.StartsWith( wxT(".OPT") ) ) // OPTIONS command
      m_oCmdOPT.bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".GEN") ) ) // GENERATOR command
      m_oCmdGEN.bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".OP")  ) ) // OP command
      m_oCmdOP .bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".DC")  ) ) // DC command
      m_oCmdDC .bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".AC")  ) ) // AC command
      m_oCmdAC .bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".TR")  ) ) // TRANSIENT command
      m_oCmdTR .bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".FO")  ) ) // FOURIER command
      m_oCmdFO .bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else if( os1.StartsWith( wxT(".PR")  ) ) // PRINT command
      m_oCmdPR.bSetString( NetList::m_osaNetLst.Item( sz1 ) );
    else                               continue;

    bRtn = true;
  }

  return( bRtn );
}

//**************************************************************************************************
// Extract the source component.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bLoadSigSrc( void )
{
  // Search for and extract a signal source component
  if( SimnBase::bLoadSigSrc( ) )
    return( true );

  // Special treatment for a DC Signal Source
  if( eGetAnaType( ) == eCMD_DC )
  {
    m_oCpntSigSrc.bClear( );
    m_oCpntSigSrc.bSetName( m_oCmdDC.m_osSource );
    return( true );
  }

  return( false );
}

//**************************************************************************************************
// Clear all object attributes.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bClear( void )
{
  // Clear the command object attributes
  bClrCmds( );

  // Clear the base class
  return( SimnBase::bClear( ) );
}

//**************************************************************************************************
// Clear all simulator command objects.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bClrCmds( void )
{
  m_oCmdOP .bSetDefaults( );
  m_oCmdDC .bSetDefaults( );
  m_oCmdAC .bSetDefaults( );
  m_oCmdTR .bSetDefaults( );
  m_oCmdFO .bSetDefaults( );

  m_oCmdOPT.bSetDefaults( );
  m_oCmdPR .bSetDefaults( );
  m_oCmdGEN.bSetDefaults( );

  return( true );
}

//**************************************************************************************************
// Clear all test points ie. nodes and components.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bClrTstPts( void )
{
  m_oCmdPR.m_osaNodes.Empty( );
  m_oCmdPR.m_osaCpnts.Empty( );

  return( true );
}

//**************************************************************************************************
// Do the current simulation settings constitute a valid simulation?
//
// Return Values :
//   true  - Valid
//   false - Not valid

bool  SimnGnuCap::bValidate( void )
{
  // Validate the base class
  SimnBase::bValidate( );

  if( ! m_oCmdOPT.bIsValid( ) ) SetErrMsg( m_oCmdOPT.rosGetErrMsg( ) );
  if( ! m_oCmdPR .bIsValid( ) ) SetErrMsg( m_oCmdPR .rosGetErrMsg( ) );
  if( ! m_oCmdGEN.bIsValid( ) ) SetErrMsg( m_oCmdGEN.rosGetErrMsg( ) );

  switch( eGetAnaType( ) )
  {
    case eCMD_OP :
      if( ! m_oCmdOP.bIsValid( ) ) SetErrMsg( m_oCmdOP.rosGetErrMsg( ) );
      break;

    case eCMD_DC :
      if( ! m_oCmdDC.bIsValid( ) ) SetErrMsg( m_oCmdDC.rosGetErrMsg( ) );
      break;

    case eCMD_AC :
      if( ! m_oCmdAC.bIsValid( ) ) SetErrMsg( m_oCmdAC.rosGetErrMsg( ) );
      break;

    case eCMD_TR :
      if( ! m_oCmdTR.bIsValid( ) ) SetErrMsg( m_oCmdTR.rosGetErrMsg( ) );
      break;

    case eCMD_FO :
      if( ! m_oCmdFO.bIsValid( ) ) SetErrMsg( m_oCmdFO.rosGetErrMsg( ) );
      break;

    default :
      SetErrMsg( wxT("No valid analysis command exists.") );
  }

  return( bIsValid( ) );
}

//**************************************************************************************************
// Load the simulation information from the netlist string array into the object attributes.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bLoad( void )
{
  // Envoke the base class load operations
  return( SimnBase::bLoad( ) );
}

//**************************************************************************************************
// Save the simulation information to the netlist string array from the object attributes.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bSave( void )
{
  // Envoke the base class save operations
  if( ! SimnBase::bSave( ) ) return( false );

  // Append the simulation command lines to the end of the file
  NetList::m_osaNetLst.Last( ) = wxT("********** GNU-Cap Simulation Commands **********");
  NetList::m_osaNetLst.Add( wxT("") );
  NetList::m_osaNetLst.Add( m_oCmdOPT );
  NetList::m_osaNetLst.Add( m_oCmdPR );
  if( m_oCmdGEN.bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdGEN );
  if( m_oCmdOP .bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdOP  );
  if( m_oCmdDC .bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdDC  );
  if( m_oCmdAC .bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdAC  );
  if( m_oCmdTR .bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdTR  );
  if( m_oCmdFO .bIsValid( ) ) NetList::m_osaNetLst.Add( m_oCmdFO  );

  // Add the circuit description terminator
  NetList::m_osaNetLst.Add( wxT("") );
  NetList::m_osaNetLst.Add( wxT(".END") );

  return( true );
}

//**************************************************************************************************
// Add a node to the list of test points.
//
// Argument List :
//   rosName - The name of the node to be added to the list of test points
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bAddTstNode( const wxString & rosName )
{
  // Is the node name valid?
  if( rosName.IsEmpty( ) )                                 return( false );
  // Is the node name already in the test node list?
  if( rosaGetTstNodes( ).Index( rosName ) != wxNOT_FOUND ) return( true );

  // Add the node name to the list of test points
  m_oCmdPR.m_osaNodes.Add( rosName );
  m_oCmdPR.m_osaNodes.Sort( &iStrCmpNode );

  return( true );
}

//**************************************************************************************************
// Add a component to the list of test points.
//
// Argument List :
//   rosName - The name of the component to be added to the list of test points
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnGnuCap::bAddTstCpnt( const wxString & rosName )
{
  // Is the component name valid?
  if( rosName.IsEmpty( ) )                                 return( false );
  // Is the component name already in the test component list?
  if( rosaGetTstCpnts( ).Index( rosName ) != wxNOT_FOUND ) return( true );

  // Add the component name to the list of test points
  m_oCmdPR.m_osaCpnts.Add( rosName );
  m_oCmdPR.m_osaCpnts.Sort( &iStrCmpCpnt );

  return( true );
}

//**************************************************************************************************
// Copy the contents of a SimnNgSpice object.
//
// Argument List :
//   roSimn - A reference to a SimnNgSpice object
//
// Return Values :
//   A reference to this object

SimnGnuCap & SimnGnuCap::operator = ( const SimnNgSpice & roSimn )
{
  (SimnBase &) *this = (SimnBase &) roSimn;

  if( roSimn.eGetAnaType( ) == eCMD_DC )
    if( roSimn.m_oCmdDC.m_osSource == wxT("TEMP") )
      m_oCmdPR.bSetAnaType( eCMD_OP );

  switch( roSimn.eGetAnaType( ) )
  {
    case eCMD_OP :
      m_oCmdOP = roSimn.m_oCmdDC;
      break;

    case eCMD_DC :
      m_oCmdDC = roSimn.m_oCmdDC;
      break;

    case eCMD_AC :
      m_oCmdAC = roSimn.m_oCmdAC;
      break;

    case eCMD_TR :
      m_oCmdTR = roSimn.m_oCmdTR;
      break;

    default :
      break;
  }

  m_oCmdOPT = roSimn.m_oCmdOPT;
  m_oCmdPR  = roSimn.m_oCmdPR;
  m_oCmdGEN = roSimn.m_oCpntIndSrc;

  return( *this );
}

//**************************************************************************************************
// Print the object attributes.
//
// Argument List :
//   rosPrefix - A prefix to every line displayed (usually just spaces)

void  SimnGnuCap::Print( const wxString & rosPrefix )
{
  SimnBase::Print( rosPrefix + wxT("SimnBase::") );

  m_oCmdOP .Print( rosPrefix + wxT("m_oCmdOP.")  );
  m_oCmdDC .Print( rosPrefix + wxT("m_oCmdDC.")  );
  m_oCmdAC .Print( rosPrefix + wxT("m_oCmdAC.")  );
  m_oCmdTR .Print( rosPrefix + wxT("m_oCmdTR.")  );
  m_oCmdFO .Print( rosPrefix + wxT("m_oCmdFO.")  );
  m_oCmdOPT.Print( rosPrefix + wxT("m_oCmdOPT.") );
  m_oCmdPR .Print( rosPrefix + wxT("m_oCmdPR.")  );
  m_oCmdGEN.Print( rosPrefix + wxT("m_oCmdGEN.") );
}

//**************************************************************************************************
