//**************************************************************************************************
//                                      DlgNgSpiceCfgSrc.hpp                                       *
//                                     ----------------------                                      *
// Started     : 2005-05-13                                                                        *
// Last Update : 2018-11-03                                                                        *
// Copyright   : (C) 2005-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 "DlgNgSpiceCfgSrc.hpp"

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

wxBEGIN_EVENT_TABLE( DlgNgSpiceCfgSrc, wxDialog )

  EVT_BUTTON( DlgNgSpiceCfgSrc::ID_BTN_OK,     DlgNgSpiceCfgSrc::OnBtnOk     )
  EVT_BUTTON( DlgNgSpiceCfgSrc::ID_BTN_CLEAR,  DlgNgSpiceCfgSrc::OnBtnClear  )
  EVT_BUTTON( DlgNgSpiceCfgSrc::ID_BTN_CANCEL, DlgNgSpiceCfgSrc::OnBtnCancel )

wxEND_EVENT_TABLE( )

//**************************************************************************************************
// Constructor.
//
// Argument List :
//   poWin - A pointer to the dialog parent window

DlgNgSpiceCfgSrc::DlgNgSpiceCfgSrc( wxWindow * poWin ) :
                                    wxDialog( poWin, -1, wxT(""), wxDefaultPosition, wxDefaultSize,
                                              wxDEFAULT_DIALOG_STYLE, wxDialogNameStr )
{
  SetTitle( wxT("Signal Source Setup") );
  Initialize( );
  bClear( );
}

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

DlgNgSpiceCfgSrc::~DlgNgSpiceCfgSrc( )
{
}

//**************************************************************************************************
// Initialize object attributes.

void  DlgNgSpiceCfgSrc::Initialize( void )
{
  // Call all the initialization functions
  Create( );
  ToolTips( );

  // Layout the of the display objects
  DoLayout( );
}

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

void  DlgNgSpiceCfgSrc::Create( void )
{
  wxPanel * poPnlSine, * poPnlPulse, * poPnlBtns;
  int       iWdName=115, iWdValue=95, iWdUnits=75;

  // Create the various underlying panel objects
  poPnlSine  = new wxPanel( this );
  poPnlPulse = new wxPanel( this );
  poPnlBtns  = new wxPanel( this );

  // Create the Sinusoid panel controls
  m_oPnlSinAmp   .bCreate( poPnlSine, ID_PNL_SIN_AMP   , iWdName, iWdValue, iWdUnits );
  m_oPnlSinFreq  .bCreate( poPnlSine, ID_PNL_SIN_FREQ  , iWdName, iWdValue, iWdUnits );
  m_oPnlSinOffset.bCreate( poPnlSine, ID_PNL_SIN_OFFSET, iWdName, iWdValue, iWdUnits );
  m_oPnlSinDelay .bCreate( poPnlSine, ID_PNL_SIN_DELAY , iWdName, iWdValue, iWdUnits );
  m_oPnlSinDamp  .bCreate( poPnlSine, ID_PNL_SIN_DAMP  , iWdName, iWdValue, iWdUnits );

  m_oPnlSinAmp   .bSetName( wxT("Amplitude")      );
  m_oPnlSinFreq  .bSetName( wxT("Frequency")      );
  m_oPnlSinOffset.bSetName( wxT("DC Offset")      );
  m_oPnlSinDelay .bSetName( wxT("Initial Delay")  );
  m_oPnlSinDamp  .bSetName( wxT("Damping Factor") );

  m_oPnlSinAmp   .bSetUnitsType( eUNITS_VOLT );
  m_oPnlSinFreq  .bSetUnitsType( eUNITS_FREQ );
  m_oPnlSinOffset.bSetUnitsType( eUNITS_VOLT );
  m_oPnlSinDelay .bSetUnitsType( eUNITS_TIME );
  m_oPnlSinDamp  .bShowUnits( PnlValue::eSHOW_LBL );

  // Create the Pulse panel controls
  m_oPnlPulInitV .bCreate( poPnlPulse, ID_PNL_PUL_INITV , iWdName, iWdValue, iWdUnits );
  m_oPnlPulValue .bCreate( poPnlPulse, ID_PNL_PUL_VALUE , iWdName, iWdValue, iWdUnits );
  m_oPnlPulDelay .bCreate( poPnlPulse, ID_PNL_PUL_DELAY , iWdName, iWdValue, iWdUnits );
  m_oPnlPulRise  .bCreate( poPnlPulse, ID_PNL_PUL_RISE  , iWdName, iWdValue, iWdUnits );
  m_oPnlPulWidth .bCreate( poPnlPulse, ID_PNL_PUL_WIDTH , iWdName, iWdValue, iWdUnits );
  m_oPnlPulFall  .bCreate( poPnlPulse, ID_PNL_PUL_FALL  , iWdName, iWdValue, iWdUnits );
  m_oPnlPulPeriod.bCreate( poPnlPulse, ID_PNL_PUL_PERIOD, iWdName, iWdValue, iWdUnits );

  m_oPnlPulInitV .bSetName( wxT("Initial Value") );
  m_oPnlPulValue .bSetName( wxT("Pulsed Value")  );
  m_oPnlPulDelay .bSetName( wxT("Initial Delay") );
  m_oPnlPulRise  .bSetName( wxT("Rise Time")     );
  m_oPnlPulWidth .bSetName( wxT("Pulse Width")   );
  m_oPnlPulFall  .bSetName( wxT("Fall Time")     );
  m_oPnlPulPeriod.bSetName( wxT("Period")        );

  m_oPnlPulInitV .bSetUnitsType( eUNITS_VOLT );
  m_oPnlPulValue .bSetUnitsType( eUNITS_VOLT );
  m_oPnlPulDelay .bSetUnitsType( eUNITS_TIME );
  m_oPnlPulRise  .bSetUnitsType( eUNITS_TIME );
  m_oPnlPulWidth .bSetUnitsType( eUNITS_TIME );
  m_oPnlPulFall  .bSetUnitsType( eUNITS_TIME );
  m_oPnlPulPeriod.bSetUnitsType( eUNITS_TIME );

  // Create buttons panel and the button controls
  m_oBtnOk    .Create( poPnlBtns, ID_BTN_OK,     wxT("OK")     );
  m_oBtnClear .Create( poPnlBtns, ID_BTN_CLEAR,  wxT("Clear")  );
  m_oBtnCancel.Create( poPnlBtns, ID_BTN_CANCEL, wxT("Cancel") );
}

