//**************************************************************************************************
//                                         CmdGnuCapAC.cpp                                         *
//                                        -----------------                                        *
// Started     : 2008-02-21                                                                        *
// Last Update : 2014-12-23                                                                        *
// Copyright   : (C) 2008-2016 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 "CmdGnuCapAC.hpp"

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

CmdGnuCapAC::CmdGnuCapAC( void )
{
  bSetDefaults( );
}

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

CmdGnuCapAC::~CmdGnuCapAC( )
{
}

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

bool  CmdGnuCapAC::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.") );
  if( df2 < df1 )
    SetErrMsg( wxT("Start value greater than 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 less than or equal to zero.") );
  switch( m_eScale )
  {
    case eSCALE_LIN :
      if( df1!=df2 && df3>fabs( df2 - df1 ) )
        SetErrMsg( wxT("Step value is greater than sweep range.") );
      break;
    case eSCALE_LOG :
      if( df1!=df2 && df3==1.0 )
        SetErrMsg( wxT("Invalid step multiplier, must be non-unity.") );
      break;
    case eSCALE_DEC :
    case eSCALE_OCT : break;
    default         : SetErrMsg( wxT("Invalid step scale value.") );
  }

  // Set the analysis temperature
  if( ! CnvtType::bStrToFlt( m_osTempC, &df3 ) )
    SetErrMsg( wxT("Invalid analysis temperature value.") );

  return( bIsValid( ) );
}

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

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

  m_eSimEng  = eSIMR_GNUCAP;
  m_eCmdType = eCMD_AC;

  m_osStart  = wxT("1.0K");
  m_osStop   = wxT("100.0K");
  m_osStep   = wxT("10");

  m_eScale   = eSCALE_DEC;

  m_osTempC  = wxT("27.0");

  return( true );
}

//**************************************************************************************************
// Parse the command string.
//
// Eg.s : .AC 1.00K 100.00K BY 10.00K TE 27.00 BASIC
//        .AC 1.00K 100.00K TI 10.00 TE 27.00 BASIC
//        .AC 1.00K 100.00K DE 10 TE 27.00 BASIC
//        .AC 1.00K 100.00K OC 10 TE 27.00 BASIC
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdGnuCapAC::bParse( void )
{
  wxStringTokenizer  ostk1;
  wxString           os1;
  double             df1, df2;

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

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

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

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

  // Is the next field a number?
  os1 = ostk1.GetNextToken( );
  if( CnvtType::bStrToFlt( os1, &df2 )  )
  {
    // Extract the stop value
    if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osStop = os1;
    else                                               return( bValidate( ) );

    // Extract the sweep type
    os1 = ostk1.GetNextToken( ).Upper( );
    if(      os1 == wxT("BY") ) m_eScale = eSCALE_LIN;
    else if( os1 == wxT("TI") ) m_eScale = eSCALE_LOG;
    else if( os1 == wxT("DE") ) m_eScale = eSCALE_DEC;
    else if( os1 == wxT("OC") ) m_eScale = eSCALE_OCT;
    else                                               return( bValidate( ) );

    // Extract the step size/count
    os1 = ostk1.GetNextToken( );
    if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osStep = os1;
    else                                               return( bValidate( ) );

    os1 = ostk1.GetNextToken( );
  }
  else
  { // Use default values for the remaining parameters
    m_osStop = os1;
    m_osStep = wxT("1.0");
    m_eScale = eSCALE_LIN;
  }

  // Extract the analysis temperature
  if( os1.Upper( ) == wxT("TE") )
  {
    os1 = ostk1.GetNextToken( );
    if( CnvtType::bStrToFlt( os1, &df1 ) ) m_osTempC = os1;
    else                                               return( bValidate( ) );
  }

  // Check that the last field is "BASIC"
  if( ostk1.GetNextToken( ).Upper( ) != wxT("BASIC") ) return( bValidate( ) );

  return( bValidate( ) );
}

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

bool  CmdGnuCapAC::bFormat( void )
{
  wxString  osCmd, os1;

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

  // Set sweep parameters
  osCmd << wxT(' ') << m_osStart;
  osCmd << wxT(' ') << m_osStop;
  switch( m_eScale )
  {
    case eSCALE_LIN : osCmd << wxT(" BY"); break;
    case eSCALE_LOG : osCmd << wxT(" TI"); break;
    case eSCALE_DEC : osCmd << wxT(" DE"); break;
    case eSCALE_OCT : osCmd << wxT(" OC"); break;
    default : return( false );
  }
  osCmd << wxT(' ') << m_osStep;

  // Set analysis temperature
  osCmd << wxT(" TE ") << m_osTempC;

  // Append format modifier
  osCmd << wxT(" BASIC");

  assign( osCmd );

  return( bValidate( ) );
}

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

CmdGnuCapAC & CmdGnuCapAC::operator = ( const CmdNgSpiceAC & roCmdAC )
{
  (CmdBase &) *this = (CmdBase &) roCmdAC;

  m_osStart = roCmdAC.m_osStart;
  m_osStop  = roCmdAC.m_osStop;
  m_osStep  = roCmdAC.m_osStep;
  m_eScale  = roCmdAC.m_eScale;

  bFormat( );

  return( *this );
}

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

void  CmdGnuCapAC::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_eScale  : ";
  switch( m_eScale )
  {
    case eSCALE_LIN  : std::cout << "eSCALE_LIN\n";  break;
    case eSCALE_LOG  : std::cout << "eSCALE_LOG\n";  break;
    case eSCALE_DEC  : std::cout << "eSCALE_DEC\n";  break;
    case eSCALE_OCT  : std::cout << "eSCALE_OCT\n";  break;
    case eSCALE_NONE : std::cout << "eSCALE_NONE\n"; break;
    default :          std::cout << "Invalid\n";     break;
  }

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

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

#ifdef TEST_CMDGNUCAPAC

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 CmdGnuCapAC Test Utility"
       << "\n    Version 1.02 (12/08/2011)\n";

  // Create a GNU-CAP AC command object
  CmdGnuCapAC  tCmd_AC;

  // Use the following command example to check the formatter and the parser :
  osCmd = wxT(".AC 1.00K 200.00K TI 1.01 TE 30.00 BASIC");

  // Set things up for a formatter test
  tCmd_AC.m_osStart = wxT("1.00K");
  tCmd_AC.m_osStop  = wxT("200.00K");
  tCmd_AC.m_osStep  = wxT("1.01");
  tCmd_AC.m_eScale  = eSCALE_LOG;
  tCmd_AC.m_osTempC = wxT("30.00");
  cout << "\nRun Formatter    : " << ( tCmd_AC.bFormat( ) ? "OK" : "FAULT" );
  cout << "\nTest Cmd Format  : " << ( tCmd_AC == osCmd   ? "OK" : "FAULT" );
  cout << "\nExample Command  : " << osCmd  .mb_str( );
  cout << "\ntCmd_AC Contents : " << tCmd_AC.mb_str( ) << '\n';

  // Set things up for a parser test
  tCmd_AC.bSetString( osCmd );
  cout << "\nRun Parser       : " << ( tCmd_AC.bParse( ) ? "OK" : "FAULT" );
  tCmd_AC.bFormat( );
  cout << "\nTest Cmd Format  : " << ( tCmd_AC == osCmd  ? "OK" : "FAULT" );
  cout << "\nExample Command  : " << osCmd  .mb_str( );
  cout << "\ntCmd_AC Contents : " << tCmd_AC.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_CMDGNUCAPAC

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