//**************************************************************************************************
//                                          ChoUnits.cpp                                           *
//                                         --------------                                          *
// Started     : 2004-03-27                                                                        *
// Last Update : 2018-10-19                                                                        *
// 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 "ChoUnits.hpp"

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

ChoUnits::ChoUnits( void ) : UnitsBase( ), wxChoice( )
{
  bClear( );
}

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

ChoUnits::~ChoUnits( )
{
}

//**************************************************************************************************
// Create an instance of this object.
//
// Argument List :
//   poWin  - The parent window
//   oWinID - The window identifier
//   iWidth - The width of the choice control in pixels
//
// Return Values :
//   true  - Success
//   false - Failure

bool  ChoUnits::bCreate( wxWindow * poWin, wxWindowID oWinID, int iWidth )
{
  // Check if the object has already been created
  if( bIsCreated( ) )                                                               return( true );

  // Create the object
#if wxCHECK_VERSION( 3,0,0 )
  if( ! wxChoice::Create( poWin, oWinID, wxDefaultPosition, wxSize( iWidth, -1) ) ) return( false );
#else
  if( ! wxChoice::Create( poWin, oWinID, wxDefaultPosition, wxSize( iWidth, GUI_CTRL_HT ) ) )
                                                                                    return( false );
#endif
  // Set the units
  if( ! bSetUnitsType( m_eUnitsType ) )                                             return( false );
  if( ! bSetUnits( m_osDefUnits ) )                                                 return( false );

  return( true );
}

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

bool  ChoUnits::bClear( void )
{
  m_eUnitsType = eUNITS_NONE;
  m_osDefUnits = wxT("Units");

  if( bIsCreated( ) ) ChoUnits::Clear( );

  return( true );
}

//**************************************************************************************************
// Set the type of units to be displayed.
//
// Argument List :
//   eUType - The type of units to be displayed
//
// Return Values :
//   Success - true
//   Failure - false

bool  ChoUnits::bSetUnitsType( eTypeUnits eUType )
{
  int  i1;

  if( ! bIsCreated( ) )                               return( false );
  if( eUType==m_eUnitsType && !ChoUnits::IsEmpty( ) ) return( true );

  // Load the new choice items into the control
  switch( eUType )
  {
    case eUNITS_CAP :   // Capacitance
      ChoUnits::Clear( ); // Delete existing choice items from the list
      ChoUnits::Append( wxT("F")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mF")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uF")     , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nF")     , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pF")     , new wxStringClientData( wxT("-12") ) );
      m_osDefUnits = wxT("uF");
      break;

    case eUNITS_IND :   // Inductance
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("H")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mH")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uH")     , new wxStringClientData(  wxT("-6") ) );
      m_osDefUnits = wxT("mH");
      break;

    case eUNITS_RES :   // Resistance
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("GOhm")   , new wxStringClientData(   wxT("9") ) );
      ChoUnits::Append( wxT("MOhm")   , new wxStringClientData(   wxT("6") ) );
      ChoUnits::Append( wxT("kOhm")   , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("Ohm")    , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mOhm")   , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uOhm")   , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nOhm")   , new wxStringClientData(  wxT("-9") ) );
      m_osDefUnits = wxT("kOhm");
      break;

    case eUNITS_COND :  // Conductance
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("kS")     , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("S")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mS")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uS")     , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nS")     , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pS")     , new wxStringClientData( wxT("-12") ) );
      ChoUnits::Append( wxT("fS")     , new wxStringClientData( wxT("-15") ) );
      m_osDefUnits = wxT("mS");
      break;

    case eUNITS_VOLT :  // Voltage
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("MV")     , new wxStringClientData(   wxT("6") ) );
      ChoUnits::Append( wxT("kV")     , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("V")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mV")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uV")     , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nV")     , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pV")     , new wxStringClientData( wxT("-12") ) );
      ChoUnits::Append( wxT("fV")     , new wxStringClientData( wxT("-15") ) );
      m_osDefUnits = wxT("mV");
      break;

    case eUNITS_CURR :  // Current
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("kA")     , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("A")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mA")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uA")     , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nA")     , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pA")     , new wxStringClientData( wxT("-12") ) );
      m_osDefUnits = wxT("mA");
      break;

    case eUNITS_TIME :  // Time
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("Sec")    , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mSec")   , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uSec")   , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nSec")   , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pSec")   , new wxStringClientData( wxT("-12") ) );
      m_osDefUnits = wxT("mSec");
      break;

    case eUNITS_FREQ :  // Frequency
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("THz")    , new wxStringClientData(  wxT("12") ) );
      ChoUnits::Append( wxT("GHz")    , new wxStringClientData(   wxT("9") ) );
      ChoUnits::Append( wxT("MHz")    , new wxStringClientData(   wxT("6") ) );
      ChoUnits::Append( wxT("kHz")    , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("Hz")     , new wxStringClientData(   wxT("0") ) );
      m_osDefUnits = wxT("kHz");
      break;

    case eUNITS_CHRG :  // Charge
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("C")      , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("mC")     , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("uC")     , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("nC")     , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("pC")     , new wxStringClientData( wxT("-12") ) );
      ChoUnits::Append( wxT("fC")     , new wxStringClientData( wxT("-15") ) );
      m_osDefUnits = wxT("uC");
      break;

    case eUNITS_PHAD :  // Phase / angle
    case eUNITS_PHAR :
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("Degree") , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("Radian") , new wxStringClientData(   wxT("0") ) );
      m_osDefUnits = wxT("Degree");
      break;

    case eUNITS_TMPC :  // Temperature
    case eUNITS_TMPF :
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("Deg.C")  , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("Deg.F")  , new wxStringClientData(   wxT("0") ) );
      m_osDefUnits = wxT("Deg.C");
      break;

    case eUNITS_EXP :  // Dimensionless, append an exponent
      ChoUnits::Clear( );