//**************************************************************************************************
// Initialize the tool tips.

void  DlgNgSpiceCfgSrc::ToolTips( void )
{
  m_oPnlSinAmp   .SetToolTip( wxT("The amplitude of the sinusoidal signal") );
  m_oPnlSinFreq  .SetToolTip( wxT("The frequency of the sinusoidal signal") );
  m_oPnlSinOffset.SetToolTip( wxT("The DC offset of the sinusoidal signal") );
  m_oPnlSinDelay .SetToolTip( wxT("The initial delay of the sinusoidal signal") );
  m_oPnlSinDamp  .SetToolTip( wxT("The damping factor of the sinusoidal signal") );

  m_oPnlPulInitV .SetToolTip( wxT("The initial value of the pulse source") );
  m_oPnlPulValue .SetToolTip( wxT("The value of each pulse") );
  m_oPnlPulDelay .SetToolTip( wxT("The time until the first pulse") );
  m_oPnlPulRise  .SetToolTip( wxT("The time taken to go from 0 to the pulsed value") );
  m_oPnlPulWidth .SetToolTip( wxT("The width of each pulse") );
  m_oPnlPulFall  .SetToolTip( wxT("The time taken to go from the pulsed value to 0") );
  m_oPnlPulPeriod.SetToolTip( wxT("The period of the pulse train") );
}

//**************************************************************************************************
// Layout the dialog display objects.

