//**************************************************************************************************
//                                         FileTasks.cpp                                           *
//                                        ---------------                                          *
// Started     : 2005-05-28                                                                        *
// Last Update : 2018-10-28                                                                        *
// 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 "FileTasks.hpp"
#include "FrmMain.hpp"

//**************************************************************************************************
// Constructor.
//
// Argument List :
//   poFrmMain - A pointer to the parent frame

FileTasks::FileTasks( FrmMain * poFrmMain ) : m_oPrc_gnetlist( )
{
  // Set the pointer to the parent frame
  m_poFrmMain = poFrmMain;
}

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

FileTasks::~FileTasks( )
{
}

//**************************************************************************************************
// Execute the schematic import process.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bExecImport( void )
{
  bool       bRtn;
  TextCtrl * poTxtCtl;

  // Display the console page
  m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_CONSOLE );

  // Convert the schematic file/s to a netlist file
  bRtn = m_oPrc_gnetlist.bExec( );

  // Print the results
  poTxtCtl = m_poFrmMain->m_oNbkTxtCtls.poGetPage( );
  m_oPrc_gnetlist.PrintIO( *poTxtCtl );

  // Check for errors in the gnetlist output
  if( poTxtCtl->GetValue( ).Contains( wxT("ERROR") )     ) bRtn = false;
  if( poTxtCtl->GetValue( ).Contains( wxT("Backtrace") ) ) bRtn = false;

  // Delete the process log file
  m_oPrc_gnetlist.bDelLogFile( );

  return( bRtn );
}

//**************************************************************************************************
// Initialize the Guile procedure name to be used by gnetlist when importing schematic files.

void  FileTasks::InitGuileProc( void )
{
  // Get the Guile procedure name
  const wxString & ros1 = g_oConfig.rosGetGuileProc( );
  if( ros1.IsEmpty( ) ) return;

  // Set the Guile procedure name
  bSetGuileProc( ros1 );
}

//**************************************************************************************************
// Initialize the schematic file name/s.

void  FileTasks::InitSchemFiles( void )
{
  // Get the schematic file name/s
  const wxArrayString & roas1 = g_oConfig.roasGetSchemFiles( );
  if( roas1.IsEmpty( ) )          return;

  // Set the schematic file name/s
  if( ! bSetSchemFiles( roas1 ) ) return;

  // Return if a netlist file has also been specified
  const wxString & ros1 = g_oConfig.rosGetNetLstFile( );
  if( ! ros1.IsEmpty( ) )         return;

  // Import the schematic file/s
  bImport( );
}

//**************************************************************************************************
// Initialize the netlist file name.

void  FileTasks::InitNetLstFile( void )
{
  // Return if a netlist file has already been loaded
  if( ! m_poFrmMain->m_oNetLst.bIsEmpty( ) ) return;

  // Get the netlist file name
  const wxString & ros1 = g_oConfig.rosGetNetLstFile( );
  if( ros1.IsEmpty( ) )                      return;

  // Set the netlist file name
    if( ! bSetNetLstFile( ros1 ) )           return;

  // Open the netlist file
  bOpen( );

  // Does the netlist file contain simulator specific information?
  if(      m_poFrmMain->m_oSimnNgSp.m_oCmdPR.bIsValid( ) )
  {
    g_oConfig.bSetSimEng( eSIMR_NGSPICE );
    g_oConfig.bFlush( );
    m_poFrmMain->m_oSimnGCap = m_poFrmMain->m_oSimnNgSp;
  }
  else if( m_poFrmMain->m_oSimnGCap.m_oCmdPR.bIsValid( ) )
  {
    g_oConfig.bSetSimEng( eSIMR_GNUCAP );
    g_oConfig.bFlush( );
    m_poFrmMain->m_oSimnNgSp = m_poFrmMain->m_oSimnGCap;
  }
}

//**************************************************************************************************
// Display a error message dialog when schematic file/s can't be imported.

