//**************************************************************************************************
//                                        CmdNgSpiceDC.cpp                                         *
//                                       ------------------                                        *
// Started     : 2007-08-21                                                                        *
// Last Update : 2018-09-25                                                                        *
// Copyright   : (C) 2007-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 "CmdNgSpiceDC.hpp"

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

CmdNgSpiceDC::CmdNgSpiceDC( void ) : CmdBase( )
{
  bSetDefaults( );
}

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

CmdNgSpiceDC::~CmdNgSpiceDC( )
{
}

//**************************************************************************************************
// Check that the object attributes are valid.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceDC::bValidate( void )
{
  double  df1, df2, df3;

  CmdBase::bValidate( );

  // Check the sweep start and stop values
  if( ! CnvtType::bStrToFlt( m_osStart, &df1 ) ) SetErrMsg( wxT("Invalid sweep start value.") );
  if( ! CnvtType::bStrToFlt( m_osStop,  &df2 ) ) SetErrMsg( wxT("Invalid sweep stop value.") );

  // Check the sweep step value and sweep scale
  if( ! CnvtType::bStrToFlt( m_osStep,  &df3 ) ) SetErrMsg( wxT("Invalid sweep step value.") );
  if( df3 == 0.0 )                               SetErrMsg( wxT("Step value equal to zero.") );

  // Check the component to be used as the sweep source
  if( m_osSource.IsEmpty( ) && m_osSource!=wxT("TEMP") )
    SetErrMsg( wxT("No source component has been selected.") );

  return( bIsValid( ) );
}

//**************************************************************************************************
// Set the object attributes to they're default values.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceDC::bSetDefaults( void )
{
  CmdBase::bSetDefaults( );

  m_eSimEng  = eSIMR_NGSPICE;
  m_eCmdType = eCMD_DC;

  m_osStart  = wxT("0.0");
  m_osStop   = wxT("100.0");
  m_osStep   = wxT("10.0");

  m_osSource = wxT("None");

  return( true );
}

//**************************************************************************************************
// Parse the command string.
//
// Eg.s : .DC Vin 0.00 200.00m 25.00m
//        .DC TEMP 0.00 200.00 25.00
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceDC::bParse( void )
{
  wxStringTokenizer  ostk1;
  wxString           os1;
  double             df1;

  // Clear the object attributes
  os1 = *this;
  bSetDefaults( );
  assign( os1 );

  // Tokenize the command string
  ostk1.SetString( *this );
  if( ostk1.CountTokens( ) != 5 ) return( bValidate( ) );

  // Check command type
  os1 = ostk1.GetNextToken( ).Left( 3 ).Upper( );
  if( os1 != wxT(".DC") )         return( false );

  // Extract the sweep type : a signal source or temperature
  m_osSource = ostk1.GetNextToken( );
  if( m_osSource.IsEmpty( ) )     return( bValidate( ) );

  // Extract the start value
  os1 = ostk1.GetNextToken( );
  if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osStart = os1;
  else                            return( bValidate( ) );

  // Extract the stop value
  os1 = ostk1.GetNextToken( );
  if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osStop  = os1;
  else                            return( bValidate( ) );

  // Extract the step increment
  os1 = ostk1.GetNextToken( );
  if( os1.GetChar( 0 ) == wxT('-') ) os1 = os1.Mid( 1 );
  if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osStep  = os1;
  else                            return( bValidate( ) );

  return( bValidate( ) );
}

//**************************************************************************************************
// Format the command string.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdNgSpiceDC::bFormat( void )
{
  wxString  osCmd;
  double    df1, df2;

  // Set the command name
  osCmd = wxT(".DC");

  // Set signal source
  osCmd << wxT(' ') << m_osSource;

  // Set sweep parameters
  osCmd << wxT(' ') << m_osStart;
  osCmd << wxT(' ') << m_osStop;
  osCmd << wxT(' ');
  if( CnvtType::bStrToFlt( m_osStart, &df1 ) && CnvtType::bStrToFlt( m_osStop, &df2 ) )
    if( df1 > df2 )
      osCmd << wxT('-');
  osCmd             << m_osStep;


  assign( osCmd );

  return( bValidate( ) );
}

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