void  DlgNgSpiceCfgSrc::DoLayout( void )
{
  wxPanel          * poPnlSine, * poPnlPulse, * poPnlBtns;
  wxBoxSizer       * poSzrDlg , * poSzrBtns;
  wxStaticBoxSizer * poSzrSine, * poSzrPulse;
  wxSizerFlags       oFlags;
  wxFont             oFont;

  // Get pointers to the various panels
  poPnlSine  = (wxPanel *) m_oPnlSinFreq .GetParent( );
  poPnlPulse = (wxPanel *) m_oPnlPulInitV.GetParent( );
  poPnlBtns  = (wxPanel *) m_oBtnOk      .GetParent( );

  // Create sizers to associate with the panels
  poSzrDlg   = new wxBoxSizer      ( wxVERTICAL   );
  poSzrSine  = new wxStaticBoxSizer( wxVERTICAL, poPnlSine , wxT(" Sinusoid ") );
  poSzrPulse = new wxStaticBoxSizer( wxVERTICAL, poPnlPulse, wxT(" Pulse ") );
  poSzrBtns  = new wxBoxSizer      ( wxHORIZONTAL );

  // Set the font of the static box labels
  oFont = poSzrSine->GetStaticBox( )->GetFont( );
  oFont.SetStyle( wxFONTSTYLE_ITALIC );
  poSzrSine ->GetStaticBox( )->SetFont( oFont );
  poSzrPulse->GetStaticBox( )->SetFont( oFont );

  // Set the sizers to the panels
              SetSizer( poSzrDlg   );
  poPnlSine ->SetSizer( poSzrSine  );
  poPnlPulse->SetSizer( poSzrPulse );
  poPnlBtns ->SetSizer( poSzrBtns  );

  // Layout the Sinusoid  panel
  oFlags.Align( wxALIGN_LEFT );
  oFlags.Border( wxTOP | wxLEFT | wxRIGHT, 10 );
  poSzrSine->Add( &m_oPnlSinAmp   , oFlags );
  oFlags.Border( wxLEFT | wxRIGHT        , 10 );
  poSzrSine->Add( &m_oPnlSinFreq  , oFlags );
  poSzrSine->Add( &m_oPnlSinOffset, oFlags );
  poSzrSine->Add( &m_oPnlSinDelay , oFlags );
  oFlags.Border( wxLEFT | wxBOTTOM       , 10 );
  poSzrSine->Add( &m_oPnlSinDamp  , oFlags );

  // Layout the Pulse panel
  oFlags.Border( wxTOP | wxLEFT | wxRIGHT, 10 );
  poSzrPulse->Add( &m_oPnlPulInitV , oFlags );
  oFlags.Border( wxLEFT | wxRIGHT        , 10 );
  poSzrPulse->Add( &m_oPnlPulValue , oFlags );
  poSzrPulse->Add( &m_oPnlPulDelay , oFlags );
  poSzrPulse->Add( &m_oPnlPulRise  , oFlags );
  poSzrPulse->Add( &m_oPnlPulWidth , oFlags );
  poSzrPulse->Add( &m_oPnlPulFall  , oFlags );
  oFlags.Border( wxLEFT | wxBOTTOM       , 10 );
  poSzrPulse->Add( &m_oPnlPulPeriod, oFlags );

  // Layout the button panel
  oFlags.Align( wxALIGN_RIGHT  );
  oFlags.Border( wxTOP | wxBOTTOM, 10 );
  poSzrBtns->Add( &m_oBtnOk    , oFlags );
  poSzrBtns->AddSpacer( 10 );
  oFlags.Align( wxALIGN_CENTER );
  poSzrBtns->Add( &m_oBtnClear , oFlags );
  poSzrBtns->AddSpacer( 10 );
  oFlags.Align( wxALIGN_LEFT   );
  poSzrBtns->Add( &m_oBtnCancel, oFlags );

  // Layout the underlying dialog
  oFlags.Align( wxALIGN_CENTER );
  oFlags.Border( wxTOP | wxLEFT | wxRIGHT, 15 );
  poSzrDlg->Add( poPnlSine , oFlags );
  oFlags.Border( wxALL                   , 15 );
  poSzrDlg->Add( poPnlPulse, oFlags );
  oFlags.Align( wxALIGN_CENTER );
  oFlags.Border( wxBOTTOM                , 15 );
  poSzrDlg->Add( poPnlBtns , oFlags );

  // Set dialogues minimum size and initial size as calculated by the sizer
  poSzrSine ->SetSizeHints( poPnlSine  );
  poSzrPulse->SetSizeHints( poPnlPulse );
  poSzrBtns ->SetSizeHints( poPnlBtns  );
  poSzrDlg  ->SetSizeHints( this       );
}