void  FileTasks::DlgErrSchems( void )
{
  wxString  os1, os2, os3;
  size_t    sz1;

  for( sz1=0; sz1<m_oPrc_gnetlist.roaGetSchemFiles( ).GetCount( ); sz1++ )
    os2 << wxT("     ") << m_oPrc_gnetlist.roGetSchemFile( sz1 ).GetFullPath( ) << wxT("\n");

  if( sz1 > 1 ) os3 = wxT("s were");
  else          os3 = wxT(" was");

  os1 << wxT("The schematic file") << os3 << wxT("n't converted to a netlist correctly :\n")
      << wxT("\n")
      << os2
      << wxT("\n")
      << wxT("This is usually because gnetlist encountered problem/s\n")
      << wxT("while attempting to convert the schematic file/s to a netlist.  \n")
      << wxT("Try examining the Console output to determine where the\n")
      << wxT("problem/s occurred.\n");

  m_poFrmMain->DlgErrMsg( wxT("Import Schematic/s Error"), os1 );
}

//**************************************************************************************************
// Display a error message dialog when a netlist file can't be loaded.

void  FileTasks::DlgErrNetLst( void )
{
  wxString  os1;

  os1 << wxT("The netlist file wasn't loaded correctly :\n")
      << wxT("\n")
      << wxT("     ") << m_oPrc_gnetlist.roGetNetLstFile( ).GetFullPath( ) << wxT("\n")
      << wxT("\n")
      << wxT("This is often because the file is in-complete, empty or  \n")
      << wxT("doesn't exist.\n");

  m_poFrmMain->DlgErrMsg( wxT("Netlist File Error"), os1 );
}

//**************************************************************************************************
// Do initialization tasks.

void  FileTasks::Initialize( void )
{
  InitGuileProc ( );
  InitSchemFiles( );
  InitNetLstFile( );
}

//**************************************************************************************************
// Check that the gnetlist binary can be found, if not display an error message.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bIsOk_gnetlist( void )
{
  wxString  os1;

  // Check that gnetlist exists and is accessible
  if( ! m_oPrc_gnetlist.bBinExists( ) )
  {
    if( m_poFrmMain != NULL )
    {
      os1 << wxT("Can't find the binary \"") << m_oPrc_gnetlist.roGetBinFile( ).GetFullName( )
                                                                    << wxT("\" which is required\n")
          << wxT("to import schematic file/s. The path is unknown   \n")
          << wxT("or gnetlist hasn't been installed.\n");

      m_poFrmMain->DlgErrMsg( wxT("gnetlist Error"), os1 );
    }
    return( false );
  }

  return( true );
}

//**************************************************************************************************
// Set the application main frame title.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bSetTitle( void )
{
  wxFileName  ofn1;
  wxString    os1;

  if( m_poFrmMain == NULL ) return( false );

  // Create the title line
  os1 << wxT(" ") << APP_NAME;
  if( ! rosGetNetLstFile( ).IsEmpty( ) )
  {
    ofn1 = rosGetNetLstFile( );
    if( ! ofn1.IsAbsolute( ) ) ofn1.MakeAbsolute( );
    if( ofn1.GetFullPath( ).StartsWith( ofn1.GetHomeDir( ) ) )
      ofn1.MakeRelativeTo( ofn1.GetHomeDir( ) );

    os1 << wxT("  -  ");
    if( ! ofn1.IsAbsolute( ) ) os1 << wxT("~/");
    os1 << ofn1.GetFullPath( );
  }

  // Set the main frames title line
  m_poFrmMain->wxFrame::SetTitle( os1 );

  return( true );
}

//**************************************************************************************************
// Set a Guile procedure name to be used for importing schematic files using gNetList.
//
// Argument List :
//   rosProcName - The Guile procedure name
//                 (Refer to gNetList documentation for list of procedure names)

