//**************************************************************************************************
//                                        PrcSimEngBase.cpp                                        *
//                                       -------------------                                       *
// Started     : 2004-04-25                                                                        *
// Last Update : 2018-10-26                                                                        *
// 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 "PrcSimEngBase.hpp"

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

PrcSimEngBase::PrcSimEngBase( void ) : PrcBase( wxPROCESS_REDIRECT )
{
  m_eSimEng = eSIMR_NONE;
}

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

PrcSimEngBase::~PrcSimEngBase( )
{
}

//**************************************************************************************************
// Set the simulation results file name.
//
// Argument List :
//   rosFileName - A string containing the full path and file name
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PrcSimEngBase::bSetResultsFile( const wxString & rosFileName )
{
  wxFileName  ofn1;

  ofn1 = rosFileName;
  if( ofn1.GetPath( ).IsEmpty( ) ) ofn1.SetPath( wxT(".") );

  if( ! ofn1.IsOk( ) ) return( false );

  m_oNameResults = ofn1;

  return( true );
}

//**************************************************************************************************
// Make the process argument list based on the contents of a simulation object.
//
// Argument List :
//   roSimn - The simulation object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PrcSimEngBase::bMakeArgLst( SimnBase & roSimn )
{
  wxString  os1;
  int       i1;

  // Clear error message
  PrcBase::ClrErrMsg( );

  // Only proceed if the simulator isn't already running
  if( bIsExec( ) )
  {
    SetErrMsg( wxT("Simulator already running") );
    return( false );
  }

  // Create the results file name
  os1 = roSimn.roGetLoadFile( ).GetPath( ) + wxT('/')
      + roSimn.roGetLoadFile( ).GetName( );
  i1 = os1.Find( wxT(".gspiceui") );
  if( i1 > 0 ) os1 = os1.Truncate( (size_t) i1 );
  os1 << wxT('.') << roGetBinFile( ).GetName( );
  switch( roSimn.eGetAnaType( ) )
  {
    case eCMD_OP : os1 << wxT(".op"); break;
    case eCMD_DC : os1 << wxT(".dc"); break;
    case eCMD_AC : os1 << wxT(".ac"); break;
    case eCMD_TR : os1 << wxT(".tr"); break;
    case eCMD_FO : os1 << wxT(".fo"); break;
    case eCMD_DI : os1 << wxT(".di"); break;
    case eCMD_NO : os1 << wxT(".no"); break;
    case eCMD_PZ : os1 << wxT(".pz"); break;
    case eCMD_SE : os1 << wxT(".se"); break;
    case eCMD_TF : os1 << wxT(".tf"); break;
    default      : return( false );
  }

  // Set the results file name
  if( ! PrcSimEngBase::bSetResultsFile( os1 ) )
  {
    PrcBase::SetErrMsg( wxT("Couldn't set results file name") );
    return( false );
  }

  // Construct the default argument list
  os1 = rosEscSpaceChrs( roSimn.roGetSaveFile( ).GetFullPath( ) );
  if( ! bSetArgLst( os1 ) )
  {
    PrcBase::SetErrMsg( wxT("Couldn't set argument list") );
    return( false );
  }

  // Set the process working directory to the netlist directory
  PrcBase::bSetCwd( roSimn.roGetSaveFile( ).GetPath( ) );

  return( true );
}

//**************************************************************************************************
// Execute a simulation.
//
// Argument List :
//   roSimn - The simulation object
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PrcSimEngBase::bExec( void )
{
  wxString  os1, os2;

  // Execute the simulation
  if( ! PrcBase::bExecAsync( ) ) return( false );

  // Save the simulation results to the log file
  if( ! PrcBase::bLogOutput( ) ) return( false );

  // Copy the log file to the results file
  os1 = roGetLogFile( ).GetFullPath( );
  os2 = roGetResultsFile( ).GetFullPath( );
  if( ! wxCopyFile( os1, os2 ) ) return( false );

  return( true );
}