//**************************************************************************************************
// Get a pointer to a value panel associated with a control ID number.
//
// Argument List :
//   iPnlID - The control ID number
//
// Return Values :
//   Success - A pointer to the value panel
//   Failure - NULL

PnlValue * DlgNgSpiceCfgSrc::poGetPanel( int iPnlID )
{
  switch( iPnlID )
  {
    case ID_PNL_SIN_AMP    : return( &m_oPnlSinAmp    );
    case ID_PNL_SIN_FREQ   : return( &m_oPnlSinFreq   );
    case ID_PNL_SIN_OFFSET : return( &m_oPnlSinOffset );
    case ID_PNL_SIN_DELAY  : return( &m_oPnlSinDelay  );
    case ID_PNL_SIN_DAMP   : return( &m_oPnlSinDamp   );
    case ID_PNL_PUL_INITV  : return( &m_oPnlPulInitV  );
    case ID_PNL_PUL_VALUE  : return( &m_oPnlPulValue  );
    case ID_PNL_PUL_DELAY  : return( &m_oPnlPulDelay  );
    case ID_PNL_PUL_RISE   : return( &m_oPnlPulRise   );
    case ID_PNL_PUL_WIDTH  : return( &m_oPnlPulWidth  );
    case ID_PNL_PUL_FALL   : return( &m_oPnlPulFall   );
    case ID_PNL_PUL_PERIOD : return( &m_oPnlPulPeriod );

    default                : return( NULL );
  }
}

//**************************************************************************************************
// Set the values in the value panel controls.
//
// Argument List :
//   roCpntSrc - A reference to an independent source component object

void  DlgNgSpiceCfgSrc::SetValues( CpntNgSpiceIndSrc & roCpntSrc )
{
  SetEvtHandlerEnabled( false );

  m_oPnlSinAmp   .bSetValue( roCpntSrc.m_osSinAmp    );
  m_oPnlSinFreq  .bSetValue( roCpntSrc.m_osSinFreq   );
  m_oPnlSinOffset.bSetValue( roCpntSrc.m_osSinOffset );
  m_oPnlSinDelay .bSetValue( roCpntSrc.m_osSinDelay  );
  m_oPnlSinDamp  .bSetValue( roCpntSrc.m_osSinDamp   );

  m_oPnlPulInitV .bSetValue( roCpntSrc.m_osPulInitV  );
  m_oPnlPulValue .bSetValue( roCpntSrc.m_osPulValue  );
  m_oPnlPulDelay .bSetValue( roCpntSrc.m_osPulDelay  );
  m_oPnlPulRise  .bSetValue( roCpntSrc.m_osPulRise   );
  m_oPnlPulWidth .bSetValue( roCpntSrc.m_osPulWidth  );
  m_oPnlPulFall  .bSetValue( roCpntSrc.m_osPulFall   );
  m_oPnlPulPeriod.bSetValue( roCpntSrc.m_osPulPeriod );

  SetEvtHandlerEnabled( true );
}

//**************************************************************************************************
// Get the values from the value panel controls.
//
// Argument List :
//   roCpntSrc - A reference to an independent source component object

void  DlgNgSpiceCfgSrc::GetValues( CpntNgSpiceIndSrc & roCpntSrc )
{
  SetEvtHandlerEnabled( false );

  roCpntSrc.m_osSinAmp    = m_oPnlSinAmp   .rosGetValue( );
  roCpntSrc.m_osSinFreq   = m_oPnlSinFreq  .rosGetValue( );
  roCpntSrc.m_osSinOffset = m_oPnlSinOffset.rosGetValue( );
  roCpntSrc.m_osSinDelay  = m_oPnlSinDelay .rosGetValue( );
  roCpntSrc.m_osSinDamp   = m_oPnlSinDamp  .rosGetValue( );

  roCpntSrc.m_osPulInitV  = m_oPnlPulInitV .rosGetValue( );
  roCpntSrc.m_osPulValue  = m_oPnlPulValue .rosGetValue( );
  roCpntSrc.m_osPulDelay  = m_oPnlPulDelay .rosGetValue( );
  roCpntSrc.m_osPulRise   = m_oPnlPulRise  .rosGetValue( );
  roCpntSrc.m_osPulWidth  = m_oPnlPulWidth .rosGetValue( );
  roCpntSrc.m_osPulFall   = m_oPnlPulFall  .rosGetValue( );
  roCpntSrc.m_osPulPeriod = m_oPnlPulPeriod.rosGetValue( );

  SetEvtHandlerEnabled( true );
}