bool  FileTasks::bSetGuileProc( const wxString & rosProcName )
{
  if( ! m_oPrc_gnetlist.bSetGuileProc( rosProcName ) ) return( false );

  // Record the Guile procedure name currently selected
  g_oConfig.bSetGuileProc( rosGetGuileProc( ) );

  // Write any changes to the configuration file
  g_oConfig.bFlush( );

  return( true );
}

//**************************************************************************************************
// Set the schematic file name/s.
//
// Argument List :
//   roasFileNames - A string containing the full path and file name/s
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bSetSchemFiles( const wxString & rosFileNames )
{
  wxStringTokenizer  ostk1;
  wxArrayString      osa1;

  ostk1.SetString( rosFileNames );
  while( ostk1.HasMoreTokens( ) )
    osa1.Add( ostk1.GetNextToken( ) );

  return( bSetSchemFiles( osa1 ) );
}

//**************************************************************************************************
// Set the schematic file name/s.
//
// Argument List :
//   roasFileNames - A string array containing the full path and file name/s
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bSetSchemFiles( const wxArrayString & roasFileNames )
{
  wxArrayString  oas1;
  wxString       os1;

  if( roasFileNames.IsEmpty( ) )
  {
    // Clear the schematic file name/s in the configuration object
    oas1.Empty( );
    g_oConfig.bSetSchemFiles( oas1 );
    g_oConfig.bFlush( );
  }

  // Attempt to set the schematic file name/s in the gnetlist process object
  if( ! m_oPrc_gnetlist.bSetSchemFiles( roasFileNames ) ) return( false );

  // Set the schematic file name/s
  if( m_poFrmMain != NULL ) m_poFrmMain->m_oNetLst.bSetSchemFiles( roasFileNames );

  // Record the schematic file name/s in the configuration object
  g_oConfig.bSetSchemFiles( rosaGetSchemFiles( ) );
  g_oConfig.bFlush( );

  return( true );
}

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

bool  FileTasks::bSetNetLstFile( const wxString & rosFileName )
{
  wxString  os1;

  if( rosFileName.IsEmpty( ) )
  {
    // Clear the netlist file name in the configuration object
    g_oConfig.bSetNetLstFile( wxEmptyString );
    g_oConfig.bFlush( );
  }

  // Attempt to set the netlist file name in the gNetList process object
  if( ! m_oPrc_gnetlist.bSetNetLstFile( rosFileName ) ) return( false );

  // Configure stuff in the main frame
  if( m_poFrmMain != NULL )
  {
    m_poFrmMain->m_oNetLst.bSetLoadFile( rosFileName );  // Set load file path
    m_poFrmMain->m_oNetLst.bSetSaveFile( rosFileName );  // Set save file path
  }

  // Record the netlist file name in the configuration object
  os1 = rosGetNetLstFile( );
  g_oConfig.bSetNetLstFile( os1 );
  g_oConfig.bFlush( );

  return( true );
}

//**************************************************************************************************
// Get the currently selected Guile procedure.
//
// Return Values :
//   The currently selected Guile procedure

const wxString & FileTasks::rosGetGuileProc( void )
{
  return( m_oPrc_gnetlist.rosGetGuileProc( ) );
}

//**************************************************************************************************
// Get an array containing the schematic file name/s.
//
// Return Values :
//   An array of schematic file names

const wxArrayString & FileTasks::rosaGetSchemFiles( void )
{
  static  wxArrayString  osa1;
  wxString  os1;
  size_t    szt1;

  osa1.Clear( );

  for( szt1=0; szt1<m_oPrc_gnetlist.roaGetSchemFiles( ).GetCount( ); szt1++ )
  {
    os1 = m_oPrc_gnetlist.roGetSchemFile( szt1 ).GetFullPath( );
    if( ! os1.IsEmpty( ) ) osa1.Add( os1 );
  }

  return( osa1 );
}

//**************************************************************************************************
// Get the netlist file name.
//
// Return Values :
//   The netlist file name

const wxString & FileTasks::rosGetNetLstFile( void )
{
  static  wxString  osNetLstFile;

  osNetLstFile = m_oPrc_gnetlist.roGetNetLstFile( ).GetFullPath( );

  return( osNetLstFile );
}

