//**************************************************************************************************
//                                          SimnBase.cpp                                           *
//                                         --------------                                          *
// Started     : 2008-05-01                                                                        *
// Last Update : 2018-11-01                                                                        *
// Copyright   : (C) 2008-2018 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 "SimnBase.hpp"

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

SimnBase::SimnBase( void )
{
  m_eSimEng = eSIMR_NONE;
}

//**************************************************************************************************
// Copy constructor.
//
// Argument List :
//   roSimn - A reference to the object to be copied

SimnBase::SimnBase( const SimnBase & roSimn )
{
  *this = roSimn;
}

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

SimnBase::~SimnBase( )
{
}

//**************************************************************************************************
// Extract the source component.
//
// Several tasks are performed here :
//  - Search for a component which is being used as a signal source.
//  - Extract the source component's original definition.
//  - Set the attribute m_oCpntSwpSrc to the source component definition.
//  - Set the component in m_oaCpnts to it's original definition.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnBase::bLoadSigSrc( void )
{
  Component  oCpnt;
  wxString   os1;
  size_t     sz1;

  // Scan the circuit description for a source component
  for( sz1=0; sz1<m_osaNetLst.GetCount( )-1; sz1++, os1.Empty( ) )
  {
    os1 = m_osaNetLst.Item( sz1 );

    // Is this a signal source?
    if(   os1.IsEmpty( ) )                             continue; // No
    if( ! os1.StartsWith( wxT("* Signal source (") ) ) continue; // No
    if(   os1.GetChar( os1.Len( )-1 ) != wxT(')') )    continue; // No
    break;                                                       // Yes, looks like a signal source
  }
  if( os1.IsEmpty( ) )      return( false );

  // Attempt to extract the original component definition
  os1 = os1.AfterFirst( wxT('(') );
  os1 = os1.BeforeLast( wxT(')') );
  oCpnt = os1;
  if( ! oCpnt.bIsValid( ) ) return( false );

  // Set the source component
  m_oCpntSigSrc = m_osaNetLst.Item( sz1 + 1 );

  // Scan the component list for the source component
  for( sz1=0; sz1<m_oaCpnts.GetCount( ); sz1++ )
  {
    if( m_oaCpnts.Item( sz1 ).rosGetName( ) == oCpnt.rosGetName( ) )
    {
      // Set the signal source component back to it's original definition
      m_oaCpnts.Item( sz1 ) = oCpnt.rosGetString( );
      break;
    }
  }

  return( true );
}

//**************************************************************************************************
// If a signal source has been defined save it's current definition and save the original definition
// in the netlist as a comment immediately before the new signal source definition.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  SimnBase::bSaveSigSrc( void )
{
  Component  oCpnt;
  wxString   os1;
  size_t     sz1;

  // Check if a signal source has been selected
  if( ! m_oCpntSigSrc.bIsValid( ) ) return( true );

  // Find the source component, replace it with the new definition and insert a comment before it
  // containing the original source component definition
  for( sz1=0; sz1<NetList::m_osaNetLst.GetCount( ); sz1++ )
  {
    // Is this a component definition?
    oCpnt = NetList::m_osaNetLst.Item( sz1 );
    if( ! oCpnt.bIsValid( ) ) continue;

    // Is this the signal source component?
    if( oCpnt.rosGetName( ) == m_oCpntSigSrc.rosGetName( ) )
    {
      NetList::m_osaNetLst.Item( sz1 ) = m_oCpntSigSrc.rosGetString( );   // Replace sig. src. def.
      os1 = wxT("* Signal source (") + oCpnt.rosGetString( ) + wxT(')');  // Create comment line
      NetList::m_osaNetLst.Insert( os1, sz1 );                            // Insert comment line
      break;
    }
  }

  return( true );
}

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

bool  SimnBase::bClear( void )
{
  // Clear the sweep source component
  m_oCpntSigSrc.bClear( );
  m_oCpntSigSrc.bSetName( wxT("None") );

  // Clear any error messages
  m_osErrMsg.Empty( );

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

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

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

  // Clear the error message
  m_osErrMsg.Clear( );

  // Check the simulation engine
  if( m_eSimEng == eSIMR_NONE )
  {
    SetErrMsg( wxT("No simulation engine has been specified.") );
    return( false );
  }

  // Check the analysis type
  if( eGetAnaType( ) == eCMD_NONE )
  {
    SetErrMsg( wxT("No analysis type has been specified.") );
    return( false );
  }

  // Have any test components or test nodes been specified?
  if( rosaGetTstNodes( ).GetCount( )<=0 || rosaGetTstCpnts( ).GetCount( )<=0 )
  {
    SetErrMsg( wxT("No nodes or components have been selected.") );
    return( false );
  }

  return( true );
}

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

bool  SimnBase::bLoad( void )
{
  // Envoke the base class load operations
  if( ! NetList::bLoad( ) ) return( false );

  // Check for a simulator signifier
  if( ! bLoadSimEng( ) )    return( false );

  // Extract the simulator instructions
  bLoadSimCmds( );
  bLoadSigSrc ( );

  return( true );
}

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

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

  // Save the signal source to the simulation file
  if( ! bSaveSigSrc( ) )    return( false );

  return( true );
}

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

SimnBase & SimnBase::operator = ( const SimnBase & roSimn )
{
  m_oCpntSigSrc = roSimn.m_oCpntSigSrc;

  return( *this );
}

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

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

  std::cout << rosPrefix.mb_str( )  << "m_eSimEng  : ";
  switch( m_eSimEng )
  {
    case eSIMR_GNUCAP  : std::cout << "eSIMR_GNUCAP";  break;
    case eSIMR_NGSPICE : std::cout << "eSIMR_NGSPICE"; break;
    case eSIMR_NONE    : std::cout << "eSIMR_NONE";    break;
  }
  std::cout << '\n';

  std::cout << rosPrefix .mb_str( ) << "m_osErrMsg : " << m_osErrMsg.mb_str( ) << '\n';

  m_oCpntSigSrc.Print( rosPrefix + wxT("m_oCpntSigSrc::") );
}

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