//**************************************************************************************************
// Get a value panel control's value.
//
// Argument List :
//   iPnlID - Value panel control identifier
//
// Return Values :
//   Success - The panel value
//   Failure - An empty string

const wxString & DlgNgSpiceCfgSrc::rosGetValue( int iPnlID )
{
  static  wxString   osEmpty;
          PnlValue * poPnlValue;

  poPnlValue = poGetPanel( iPnlID );
  if( poPnlValue == NULL ) return( osEmpty );

  return( poPnlValue->rosGetValue( ) );
}

//**************************************************************************************************
// Set a value panel control's value.
//
// Argument List :
//   iPnlID   - Value panel control identifier
//   rosValue - The value to set
//
// Return Values :
//   true  - Success
//   false - Failure

bool  DlgNgSpiceCfgSrc::bSetValue( int iPnlID, const wxString & rosValue )
{
  PnlValue * poPnlValue;

  // Get a pointer to the appropriate value panel
  poPnlValue = poGetPanel( iPnlID );
  if( poPnlValue == NULL )                  return( false );

  // Set the panel value
  if( ! poPnlValue->bSetValue( rosValue ) ) return( false );

  // Update the Independent Source component object
  GetValues( m_oCpntIndSrc );

  return( true );
}

//**************************************************************************************************
// Set the source component name.
//
// Argument List :
//   rosName - The name of the source component
//
// Return Values :
//   true  - Success
//   false - Failure

bool  DlgNgSpiceCfgSrc::bSetName( wxString & rosName )
{
  eTypeCpnt  eCpnt;

  eCpnt = Component::eGetType( rosName );
  if( eCpnt!=eCPNT_IVS && eCpnt!=eCPNT_ICS ) return( false );

  m_oCpntIndSrc.bSetName( rosName );

  return( true );
}

//**************************************************************************************************
// Reset all dialog settings to defaults.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  DlgNgSpiceCfgSrc::bClear( void )
{
  m_oCpntIndSrc.bClear( );

  SetValues( m_oCpntIndSrc );

  return( true );
}

//**************************************************************************************************
// Set the values in the value panel controls.
//
// Argument List :
//   roCpntSrc - A reference to an independent source component object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  DlgNgSpiceCfgSrc::bSetValues( CpntNgSpiceIndSrc & roCpntSrc )
{
  SetValues( roCpntSrc );
  m_oCpntIndSrc = roCpntSrc;

  return( true );
}

//**************************************************************************************************
// Get the values from the value panel controls.
//
// Argument List :
//   roCpntSrc - A reference to an independent source component object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  DlgNgSpiceCfgSrc::bGetValues( CpntNgSpiceIndSrc & roCpntSrc )
{
  GetValues( roCpntSrc );

  return( true );
}

//**************************************************************************************************
//                                         Event Handlers                                          *
//**************************************************************************************************
// OK button event handler.
//
// Argument List :
//   roEvtCmd - An object holding information about the event (not used)

void  DlgNgSpiceCfgSrc::OnBtnOk( wxCommandEvent & roEvtCmd )
{
  GetValues( m_oCpntIndSrc );
  EndModal( wxID_OK );
}

//**************************************************************************************************
// Clear button event handler.
//
// Argument List :
//   roEvtCmd - An object holding information about the event (not used)

void  DlgNgSpiceCfgSrc::OnBtnClear( wxCommandEvent & roEvtCmd )
{
  CpntNgSpiceIndSrc  oCpntIndSrc;

  oCpntIndSrc.bClear( );
  SetValues( oCpntIndSrc );
}

//**************************************************************************************************
// Cancel button event handler.
//
// Argument List :
//   roEvtCmd - An object holding information about the event (not used)

void  DlgNgSpiceCfgSrc::OnBtnCancel( wxCommandEvent & roEvtCmd )
{
  SetValues( m_oCpntIndSrc );
  EndModal( wxID_CANCEL );
}

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