//**************************************************************************************************
//                                        PnlNgSpiceAC.cpp                                         *
//                                       ------------------                                        *
// Started     : 2004-08-04                                                                        *
// Last Update : 2018-11-01                                                                        *
// Copyright   : (C) 2004-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 "PnlNgSpiceAC.hpp"

//**************************************************************************************************
// Implement an event table.

wxBEGIN_EVENT_TABLE( PnlNgSpiceAC, PnlAnaBase )

  EVT_RADIOBOX( PnlAnaBase::ID_RBX_SCALE  , PnlNgSpiceAC::OnScale   )
  EVT_CHOICE  ( PnlAnaBase::ID_CHO_SRCNAME, PnlNgSpiceAC::OnSrcName )

wxEND_EVENT_TABLE( )

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

PnlNgSpiceAC::PnlNgSpiceAC( wxWindow * poWin ) : PnlAnaBase( poWin )
{
  bSetAnalysType( eCMD_AC );  // Set the analysis panel type
  Create( );                  // Create the analysis panel
  bClear( );                  // Clear all object attributes
}

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

PnlNgSpiceAC::~PnlNgSpiceAC( )
{
}

//**************************************************************************************************
// Create the display objects.

void  PnlNgSpiceAC::Create( void )
{
  PnlAnaBase::CreateBase( );    // Create the base controls
  PnlAnaBase::CreateScale( );   // Create the scale controls
  PnlAnaBase::CreateCpxPrt( );  // Create the simulation parameter complex part check boxes
  PnlAnaBase::CreateTemp( );    // Create the analysis temperature controls
  PnlAnaBase::CreateSigSrc( );  // Create the input signal source controls
              CreateSigSrc( );  // Create the additional input signal source controls

#ifdef LAYOUT_MNGR
  PnlAnaBase::DoLayout( );      // Layout the panel's GUI objects
#endif // LAYOUT_MNGR

  // Set the frequency sweep parameter labels
#ifdef LAYOUT_MNGR
  bSetSwpParsLbl( wxT("AC Sweep") );
#else
  m_oSbxSwpPars.SetLabel( wxT(" AC Sweep ") );
#endif // LAYOUT_MNGR
  m_oPnlStart  .bSetName( wxT("Start Frequency") );
  m_oPnlStop   .bSetName( wxT("Stop Frequency") );

  // Set sweep parameter spin control parameters and units
  m_oPnlStart.bSetUnitsType( eUNITS_FREQ );
  m_oPnlStop .bSetUnitsType( eUNITS_FREQ );
  m_oPnlStep .bSetValueType( eVALUE_INT );
  m_oPnlStep .bShowUnits( PnlValue::eSHOW_LBL );

  // Disable the scale option NG-Spice doesn't support
  m_oRbxSweep.Enable( eSCALE_LOG, false );

  // Disable the checkboxes for the parameters NG-Spice cannot calculate
  m_oCbxCurrent.Disable( );
  m_oCbxPower  .Disable( );
  m_oCbxResist .Disable( );
}

//**************************************************************************************************
// Create the source component display objects.

void  PnlNgSpiceAC::CreateSigSrc( void )
{
  wxPanel * poPnl;

  poPnl = static_cast< wxPanel * >( m_oChoSrcName.GetParent( ) );

  // Create and add signal source controls
#ifdef LAYOUT_MNGR
  m_oPnlSrcLvl.bCreate( poPnl, ID_PNL_SRCLVL, -1, 95, 82 );
#else
  m_oSbxSigSrc.SetSize( wxSize( 330, 60 ) );
  m_oPnlSrcLvl.bCreate( poPnl, ID_PNL_SRCLVL, -1, 95, 82, wxPoint( 142, 200 ) );
#endif // LAYOUT_MNGR
}

//**************************************************************************************************
// Initialize the step scale.

void  PnlNgSpiceAC::InitScale( void )
{
  switch( m_oRbxSweep.GetSelection( ) )
  {
    case eSCALE_LIN :
      m_oPnlStep.bSetName( wxT("Steps in Total") );
      m_oPnlStep.bSetSpnRange( 1, 100000 );
      m_oPnlStep.bSetSpnIncSz( 1,  10000 );
      m_oPnlStep.bSetDefValue( 10 );
      break;

    case eSCALE_DEC :
      m_oPnlStep.bSetName( wxT("Steps / Decade") );
      m_oPnlStep.bSetSpnRange( 1, 10000 );
      m_oPnlStep.bSetSpnIncSz( 1,  1000 );
      m_oPnlStep.bSetDefValue( 10 );
      break;

    case eSCALE_OCT :
      m_oPnlStep.bSetName( wxT("Steps / Octave") );
      m_oPnlStep.bSetSpnRange( 1, 10000 );
      m_oPnlStep.bSetSpnIncSz( 1,  1000 );
      m_oPnlStep.bSetDefValue( 10 );
      break;

    default :
      break;
  }
}