//**************************************************************************************************
// Get the log file name.
//
// Return Values :
//   The log file name

const wxString & FileTasks::rosGetLogFile( void )
{
  static  wxString  osLogFile;

  osLogFile = m_oPrc_gnetlist.roGetLogFile( ).GetFullPath( );

  return( osLogFile );
}

//**************************************************************************************************
// Display an open file dialog and set the netlist file name.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bDlgOpen( void )
{
  wxFileDialog * poDlgOpen;
  wxString       os1, os2;
  long           li1;

  // Can't display dialogue unless the application main frame has been created
  if( m_poFrmMain == NULL )                return( false );

  // Create the different file filters
  os1 << wxT("All files (*)|*|")
      << wxT("Circuit files (*.ckt)|*.ckt|")
      << wxT("Circuit files (*.cir)|*.cir|")
      << wxT("Netlist files (*.net)|*.net");

  // Get the file path from the global configuration object
  os2 = g_oConfig.rosGetDirLastAcc( );

  // Set the style bit pattern
#if wxCHECK_VERSION( 2,8,0 )
  li1 = wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_FILE_MUST_EXIST;
#else
  li1 = wxOPEN | wxCHANGE_DIR | wxFILE_MUST_EXIST;
#endif

  // Create and configure the file open dialog
  poDlgOpen = new wxFileDialog( m_poFrmMain, wxT(""), wxT(""), wxT(""), wxT(""), li1 );
  poDlgOpen->SetMessage( wxT("Open a Circuit Description File") );
  poDlgOpen->SetWildcard( os1 );
  poDlgOpen->SetFilterIndex( 1 );
  poDlgOpen->SetDirectory( os2 );

  // Display file open dialog
  if( poDlgOpen->ShowModal( ) != wxID_OK ) return( false );

  // Delete temporary files
  bDelTmpFiles( );

  // Set the netlist file name
  os1 = poDlgOpen->GetPath( );
  if( ! bSetNetLstFile( os1 ) )            return( false );

  // Set the path last accessed in the global configuration object
  g_oConfig.bSetDirLastAcc( poDlgOpen->GetDirectory( ) );

  // Write any changes to the configuration file
  g_oConfig.bFlush( );

  return( true );
}

//**************************************************************************************************
// Display an import file/s dialog and set the schematic file name/s.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bDlgImport( void )
{
  wxFileDialog * poDlgImport;
  wxArrayString  oas1;
  wxString       os1, os2;
  long           li1;

  // Can't display dialogue unless the application main frame has been created
  if( m_poFrmMain == NULL )                  return( false );

  // Create the different file filters
  os1 << wxT("gSchem files (*.sch)|*.sch|")
      << wxT("Protel II files (*.\?\?\?)|*.\?\?\?");

  // Get the file path from the global configuration object
  os2 = g_oConfig.rosGetDirLastAcc( );

  // Set the style bit pattern
#if wxCHECK_VERSION( 2,8,0 )
  li1 = wxFD_OPEN | wxFD_CHANGE_DIR | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST;
#else
  li1 = wxOPEN | wxCHANGE_DIR | wxMULTIPLE | wxFILE_MUST_EXIST;
#endif

  // Create and configure the file import dialog
  poDlgImport = new wxFileDialog( m_poFrmMain, wxT(""), wxT(""), wxT(""), wxT(""), li1 );
  poDlgImport->SetMessage( wxT("Import a Schematic File/s") );
  poDlgImport->SetWildcard( os1 );
  poDlgImport->SetFilterIndex( 0 );
  poDlgImport->SetDirectory( os2 );

  // Display file import dialog
  if( poDlgImport->ShowModal( ) != wxID_OK ) return( false );

  // Delete temporary files
  bDelTmpFiles( );

  // Set the schematic file name/s
  poDlgImport->GetPaths( oas1 );
  if( ! bSetSchemFiles( oas1 ) )             return( false );

  // Set the netlist file name (derive it from the schematic file name)
  bSetNetLstFile( );

  // Set the path last accessed in the global configuration object
  g_oConfig.bSetDirLastAcc( poDlgImport->GetDirectory( ) );

  // Write any changes to the configuration file
  g_oConfig.bFlush( );

  return( true );
}