CmdNgSpiceDC & CmdNgSpiceDC::operator = ( const CmdGnuCapOP & roCmdOP )
{
  (CmdBase &) *this = (CmdBase &) roCmdOP;

  m_osStart  = roCmdOP.m_osStart;
  m_osStop   = roCmdOP.m_osStop;
  m_osStep   = roCmdOP.m_osStep;
  m_osSource = wxT("TEMP");

  bFormat( );

  return( *this );
}

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

CmdNgSpiceDC & CmdNgSpiceDC::operator = ( const CmdGnuCapDC & roCmdDC )
{
  (CmdBase &) *this = (CmdBase &) roCmdDC;

  m_osStart  = roCmdDC.m_osStart;
  m_osStop   = roCmdDC.m_osStop;
  m_osStep   = roCmdDC.m_osStep;
  m_osSource = roCmdDC.m_osSource;

  bFormat( );

  return( *this );
}

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

void  CmdNgSpiceDC::Print( const wxString & rosPrefix )
{
  CmdBase::Print( rosPrefix + wxT("CmdBase::") );

  std::cout << rosPrefix.mb_str( ) << "m_osStart  : " << m_osStart .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osStop   : " << m_osStop  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osStep   : " << m_osStep  .mb_str( ) << '\n';

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

//**************************************************************************************************
//                                          Test Utility                                           *
//**************************************************************************************************

#ifdef TEST_CMDNGSPICEDC

using  namespace  std;

// Function prototypes

void  Usage( char * psAppName );

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

int  main( int argc, char * argv[ ] )
{
  wxString  osCmd;
  wxString  os1;

  // Validate the argument count passed to the application
  if( argc > 2 )           { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); }

  // Process the command line arguments
  os1 = wxConvLibc.cMB2WC( argv[ 1 ] );
  if( argc > 1 )
  {
    if( os1 == wxT("-h") ) { Usage( argv[ 0 ] ); exit( EXIT_SUCCESS ); }
    else                   { Usage( argv[ 0 ] ); exit( EXIT_FAILURE ); }
  }

  // Display the utility banner
  cout << "\n  Class CmdNgSpiceDC Test Utility"
       << "\n     Version 1.02 (12/08/2011)\n";

  // Create a NG-SPICE DC command object
  CmdNgSpiceDC  oCmd_DC;

  // Use the following command example to check the formatter and the parser :
  osCmd = wxT(".DC Vin 0.00 100.00m 10.00m");

  // Set things up for a formatter test
  oCmd_DC.m_osStart  = wxT("0.00");
  oCmd_DC.m_osStop   = wxT("100.00m");
  oCmd_DC.m_osStep   = wxT("10.00m");
  oCmd_DC.m_osSource = wxT("Vin");
  cout << "\nRun Formatter    : " << ( oCmd_DC.bFormat( ) ? "OK" : "FAULT" );
  cout << "\nTest Cmd Format  : " << ( oCmd_DC == osCmd   ? "OK" : "FAULT" );
  cout << "\nExample Command  : " << osCmd  .mb_str( );
  cout << "\noCmd_DC Contents : " << oCmd_DC.mb_str( ) << '\n';

  // Set things up for a parser test
  oCmd_DC.bSetString( osCmd );
  cout << "\nRun Parser       : " << ( oCmd_DC.bParse( ) ? "OK" : "FAULT" );
  oCmd_DC.bFormat( );
  cout << "\nTest Cmd Format  : " << ( oCmd_DC == osCmd  ? "OK" : "FAULT" );
  cout << "\nExample Command  : " << osCmd  .mb_str( );
  cout << "\noCmd_DC Contents : " << oCmd_DC.mb_str( ) << '\n';

  cout << '\n';

  exit( EXIT_SUCCESS );
}

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

void  Usage( char * psAppName )
{
  cout << "\nUsage   : " << psAppName << " [-OPTIONS]"
       << "\nOptions :"
       << "\n  -h : Print usage (this message)\n";
}

#endif // TEST_CMDNGSPICEDC

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