//**************************************************************************************************
// Set the state of the step scale radio box.
//
// Argument List :
//   eScale - The enumerated scale specifier
//
// Return Values :
//   Success - true
//   Failure - false

bool  PnlNgSpiceAC::bSetScale( eTypeScale eScale )
{
  if( eScale == eSCALE_NONE )                       return( false );
#if wxCHECK_VERSION( 2,8,0 )
  if( m_oRbxSweep.GetCount( ) < (uint) eScale + 1 ) return( false );
#else
  if( m_oRbxSweep.GetCount( ) < (int)  eScale + 1 ) return( false );
#endif

  m_oRbxSweep.SetSelection( (int) eScale );

  InitScale( );

  return( true );
}

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

bool  PnlNgSpiceAC::bClear( void )
{
  // Clear the base class
  PnlAnaBase::bClear( );

  // Set the sweep parameters to their defaults
  m_oPnlStart.bSetValue( (float)   1.0 );
  m_oPnlStop .bSetValue( (float) 100.0 );
  m_oPnlStep .bSetValue( (float)  10.0 );
  m_oPnlStart.bSetUnits( wxT("kHz") );
  m_oPnlStop .bSetUnits( wxT("kHz") );

  // Set default scale value
  bSetScale( eSCALE_DEC );

  // Set input source default values
  m_oChoSrcName.Clear( );
  m_oChoSrcName.Append( wxT("None") );
  m_oChoSrcName.SetSelection( 0 );
  m_oPnlSrcLvl.bSetValue( (float) 0.0 );
  m_oPnlSrcLvl.bSetUnitsType( eUNITS_NONE );

  // Set parameters check box default values
  m_oCbxVoltage.SetValue( true );
  m_oCbxCurrent.SetValue( false );
  m_oCbxPower  .SetValue( false );
  m_oCbxResist .SetValue( false );

  // Set the complex part check box default values
  m_oCbxMag  .SetValue( true );
  m_oCbxPhase.SetValue( false );
  m_oCbxReal .SetValue( false );
  m_oCbxImag .SetValue( false );
  m_oCbxMagDb.SetValue( true );

  // Set default temperature value
  m_oPnlTemp.bSetValue( 27.0 );

  return( true );
}

//**************************************************************************************************
// Load information from a simulation object.
//
// Argument List :
//   roSim - A simulation object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PnlNgSpiceAC::bLoad( SimnNgSpice & roSimn )
{
  bool  bRtn=true;

  // Load components into the source choice box
  PnlAnaBase::LoadSrcNames( roSimn.m_oaCpnts, wxT("VI") );

  // Go no further if the AC command isn't valid
  if( ! roSimn.m_oCmdAC.bIsValid( ) )                        return( false );

  // Set the source component
  if( ! PnlAnaBase::bSetSrcCpnt( roSimn.m_oCpntSigSrc ) )    bRtn = false;

  // Set the step scale (do this before setting the sweep step)
  m_oRbxSweep.SetSelection( roSimn.m_oCmdAC.m_eScale );

  // Set the sweep values
  if( ! m_oPnlStart.bSetValue( roSimn.m_oCmdAC.m_osStart ) ) bRtn = false;
  if( ! m_oPnlStop .bSetValue( roSimn.m_oCmdAC.m_osStop  ) ) bRtn = false;
  if( ! m_oPnlStep .bSetValue( roSimn.m_oCmdAC.m_osStep  ) ) bRtn = false;

  // Set the complex parts to derive
  m_oCbxMag  .SetValue( roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_MAG   ] );
  m_oCbxPhase.SetValue( roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_PHASE ] );
  m_oCbxReal .SetValue( roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_REAL  ] );
  m_oCbxImag .SetValue( roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_IMAG  ] );
  m_oCbxMagDb.SetValue( roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_MAGDB ] );

  // Set the analysis temperature
  if( ! m_oPnlTemp.bSetValue( roSimn.m_oCmdOPT.m_osTEMP ) )  bRtn = false;

  return( bRtn );
}