//**************************************************************************************************
// Delete temporary files which may have been generated by this application.
//
// Eg. given the circuit description file "test-cct.sch" delete files of the form :
//       test-cct.ckt
//       test-cct.sch~
//       gspiceui.log
//       test-cct.ngspice.dc, test-cct.ngspice.ac, ... etc.
//       test-cct.gnucap.op,  test-cct.gnucap.dc,  ... etc.

bool  FileTasks::bDelTmpFiles( void )
{
  eTypeTmpFileMgt  eTmpFileMgt;
  wxArrayString    osaDelFiles;       // A list of files to delete
  bool             bDelNetLst=false;  // Is the netlist file being deleted?
  wxFileName       ofn1;
  wxString         os1, os2;
  size_t           sz1;
  int              i1;

  // Check the current temporay file management strategy and return if nothing needs to be done
  eTmpFileMgt = g_oConfig.eGetTmpFileMgt( );
  if( eTmpFileMgt == eTFM_KEEP )         return( true );

  // Before looking for files to delete, get the path to the files
  const wxArrayString & roasSchems = rosaGetSchemFiles( );
  os1 = rosGetNetLstFile( );
  if(      ! os1.IsEmpty( )           ) ofn1.Assign( os1 );
  else if( roasSchems.GetCount( ) > 0 ) ofn1.Assign( roasSchems[ 0 ] );
  if( !ofn1.IsOk( ) || !ofn1.FileExists( ) ) return( false );

  // If there is a schematic file add the netlist file and the schematic backup file/s to the list
  // of files to be deleted
  if( roasSchems.GetCount( ) > 0 )
  {
    if( ! g_oConfig.bGetKeepNetLst( ) )
    {
      osaDelFiles.Add( ofn1.GetFullPath( ) );  // Add the netlist file to the delete list
      bDelNetLst = true;
    }

    for( sz1=0; sz1<roasSchems.GetCount( ); sz1++ )
    {
      os1 = roasSchems[ sz1 ] + wxT('~');
      if( wxFileExists( os1 ) )
        osaDelFiles.Add( os1 );                // Add a schematic backup file to delete list
    }
  }

  // Look for the gspiceui log file and add it to the files to be deleted
  os1 = rosGetLogFile( );
  if( wxFileExists( os1 ) ) osaDelFiles.Add( os1 );

  // Now look for simulation results files
  ofn1.ClearExt( );

  // Look for any NG-Spice results files and add them to the delete list
  os1 = ofn1.GetFullPath( ) + wxT(".ngspice.??");
  for( os2=wxFindFirstFile( os1 ); !os2.IsEmpty( ); os2=wxFindNextFile( ) )
    osaDelFiles.Add( os2 );

  // Look for any GNU-Cap results files and add them to the delete list
  os1 = ofn1.GetFullPath( ) + wxT(".gnucap.??");
  for( os2=wxFindFirstFile( os1 ); !os2.IsEmpty( ); os2=wxFindNextFile( ) )
    osaDelFiles.Add( os2 );

  // If necessary prompt the user for permission to delete temporary files
  if( osaDelFiles.GetCount( ) > 0 )
  {
    if( m_poFrmMain!=NULL && m_poFrmMain->IsShown( ) )
    {
      // Prompt the user
      if( eTmpFileMgt == eTFM_PROMPT )
      {
        os1 = wxT("Delete Temporary Files");
        os2 = wxT("\nDelete the following temporary files :\n\n");
        for( i1=0; i1<(int)osaDelFiles.GetCount( ); i1++ )
          os2 << wxT("     ") << osaDelFiles[ i1 ] << wxT("   \n");
        i1 = wxMessageBox( os2, os1, wxYES_NO|wxICON_QUESTION, m_poFrmMain );
      }
      else i1 = wxYES;

      // Delete the temporary files
      if( i1 == wxYES )
      {
        for( i1=0; i1<(int)osaDelFiles.GetCount( ); i1++ )
          wxRemoveFile( osaDelFiles[ i1 ] );

        if( bDelNetLst )
        {
          g_oConfig.bSetNetLstFile( wxEmptyString );
          g_oConfig.bFlush( );
        }
      }
    }
  }

  return( true );
}