//    ChoUnits::Append( wxT("x 1E21") , new wxStringClientData(  wxT("21") ) );
//    ChoUnits::Append( wxT("x 1E18") , new wxStringClientData(  wxT("18") ) );
      ChoUnits::Append( wxT("x 1E15") , new wxStringClientData(  wxT("15") ) );
      ChoUnits::Append( wxT("x 1E12") , new wxStringClientData(  wxT("12") ) );
      ChoUnits::Append( wxT("x 1E9")  , new wxStringClientData(   wxT("9") ) );
      ChoUnits::Append( wxT("x 1E6")  , new wxStringClientData(   wxT("6") ) );
      ChoUnits::Append( wxT("x 1E3")  , new wxStringClientData(   wxT("3") ) );
      ChoUnits::Append( wxT("x 1")    , new wxStringClientData(   wxT("0") ) );
      ChoUnits::Append( wxT("x 1E-3") , new wxStringClientData(  wxT("-3") ) );
      ChoUnits::Append( wxT("x 1E-6") , new wxStringClientData(  wxT("-6") ) );
      ChoUnits::Append( wxT("x 1E-9") , new wxStringClientData(  wxT("-9") ) );
      ChoUnits::Append( wxT("x 1E-12"), new wxStringClientData( wxT("-12") ) );
      ChoUnits::Append( wxT("x 1E-15"), new wxStringClientData( wxT("-15") ) );
//    ChoUnits::Append( wxT("x 1E-18"), new wxStringClientData( wxT("-18") ) );
//    ChoUnits::Append( wxT("x 1E-21"), new wxStringClientData( wxT("-21") ) );
      m_osDefUnits = wxT("x 1");
      break;

    case eUNITS_NONE :  // No units specified
      ChoUnits::Clear( );
      ChoUnits::Append( wxT("Units")  , new wxStringClientData(   wxT("0") ) );
      m_osDefUnits = wxT("Units");
      break;

    default :
      return( false );
  }

  // Set the new units type
  m_eUnitsType = eUType;

  // Select the default units
  i1 = ChoUnits::FindString( m_osDefUnits, true );  // Do case sensitive string search
  if( i1 != wxNOT_FOUND ) ChoUnits::SetSelection( i1 );

  return( true );
}

//**************************************************************************************************
// Set the units to be displayed.
//
// Note : If a units type is specified in the function argument it must correspond with the type
//        currently set in this class instance.
//
// Argument List:
//   rosUnits - The units to be displayed as a string
//
// Return Values:
//   Success - true
//   Failure - false