//**************************************************************************************************
// Save information to a simulation object.
//
// Argument List :
//   roSimn - A simulation object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PnlNgSpiceAC::bSave( SimnNgSpice & roSimn )
{
  wxString  os1;
  float     f1;
  size_t    sz1;
  bool      b1;

  m_osErrMsg.Empty( );

  // Set the analysis type
  roSimn.m_oCmdPR.bSetAnaType( eCMD_AC );

  // Check the start frequency (can't set a frequency of zero so set one as
  // small as possible, 1.4e-45 is as small as I can go as a float but it will
  // be converted to a string in engineering units so use 1.0e-15 = 1.0f)
  CnvtType::bStrToFlt( roSimn.m_oCmdAC.m_osStart, &f1 );
  if( f1 == 0.0 ) roSimn.m_oCmdAC.m_osStart = wxT("1.0e-15");

  // Set the sweep values
  roSimn.m_oCmdAC.m_osStart = m_oPnlStart.rosGetValue( );
  roSimn.m_oCmdAC.m_osStop  = m_oPnlStop .rosGetValue( );
  roSimn.m_oCmdAC.m_osStep  = m_oPnlStep .rosGetValue( );

  // Set the sweep scale
  roSimn.m_oCmdAC.m_eScale = (eTypeScale) m_oRbxSweep.GetSelection( );

  // Set the sweep source component
  if( m_oChoSrcName.GetStringSelection( ) == wxT("None") )
    SetErrMsg( wxT("No source component has been selected.") );
  else if( m_oPnlSrcLvl.dfGetValue( ) == 0.0 )
    SetErrMsg( wxT("Signal source component value of zero is not permitted.") );
  else
  {
    os1 = m_oChoSrcName.GetStringSelection( );
    roSimn.m_oCpntSigSrc = roSimn.NetList::roGetCpnt( os1 );
    os1 = wxT("AC ") + m_oPnlSrcLvl.rosGetValue( );
    if( roSimn.m_oCpntSigSrc.eGetType( ) == eCPNT_IVS ) os1 += wxT('V');
    if( roSimn.m_oCpntSigSrc.eGetType( ) == eCPNT_ICS ) os1 += wxT('A');
    roSimn.m_oCpntSigSrc.bSetValue( os1 );
  }

  // Store the parameters to derive
  roSimn.m_oCmdPR.m_bParams[ ePARAM_VLT ] = m_oCbxVoltage.GetValue( );
  roSimn.m_oCmdPR.m_bParams[ ePARAM_CUR ] = m_oCbxCurrent.GetValue( );
  roSimn.m_oCmdPR.m_bParams[ ePARAM_PWR ] = m_oCbxPower  .GetValue( );
  roSimn.m_oCmdPR.m_bParams[ ePARAM_RES ] = m_oCbxResist .GetValue( );

  // Store the complex parts of the parameters to derive
  roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_MAG   ] = m_oCbxMag  .GetValue( );
  roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_PHASE ] = m_oCbxPhase.GetValue( );
  roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_REAL  ] = m_oCbxReal .GetValue( );
  roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_IMAG  ] = m_oCbxImag .GetValue( );
  roSimn.m_oCmdPR.m_bCpxPts[ eCPXPT_MAGDB ] = m_oCbxMagDb.GetValue( );

  // Create the command strings
  roSimn.m_oCmdAC.bFormat( );
  roSimn.m_oCmdPR.bFormat( );

  // Check for errors
  if( ! roSimn.m_oCmdAC.bIsValid( ) ) SetErrMsg( roSimn.m_oCmdAC.rosGetErrMsg( ) );
  if( ! roSimn.m_oCmdPR.bIsValid( ) ) SetErrMsg( roSimn.m_oCmdPR.rosGetErrMsg( ) );
  for( sz1=eCPXPT_MAG, b1=false; sz1<=eCPXPT_IMAG; sz1++ )
    if( roSimn.m_oCmdPR.m_bCpxPts[ sz1 ] ) b1 = true;
  if( ! b1 ) SetErrMsg( wxT("No complex parts have been selected.") );

  return( bIsOk( ) );
}

//**************************************************************************************************
//                                         Event Handlers                                          *
//**************************************************************************************************
// Step scale radio box event handler.
//
// Argument List :
//   roEvtCmd - An object holding information about the event

void  PnlNgSpiceAC::OnScale( wxCommandEvent & roEvtCmd )
{
  InitScale( );
}

//**************************************************************************************************
// Source component choice box event handler.
//
// Argument List :
//   roEvtCmd - An object holding information about the event

void  PnlNgSpiceAC::OnSrcName( wxCommandEvent & roEvtCmd )
{
  wxString  os1;

  if( m_oChoSrcName.GetStringSelection( ) != wxT("None") )
  {
    // Set the units type
    os1 = m_oChoSrcName.GetStringSelection( );
    m_oPnlSrcLvl.bSetUnitsType( Component::eGetUnitsType( os1 ) );

    // Set the source value
    if( m_oPnlSrcLvl.dfGetValue( ) == 0.0 )
      m_oPnlSrcLvl.bSetValue( (double) 1.0 );
  }
  else
  {
    m_oPnlSrcLvl.bSetUnitsType( eUNITS_NONE );
    m_oPnlSrcLvl.bSetValue( (double) 0.0 );
  }
}

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