//**************************************************************************************************
// Open and load a circuit description (netlist) file into the simulation objects of m_poFrmMain.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bOpen( void )
{
  bool  bRtn=true;

  // Attempt to load the circuit description file
  NetList::bLoadFile( );

  // Load circuit description (& simulation) information into the attributes of the class hierarchy
  if(      m_poFrmMain->m_oSimnNgSp.bLoad( ) ) m_poFrmMain->m_oSimnGCap = m_poFrmMain->m_oSimnNgSp;
  else if( m_poFrmMain->m_oSimnGCap.bLoad( ) ) m_poFrmMain->m_oSimnNgSp = m_poFrmMain->m_oSimnGCap;

  // Check for problems
  if( ! m_poFrmMain->m_oNetLst.bIsValid( ) )
  {
    DlgErrNetLst( );
    m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_NETLIST );
    bRtn = false;
  }
  else
    m_poFrmMain->SetStatusText( wxT(" Netlist file opened successfully"), FrmMain::ePANE_MESAGE );

  // Set the schematic file name/s if supplied
  const wxArrayString & roas1 = m_poFrmMain->m_oNetLst.roasGetSchemFiles( );
  if( ! roas1.IsEmpty( ) ) bSetSchemFiles( roas1 );

  // Set the main frame title
  bSetTitle( );

  return( bRtn );
}

//**************************************************************************************************
// Import a schematic file by converting it to a netlist using gnetlist and then loading it into the
// FrmMain simulation object.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bImport( void )
{
  bool  bRtn=true;

  // Check that gnetlist binary exists and is accessible
  if( ! bIsOk_gnetlist( ) ) return( false );

  // Convert the schematic file/s to a netlist file and load it
  if( bExecImport( ) )
  {
    bSetNetLstFile( m_oPrc_gnetlist.roGetNetLstFile( ).GetFullPath( ) );

    // Attempt to load the circuit description file
    NetList::bLoadFile( );

    // Load circuit description (& simulation) info. into the attributes of the class hierarchy
    m_poFrmMain->m_oSimnNgSp.bLoad( );
    m_poFrmMain->m_oSimnGCap.bLoad( );

    if( m_poFrmMain->m_oNetLst.bIsValid( ) )
      m_poFrmMain->SetStatusText( wxT(" Schematic file/s imported successfully"),
                                  FrmMain::ePANE_MESAGE );
    else
    {
      DlgErrNetLst( );
      if( ! m_poFrmMain->m_oNbkTxtCtls.poGetPage( NbkTxtCtls::ePAGE_NETLIST )->bIsEmpty( ) )
           m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_NETLIST );
      else m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_CONSOLE );
      bRtn = false;
    }
  }
  else
  {
    DlgErrSchems( );
    m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_CONSOLE );
    m_poFrmMain->m_oNbkTxtCtls.bSetPosn( -1 );
    bRtn = false;
  }

  // Set the main frame title
  bSetTitle( );

  return( bRtn );
}