bool  ChoUnits::bSetUnits( const wxString & rosUnits )
{
  eTypeUnits  eUType;
  int         i1;

  if( ! bIsCreated( ) )              return( false );

  // Are a different units type specified in the function argument?
  if( UnitsBase::bGetUnitsType( rosUnits, &eUType ) )
    if( eUType != eGetUnitsType( ) ) return( false );

  // Check that the specified units are supported
  i1 = ChoUnits::FindString( rosUnits );
  if( i1 == wxNOT_FOUND )            return( false );

  // Set the units displayed in the control
  ChoUnits::SetSelection( i1 );

  return( true );
}

//**************************************************************************************************
// Set the units to be displayed.
//
// Argument List :
//   iExp - The exponent associated with the units to be displayed
//
// Return Values :
//   Success - true
//   Failure - false

bool  ChoUnits::bSetUnits( int iExp )
{
  wxString  os1;
  long      li1;
  uint      ui1;

  if( ! bIsCreated( ) ) return( false );

  for( ui1=0; ui1<ChoUnits::GetCount( ); ui1++ )
  {
    li1 = 0;
    os1 = ( (wxStringClientData *) ChoUnits::GetClientObject( ui1 ) )->GetData( );
    os1.ToLong( &li1 );
    if( (int) li1 == iExp )
    {
      ChoUnits::SetSelection( ui1 );
      return( true );
    }
  }

  return( false );
}

//**************************************************************************************************
// Set the default units.
//
// Argument List :
//   rosUnits - The default units to be used
//
// Return Values :
//   Success - true
//   Failure - false

bool  ChoUnits::bSetDefUnits( const wxString & rosUnits )
{
  // Don't proceed unless the display object has been created
  if( ! bIsCreated( ) )                                 return( false );

  // Attempt to find the specified units
  if( ChoUnits::FindString( rosUnits ) == wxNOT_FOUND ) return( false );

  // Set the default units
  m_osDefUnits = rosUnits;

  return( true );
}

//**************************************************************************************************
// Get the currently selected units.
//
// Return Values :
//   Success - The selected units
//   Failure - An empty string

const wxString & ChoUnits::rosGetUnits( void )
{
  static  wxString  osUnits;

  osUnits.Empty( );

  if( ! bIsCreated( ) ) return( osUnits );

  osUnits = ChoUnits::GetStringSelection( );

  return( osUnits );
}

//**************************************************************************************************
// Get the currently selected units as an exponent.
//
// Eg. if the units are mV return -3 or if the units are MOhm return 6.
//
// Return Values :
//   Success - The units exponent
//   Failure - 0

int  ChoUnits::iGetUnits( void )
{
  wxString  os1;
  long      i1;

  if( ! bIsCreated( ) )                   return( 0 );

  i1 = ChoUnits::GetSelection( );
  if( i1 == wxNOT_FOUND )                 return( 0 );

  os1 = ( (wxStringClientData *) ChoUnits::GetClientObject( i1 ) )->GetData( );
  if( ! CnvtType::bStrToInt( os1, &i1 ) ) return( 0 );

  return( i1 );
}

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

void  ChoUnits::Print( const wxString & rosPrefix )
{
  std::cout << rosPrefix.mb_str( ) << "m_eUnitsType : ";
  switch( m_eUnitsType )
  {
    case eUNITS_CAP  : std::cout << "eUNITS_CAP";  break;
    case eUNITS_IND  : std::cout << "eUNITS_IND";  break;
    case eUNITS_RES  : std::cout << "eUNITS_RES";  break;
    case eUNITS_COND : std::cout << "eUNITS_COND"; break;
    case eUNITS_VOLT : std::cout << "eUNITS_VOLT"; break;
    case eUNITS_CURR : std::cout << "eUNITS_CURR"; break;
    case eUNITS_TIME : std::cout << "eUNITS_TIME"; break;
    case eUNITS_FREQ : std::cout << "eUNITS_FREQ"; break;
    case eUNITS_CHRG : std::cout << "eUNITS_CHRG"; break;
    case eUNITS_PHAD : std::cout << "eUNITS_PHAD"; break;
    case eUNITS_PHAR : std::cout << "eUNITS_PHAR"; break;
    case eUNITS_TMPC : std::cout << "eUNITS_TMPC"; break;
    case eUNITS_TMPF : std::cout << "eUNITS_TMPF"; break;
    case eUNITS_PCT  : std::cout << "eUNITS_PCT";  break;
    case eUNITS_EXP  : std::cout << "eUNITS_EXP";  break;

    case eUNITS_NONE : std::cout << "eUNITS_NONE"; break;

    default          : std::cout << "Invalid";
  }
  std::cout << '\n';

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

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