//**************************************************************************************************
// Format the results file. All this function does is aline the data in columns and packs the
// columns together.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  PrcSimEngBase::bFmtResults( void )
{
  wxStringTokenizer   ostk1;
  wxString            os1, os2;
  size_t              szColWd=0;
  size_t              sz1;

  // This function requires the result file to have been opened
  if( ! m_oFileResults.IsOpened( ) ) return( false );

  // Determine the width of the largest field in the results file
  // First check the column label widths
  ostk1.SetString( m_oFileResults.GetFirstLine( ) );  // Get the column header line
  while( ostk1.HasMoreTokens( ) )
  {
    os1 = ostk1.GetNextToken( );
    sz1 = os1.Length( );
    if( os1[ 0 ] == wxT('#') ) sz1--;  // Ignore the comment specifier character ie. a leading '#'
    if( sz1 > szColWd ) szColWd = sz1;
  }

  // Now check the data field widths
  ostk1.SetString( m_oFileResults.GetNextLine( ) );   // Get the first line of data
  while( ostk1.HasMoreTokens( ) )
  {
    os1 = ostk1.GetNextToken( );
    sz1 = os1.Length( );
    if( os1[ 0 ] == wxT('-') ) sz1--;  // Ignore minus signs because they are not alway present
    if( sz1 > szColWd ) szColWd = sz1;
  }

  // The total column width is made up of the column label and 2 space characters OR the data field
  // and a sign character and 1 space character
  szColWd += 2;

  // Pad the column labels so the columns are spaced evenly and everything lines up
  ostk1.SetString( m_oFileResults.GetFirstLine( ) );  // Get the column header line
  os1.Empty( );
  while( ostk1.HasMoreTokens( ) )
  {
    os1 << ostk1.GetNextToken( );
    if( ! ostk1.HasMoreTokens( ) ) break;             // The last token has been processed
    sz1 = szColWd - (os1.Length( ) % szColWd);
    os1.Append( wxT(' '), sz1+1 );
  }
  m_oFileResults[ m_oFileResults.GetCurrentLine( ) ] = os1;

  // Pad the data fields so the columns are spaced evenly and everything lines up
  for( os1=m_oFileResults.GetNextLine(); !m_oFileResults.Eof(); os1=m_oFileResults.GetNextLine() )
  {
    ostk1.SetString( os1 );

    os1.Empty( );
    while( ostk1.HasMoreTokens( ) )
    {
      os2 = ostk1.GetNextToken( );
      if( os2[ 0 ] != wxT('-') ) os1 << wxT(' ');     // Make allowance for a leading sign character
      os1 << os2;
      if( ! ostk1.HasMoreTokens( ) ) break;           // The last token has been processed
      sz1 = szColWd - (os1.Length( ) % szColWd);
      os1.Append( wxT(' '), sz1 );
    }

    m_oFileResults[ m_oFileResults.GetCurrentLine( ) ] = os1;
  }

  return( true );
}

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

void  PrcSimEngBase::Print( const wxString & rosPrefix )
{
  bool      bIsOpen;
  wxString  os1;

  PrcBase::Print( rosPrefix + wxT("PrcBase::") );

  std::cout << rosPrefix.mb_str( ) << "m_eSimEng      : ";
  switch( m_eSimEng )
  {
    case eSIMR_GNUCAP  : std::cout << "eSIMR_GNUCAP"  ; break;  // GNU-Cap
    case eSIMR_NGSPICE : std::cout << "eSIMR_NGSPICE" ; break;  // NG-Spice
    default            : std::cout << "eSIMR_NONE";
  }
  std::cout << '\n';

  std::cout << rosPrefix.mb_str( ) << "m_oNameResults : " << m_oNameResults.GetFullPath( ).mb_str( ) << '\n';

  std::cout << rosPrefix.mb_str( ) << "m_oFileResults :";

  bIsOpen = m_oFileResults.IsOpened( );
  if( ! bIsOpen )
#if wxCHECK_VERSION( 3,0,0 )
    if( m_oNameResults.Exists( ) )
#else
    if( m_oNameResults.FileExists( ) )
#endif
      m_oFileResults.Open( m_oNameResults.GetFullPath( ) );

  if( m_oFileResults.IsOpened( ) )
  {
    if( m_oFileResults.GetLineCount( ) > 0 )
    {
      std::cout << '\n';
      for( os1=m_oFileResults.GetFirstLine(); !m_oFileResults.Eof(); os1=m_oFileResults.GetNextLine() )
        std::cout << rosPrefix.mb_str( ) << "  " << os1.mb_str( ) << '\n';
    }
    else std::cout << " Is empty\n";
  }
  else std::cout << " Doesn't exist\n";

  if( ! bIsOpen )
    if( m_oFileResults.IsOpened( ) )
      m_oFileResults.Close( );
}

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