//**************************************************************************************************
// Reload a simulation object whether it be from a schematic or netlist file.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bReload( void )
{
  bool  bRtn;

  // Re-initialize the text control notebook
  m_poFrmMain->m_oNbkTxtCtls.bInitialize( );

  // Attempt to perform the reload operation
  if( ! m_oPrc_gnetlist.roaGetSchemFiles( ).IsEmpty( ) )
  { // Reload schematic file/s
    bRtn = bImport( );
    if( bRtn ) m_poFrmMain->SetStatusText( wxT(" Schematic file/s re-imported successfully"),
                                           FrmMain::ePANE_MESAGE );
  }
  else if( m_oPrc_gnetlist.roGetNetLstFile( ).IsOk( ) )
  { // Reload a netlist file
    bRtn = bOpen( );
    if( bRtn ) m_poFrmMain->SetStatusText( wxT(" Netlist file reloaded successfully"),
                                           FrmMain::ePANE_MESAGE );
  }
  else
  { // There's no open schematic or netlist to reload, display an error message
    m_poFrmMain->DlgErrMsg( wxT("Reload Operation Error"), wxT("No file is currently open.") );
    bRtn = false;
  }

  return( bRtn );
}

//**************************************************************************************************
// Close the circuit description file.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bClose( void )
{
  // Is there a file currently open?
  if( m_oPrc_gnetlist.roaGetSchemFiles( ).IsEmpty() && ! m_oPrc_gnetlist.roGetNetLstFile( ).IsOk() )
  {
    // There's no open schematic or netlist to close, display an error message
    m_poFrmMain->DlgErrMsg( wxT("Close Operation Error"), wxT("No file is currently open.") );
    return( false );
  }

  // Delete temporary files
  bDelTmpFiles( );

  // Clear file names
  m_oPrc_gnetlist.bClear( );
  bSetNetLstFile( wxT("") );
  bSetSchemFiles( wxT("") );

  // Set the status bar message
  m_poFrmMain->SetStatusText( wxT(" Netlist file closed successfully"), FrmMain::ePANE_MESAGE );

  // Set the text control notebook page
  m_poFrmMain->m_oNbkTxtCtls.bSetPage( NbkTxtCtls::ePAGE_CONSOLE );

  return( true );
}

//**************************************************************************************************
// Do the necessary tasks before the application exits.
//
// Return Values :
//   true  - Success
//   false - Failure

bool  FileTasks::bExit( void )
{
  // Delete temporary file/s
  if( ! bDelTmpFiles( ) ) return( false );

  return( true );
}

//**************************************************************************************************
// Compare the modification times of the schematic file/s and the netlist file. If the schematic
// file/s are newer than the netlist a reload operation is required (ie. generate a new netlist file
// from the schematic file/s).
//
// Return Values :
//   true  - A reload operation is    required
//   false - A reload operation isn't required

bool  FileTasks::bReloadReqd( void )
{
  wxDateTime     oModSchems;
  wxDateTime     oModNetLst;
  wxDateTime     oDtTm1;
  wxFileName     ofn1;
  wxArrayString  osa1;
  wxString       os1;
  size_t         sz1;
  bool           bRtn;

  // Initialize the file modification time objects
  oModSchems = wxInvalidDateTime;
  oModNetLst = wxInvalidDateTime;

  // Determine the lastest modification time for the schematic file/s
  osa1 = rosaGetSchemFiles( );
  if( ! osa1.IsEmpty( ) )
  {
    for( sz1=0; sz1<osa1.GetCount( ); sz1++ )
    {
      ofn1 = osa1.Item( sz1 );
      oDtTm1 = ofn1.GetModificationTime( );
      if(    ! oModSchems.IsValid( )              ) oModSchems = oDtTm1;
      else if( oModSchems.IsEarlierThan( oDtTm1 ) ) oModSchems = oDtTm1;
    }
  }

  // Determine the modification time for the netlist file
  os1 = rosGetNetLstFile( );
  if( ! os1.IsEmpty( ) )
  {
    ofn1 = os1;
    oModNetLst = ofn1.GetModificationTime( );
  }

  // Compare the modification times and set the function return value
  bRtn = false;
  if( oModSchems.IsValid( ) && oModNetLst.IsValid( ) )
    if( oModNetLst.IsEarlierThan( oModSchems ) )
      bRtn = true;

  return( bRtn );
}

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