//**************************************************************************************************
//                                         CmdGnuCapGEN.cpp                                        *
//                                        ------------------                                       *
// Started     : 2008-03-11                                                                        *
// 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 "CmdGnuCapGEN.hpp"

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

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

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

CmdGnuCapGEN::~CmdGnuCapGEN( )
{
}

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

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

  CmdBase::bValidate( );

  // Overall source characteristics
  if( ! CnvtType::bStrToFlt( m_osAmplitude, &df1 ) )
    SetErrMsg( wxT("overall amplitude value is invalid") );
//  if( df1 <= 0.0 ) ??? 05/10/2009
//    SetErrMsg( wxT("overall amplitude value must be greater than zero") );
  if( ! CnvtType::bStrToFlt( m_osOffset,    &df1 ) )
    SetErrMsg( wxT("overall offset value is invalid") );

  // Sinusoidal source characteristics
  if( ! CnvtType::bStrToFlt( m_osSinFreq,  &df1 ) )
    SetErrMsg( wxT("sinusoid frequency value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osSinPhase, &df1 ) )
    SetErrMsg( wxT("sinusoid phase value is invalid") );

  // Check the pulse time values
  if( ! CnvtType::bStrToFlt( m_osPulRise,   &df1 ) )
    SetErrMsg( wxT("pulse rise time value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osPulWidth,  &df2 ) )
    SetErrMsg( wxT("pulse width value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osPulFall,   &df3 ) )
    SetErrMsg( wxT("pulse fall time value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osPulPeriod, &df4 ) )
    SetErrMsg( wxT("pulse period value is invalid") );
  if(      df4 < df1 )
    SetErrMsg( wxT("pulse rise time is greater than the pulse period") );
  else if( df4 < df2 )
    SetErrMsg( wxT("pulse width is greater than the pulse period") );
  else if( df4 < df3 )
    SetErrMsg( wxT("pulse fall time is greater than the pulse period") );
  else if( df4 < df1+df2+df3 )
    SetErrMsg( wxT("pulse period is less then the pulse width") );

  // Check the pulse level values
  if( ! CnvtType::bStrToFlt( m_osPulInitial, &df1 ) )
    SetErrMsg( wxT("initial pulse value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osPulMin,     &df2 ) )
    SetErrMsg( wxT("minimum pulse value is invalid") );
  if( ! CnvtType::bStrToFlt( m_osPulMax,     &df3 ) )
    SetErrMsg( wxT("maximum pulse value is invalid") );
  if(      df1 < df2 )
    SetErrMsg( wxT("initial pulse value is less than the minimum pulse value") );
  else if( df1 > df3 )
    SetErrMsg( wxT("initial pulse value is greater than the maximum pulse value") );
  else if( df2 > df3 )
    SetErrMsg( wxT("minimum pulse value is less than the maximum pulse value") );

  // Check overall pulse source logic
  if( df4!=0.0  && (df2==0.0 && df3==0.0) )
    SetErrMsg( wxT("pulse timing has been defined but no pulse levels") );
  if( df4==0.0 && (df2!=0.0 || df3!=0.0) )
    SetErrMsg( wxT("pulse levels have been defined but no pulse timing") );

  return( true );
}

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

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

  m_eSimEng      = eSIMR_GNUCAP;
  m_eCmdType     = eCMD_GEN;

  m_osAmplitude  = GCP_AMPLITUDE;
  m_osOffset     = GCP_OFFSET;

  m_osSinFreq    = GCP_SINFREQ;
  m_osSinPhase   = GCP_SINPHASE;

  m_osPulInitial = GCP_PULINITIAL;
  m_osPulMin     = GCP_PULMIN;
  m_osPulMax     = GCP_PULMAX;
  m_osPulDelay   = GCP_PULDELAY;
  m_osPulRise    = GCP_PULRISE;
  m_osPulWidth   = GCP_PULWIDTH;
  m_osPulFall    = GCP_PULFALL;
  m_osPulPeriod  = GCP_PULPERIOD;

  return( true );
}

//**************************************************************************************************
// Parse the command string.
//
// Eg.s : .GENERATOR AMP=2.00K OFFSET=1.00 FREQ=1.00K PHASE=50.00 INIT=5.00m
//                   MIN=2.00m MAX=10.00m DELAY=4.00m RISE=2.00m WIDTH=8.00m
//                   FALL=1.00m PERIOD=20.00m
//
// Return Values :
//   true  - Success
//   false - Failure

bool  CmdGnuCapGEN::bParse( void )
{
  wxStringTokenizer  ostk1;
  wxString           os1, os2;
  size_t             szt1;
  int                i1;

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

  // Tokenize the command string
  ostk1.SetString( *this );
  i1 = ostk1.CountTokens( );
  if( i1<2 || i1>13 )      return( bValidate( ) );

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

  // Extract each parameter value
  while( ostk1.HasMoreTokens( ) )
  {
    // Extract the field name and the associated value
    os1 = ostk1.GetNextToken( );
    os2 = wxT("");
    if( ( szt1=os1.find( wxT("=") ) ) != wxString::npos )
    {
      os2 = os1.Right( os1.Length( )-szt1-1 );
      os1 = os1.Left( szt1 );
    }

    // Set the object attribute values
    if(      os1 == wxT("AMP")    ) m_osAmplitude  = os2;
    else if( os1 == wxT("OFFSET") ) m_osOffset     = os2;
    else if( os1 == wxT("FREQ")   ) m_osSinFreq    = os2;
    else if( os1 == wxT("PHASE")  ) m_osSinPhase   = os2;
    else if( os1 == wxT("INIT")   ) m_osPulInitial = os2;
    else if( os1 == wxT("MIN")    ) m_osPulMin     = os2;
    else if( os1 == wxT("MAX")    ) m_osPulMax     = os2;
    else if( os1 == wxT("DELAY")  ) m_osPulDelay   = os2;
    else if( os1 == wxT("RISE")   ) m_osPulRise    = os2;
    else if( os1 == wxT("WIDTH")  ) m_osPulWidth   = os2;
    else if( os1 == wxT("FALL")   ) m_osPulFall    = os2;
    else if( os1 == wxT("PERIOD") ) m_osPulPeriod  = os2;
    else                   return( bValidate( ) );
  }

  return( bValidate( ) );
}

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

bool  CmdGnuCapGEN::bFormat( void )
{
  wxString  os1;
  float     f1;
  bool      b1;

  os1 = wxT(".GENERATOR");

  if( ! m_osAmplitude .IsEmpty( ) ) os1 << wxT(" AMP=")    << m_osAmplitude;
  if( ! m_osOffset    .IsEmpty( ) ) os1 << wxT(" OFFSET=") << m_osOffset;

  f1 = 0.0;
  b1 = CnvtType::bStrToFlt( m_osSinFreq, &f1 );
  if( b1==true && f1!=0.0 )
  {
    os1 << wxT(" FREQ=")   << m_osSinFreq;
    os1 << wxT(" PHASE=")  << m_osSinPhase;
  }

  f1 = 0.0;
  b1 = CnvtType::bStrToFlt( m_osPulMax, &f1 );
  if( b1==true && f1!=0.0 )
  {
    os1 << wxT(" INIT=")   << m_osPulInitial;
    os1 << wxT(" MIN=")    << m_osPulMin;
    os1 << wxT(" MAX=")    << m_osPulMax;
    os1 << wxT(" DELAY=")  << m_osPulDelay;
    os1 << wxT(" RISE=")   << m_osPulRise;
    os1 << wxT(" WIDTH=")  << m_osPulWidth;
    os1 << wxT(" FALL=")   << m_osPulFall;
    os1 << wxT(" PERIOD=") << m_osPulPeriod;
  }

  assign( os1 );

  return( bValidate( ) );
}

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

CmdGnuCapGEN & CmdGnuCapGEN::operator = ( const CpntNgsIndSrc & roIndSrc )
{
  double  df1, df2;

  if( ! roIndSrc.m_osSinAmp.IsEmpty( ) ) m_osAmplitude = roIndSrc.m_osSinAmp;
  else                                   m_osAmplitude = wxT("1.0");
  m_osOffset     = roIndSrc.m_osSinOffset;

  m_osSinFreq    = roIndSrc.m_osSinFreq;
  if( CnvtType::bStrToFlt( roIndSrc.m_osSinFreq,  &df1 ) &&
      CnvtType::bStrToFlt( roIndSrc.m_osSinDelay, &df2 ) )
    CnvtType::bFltToStr( 360.0 * df2 * df1, m_osSinPhase );
  else
    m_osSinPhase = wxT("0.0");

  m_osPulInitial = roIndSrc.m_osPulInitial;
  m_osPulMax     = roIndSrc.m_osPulMax;
  m_osPulDelay   = roIndSrc.m_osPulDelay;
  m_osPulRise    = roIndSrc.m_osPulRise;
  m_osPulWidth   = roIndSrc.m_osPulWidth;
  m_osPulFall    = roIndSrc.m_osPulFall;
  m_osPulPeriod  = roIndSrc.m_osPulPeriod;

  bFormat( );

  return( *this );
}

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

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

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

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

  std::cout << rosPrefix.mb_str( ) << "m_osPulInitial : " << m_osPulInitial.mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulMin     : " << m_osPulMin    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulMax     : " << m_osPulMax    .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulDelay   : " << m_osPulDelay  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulRise    : " << m_osPulRise   .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulWidth   : " << m_osPulWidth  .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulFall    : " << m_osPulFall   .mb_str( ) << '\n';
  std::cout << rosPrefix.mb_str( ) << "m_osPulPeriod  : " << m_osPulPeriod .mb_str( ) << '\n';
}

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

#ifdef TEST_CMDGNUCAPGEN

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

  // Create a GNU-CAP Transient command object
  CmdGnuCapGEN  tCmd_GEN;

  // Use the following command example to check the formatter and the parser :
  osCmd << wxT(".GENERATOR AMP=2.00K OFFSET=1.00 FREQ=1.00K PHASE=50.00 ")
        << wxT("INIT=5.00m MIN=2.00m MAX=10.00m DELAY=4.00m RISE=2.00m ")
        << wxT("WIDTH=8.00m FALL=1.00m PERIOD=20.00m");

  // Set things up for a formatter test
  tCmd_GEN.m_osAmplitude  = wxT("2.00K");
  tCmd_GEN.m_osOffset     = wxT("1.00");
  tCmd_GEN.m_osSinFreq    = wxT("1.00K");
  tCmd_GEN.m_osSinPhase   = wxT("50.00");
  tCmd_GEN.m_osPulInitial = wxT("5.00m");
  tCmd_GEN.m_osPulMin     = wxT("2.00m");
  tCmd_GEN.m_osPulMax     = wxT("10.00m");
  tCmd_GEN.m_osPulDelay   = wxT("4.00m");
  tCmd_GEN.m_osPulRise    = wxT("2.00m");
  tCmd_GEN.m_osPulWidth   = wxT("8.00m");
  tCmd_GEN.m_osPulFall    = wxT("1.00m");
  tCmd_GEN.m_osPulPeriod  = wxT("20.00m");
  cout << "\nRun Formatter     : " << ( tCmd_GEN.bFormat( ) ? "OK" : "FAULT" );
  cout << "\nTest Cmd Format   : " << ( tCmd_GEN == osCmd   ? "OK" : "FAULT" );
  cout << "\nExample Command   : " << osCmd  .mb_str( );
  cout << "\ntCmd_GEN Contents : " << tCmd_GEN.mb_str( ) << '\n';

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

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