/* -*- C++ -*-
 
  This file is part of ViPEC
  Copyright (C) 1991-2001 Johan Rossouw (jrossouw@alcatel.altech.co.za)
 
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU Library General Public License as
  published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU Library General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
*/

#include <MainWindow.h>

#include <Types.h>
#include <Utils.h>
#include <Strings.h>
#include <Setup.h>
#include <ToolBar.h>
#include <Exception.h>
#include <SymbolBar.h>
#include <HelpWindow.h>
#include <TunerWindow.h>
#include <GraphDefinition.h>
#include <GridDefinition.h>
#include <SmithDefinition.h>
#include <TableDefinition.h>
#include <SchematicFrame.h>
#include <NewGraphWindow.h>
#include <SchematicWindow.h>
#include <NavigationWindow.h>
#include <MicroStripCalcWindow.h>
#include <SubstrateWindow.h>

#include "images/logo.xpm"
#include "images/vipec.xpm"

#include <qdom.h>
#include <qapplication.h>
#include <qsplitter.h>
#include <qmenubar.h>
#include <qpopupmenu.h>
#include <qtoolbar.h>
#include <qpixmap.h>
#include <qtoolbutton.h>
#include <qmessagebox.h>
#include <qfiledialog.h>
#include <qinputdialog.h>
#include <qtextstream.h>
#include <qstatusbar.h>
#include <qstringlist.h>
#include <qregexp.h>

#include <iostream>

using namespace std;

const char* version = "3.2.0";

MainWindow* MainWindow::instance_ = 0;
long int MainWindow::uniqueID_ = 0;

//-----------------------------------------------------------------
MainWindow* MainWindow::instance()
{
  if (instance_ == 0)
    {
      new MainWindow();
    }
  return instance_;
}

//-----------------------------------------------------------------
long int MainWindow::getUniqueID()
{
  return uniqueID_++;
}

//-----------------------------------------------------------------
MainWindow::MainWindow()
    : QMainWindow( 0, tr( Strings::MainWindowTitle) ),
    filename_( Strings::EmptyFileName ),
    fileChanged_( FALSE ),
    helpWindow_( 0 ),
    translator_( 0 )
{
  instance_ = this;

  setIcon( QPixmap( vipec_xpm ) );

  createApplicationMenus();
  createMainToolbar();
  createSymbolToolbar();

  QSplitter* splitter = new QSplitter( QSplitter::Horizontal, this , "main" );

  new SchematicWindow( splitter );
  NavigationWindow* navigWindow = new NavigationWindow( splitter );

  navigWindow->setMinimumSize( 50, 0 );
  splitter->setResizeMode( navigWindow, QSplitter::KeepSize );
  splitter->moveToFirst( navigWindow );
  setCentralWidget( splitter );

  graphs_.setAutoDelete( TRUE );

  statusBar()->message( tr( Strings::StatusMessageReady ) , 2000 );
}

//-----------------------------------------------------------------
MainWindow::~MainWindow()
{
  instance_ = 0;
}

//-----------------------------------------------------------------
void MainWindow::closeEvent( QCloseEvent* e )
{
  e->ignore();
  quit();
}

//-----------------------------------------------------------------
void MainWindow::quit()
{
  if ( closeFile() )
    {
      qApp->quit();
    }
}

//-----------------------------------------------------------------
void MainWindow::createApplicationMenus()
{
  //Init menus
  QPopupMenu* file = new QPopupMenu();
  menuBar()->insertItem( Strings::translate(Strings::MenuLabelFile), file );

  file->insertItem( Strings::translate(Strings::MenuLabelOpen), this, SLOT( loadSlot() ) );
  file->insertItem( Strings::translate(Strings::MenuLabelSave), this, SLOT( saveSlot() ) );
  file->insertItem( Strings::translate(Strings::MenuLabelSaveAs), this, SLOT( saveAsSlot() ) );
  file->insertItem( Strings::translate(Strings::MenuLabelClose), this, SLOT( closeSlot() ) );
  file->insertSeparator();
  file->insertItem( Strings::translate(Strings::MenuLabelNewSchematic), this, SLOT( newSchematicSlot() ) );
  file->insertSeparator();
  file->insertItem( Strings::translate(Strings::MenuLabelPrint), this, SLOT( printSlot() ) );
  file->insertSeparator();
  file->insertItem( Strings::translate(Strings::MenuLabelQuit), this, SLOT( quit() ) );

  QPopupMenu* tools = new QPopupMenu();
  menuBar()->insertItem( Strings::translate(Strings::MenuLabelTools), tools );
  tools->insertItem( Strings::translate(Strings::MenuLabelMicroStripCalc),
                     this, SLOT( microStripCalculator() ) );
  tools->insertItem( Strings::translate(Strings::MenuLabelTuner),
                     this, SLOT( tuner() ) );

  QPopupMenu* setup = new QPopupMenu();
  menuBar()->insertItem( Strings::translate(Strings::MenuLabelSetup), setup );
  setup->insertItem( Strings::translate(Strings::MenuLabelLanguage),
                     this, SLOT( setLanguage() ) );

  QPopupMenu *help = new QPopupMenu;
  help->insertItem( Strings::translate(Strings::MenuLabelIndex), this, SLOT( helpSlot() ), Key_F1 );
  help->insertSeparator();
  help->insertItem( Strings::translate(Strings::MenuLabelAbout), this, SLOT( aboutSlot() ) );
  help->insertItem( Strings::translate(Strings::MenuLabelAboutQt), this, SLOT( aboutQtSlot() ) );

  menuBar()->insertSeparator();
  menuBar()->insertItem( Strings::translate(Strings::MenuLabelHelp), help );
  menuBar()->setSeparator( QMenuBar::InWindowsStyle );

}

//-----------------------------------------------------------------
void MainWindow::createMainToolbar()
{
  ToolBar* toolBar = new ToolBar( Strings::ToolBarName, this );
  toolBar->initialize();
}

//-----------------------------------------------------------------
void MainWindow::createSymbolToolbar()
{
  SymbolBar* symbolBar = new SymbolBar( Strings::SymbolBarName, this );
  symbolBar->initialize();
}

//-----------------------------------------------------------------
void MainWindow::setFileChanged()
{
  fileChanged_ = TRUE;
}

//-----------------------------------------------------------------
const QString& MainWindow::getFilename() const
  {
    return filename_;
  }

//-----------------------------------------------------------------
void MainWindow::closeSlot()
{
  closeFile();
}

//-----------------------------------------------------------------
bool MainWindow::closeFile()
{
  if ( fileChanged_ )
    {
      bool ok = confirm( Strings::translate(Strings::MsgConfirmLooseChanges) );
      if ( !ok )
        {
          return FALSE;
        }
    }
  filename_ = Strings::EmptyFileName;
  SchematicFrame::instance()->setActiveSchematic( 0 );
  NavigationWindow::instance()->filenameChanged( filename_ );
  NavigationWindow::instance()->reset();
  schematicMap_.clear();
  variableMap_.clear();
  substrateMap_.clear();
  fileBlockMap_.clear();
  removeAllGraphs();
  if ( !tunerWindow_.isNull() )
    {
      delete tunerWindow_;
    }
  fileChanged_ = FALSE;
  return TRUE;
}

//-----------------------------------------------------------------
void MainWindow::loadSlot()
{
  if ( !closeFile())
    {
      return;
    }

  QString fileName = QFileDialog::getOpenFileName( QString::null,
                     Strings::translate(Strings::LabelFilenameFilter),
                     this );
  if ( fileName.isEmpty() )
    {
      return;
    }

  filename_ = fileName;

  NavigationWindow::instance()->filenameChanged( fileName );
  if ( !readFile() )
    {
      closeFile();
      filename_ = Strings::EmptyFileName;
      NavigationWindow::instance()->filenameChanged( fileName );
    }
  SchematicFrame::instance()->reDraw();
}

//-----------------------------------------------------------------
void MainWindow::saveSlot()
{
  if ( filename_ == Strings::EmptyFileName )
    {
      saveAsSlot();
      return;
    }
#ifdef WIN_DEMO
  QMessageBox::warning( this, Strings::LabelApplicationName,
                        "The save feature is disabled in the Windows demo",
                        Strings::translate(Strings::LabelOk),
                        0, 0, 0, 0);
#else

  writeFile();
#endif
}

//-----------------------------------------------------------------
void MainWindow::saveAsSlot()
{
  QString fileName = QFileDialog::getSaveFileName( QString::null ,
                     Strings::translate(Strings::LabelFilenameFilter),
                     this );
  if ( !fileName.isNull() )
    {
      filename_ = fileName;
      NavigationWindow::instance()->filenameChanged( fileName );
#ifdef WIN_DEMO

      QMessageBox::warning( this, Strings::LabelApplicationName,
                            "The save feature is disabled in the Windows demo",
                            Strings::translate(Strings::LabelOk),
                            0, 0, 0, 0);
#else

      writeFile();
#endif

    }
}

//-----------------------------------------------------------------
void MainWindow::writeFile()
{
  QFile file( filename_ );
  file.remove();

  if ( !file.open( IO_WriteOnly ) )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgCouldNotWriteFile),
                            Strings::translate(Strings::LabelOk),
                            0, 0, 0, 0);
      return;
    }

  QString docStr;
  QTextStream filestream( &file );
  QTextStream stream( docStr, IO_WriteOnly );

  stream << "<!DOCTYPE VIPEC_CIRCUIT_FILE ><FILE CREATOR=\"ViPEC\" ";
  stream << "VERSION=\"" << version << "\">" << endl;

  //Save all circuits
  SchematicMap::Iterator it;
  for( it = schematicMap_.begin(); it != schematicMap_.end(); ++it )
    {
      stream << "<CIRCUIT NAME=\"" << it.key() << "\"";
      Schematic::SchematicSize size = it.data().getSize();
      stream << "SIZE=\"" << size << "\">\n";
      it.data().writeToStream( stream );
      stream << "</CIRCUIT>" << endl;
    }

  //Save variables
  if ( variableMap_.count() > 0 )
    {
      stream << "<VARIABLES>" << endl;
      VariableMap::Iterator it;
      for( it = variableMap_.begin(); it != variableMap_.end(); ++it )
        {
          stream << "<VAR NAME=\"" << it.key() << "\" ";
          stream << "VALUE=\"" << it.data() << "\" />" << endl;
        }
      stream << "</VARIABLES>" << endl;
    }

  //Save dimension settings
  stream << "<DIMENSIONS>" << endl;
  DimensionMap& map =  Setup::instance()->getDimensionMap();
  DimensionMap::Iterator it2;
  for( it2 = map.begin(); it2 != map.end(); ++it2 )
    {
      const QString& entry = it2.key();
      const QString& value = it2.data().getActiveValueName();
      stream << "<DIM NAME=\"" << entry << "\" ";
      stream << " VALUE=\"" << value << "\"/>" << endl;
    }
  stream << "</DIMENSIONS>" << endl;

  //Save sweep settings
  Setup* setup = Setup::instance();
  stream << "<SWEEP START=\"";
  stream << setup->getStartFrequency() << "\" STOP=\"";
  stream << setup->getStopFrequency() << "\" POINTS=\"";
  stream << setup->getNumberOfFrequencyPoints() << "\" LINEAR=\"";
  stream << (int) setup->isLinearSweep() << "\" />" << endl;

  //Save graph settings
  stream << "<GRAPHDEFINITIONS>" << endl;
  GraphDefinition* definition = 0;
  for ( definition = graphs_.first(); definition != 0; definition = graphs_.next() )
    {
      definition->writeToStream( stream );
    }
  stream << "</GRAPHDEFINITIONS>" << endl;

  //Save substrate definitions
  stream << "<SUBSTRATES>" << endl;
  SubstrateMap::Iterator it3;
  for ( it3 = substrateMap_.begin(); it3 != substrateMap_.end(); ++it3 )
    {
      it3.data().writeToStream( it3.key(), stream );
    }
  stream << "</SUBSTRATES>" << endl;

  //Save file blocks
  stream << "<FILEBLOCKS>" << endl;
  FileBlockMap::Iterator it4;
  for ( it4 = fileBlockMap_.begin(); it4 != fileBlockMap_.end(); ++it4 )
    {
      stream << "<BLOCK NAME=\"";
      stream << it4.data().filename() << "\" />" << endl;
    }
  stream << "</FILEBLOCKS>" << endl;

  stream << "</FILE>" << endl;


  //Use QDomDocument to format output nicely
  QDomDocument doc( "temp" );
  doc.setContent( docStr );
  QString tempStr = doc.toString();

  //Fix for Qt bug under Windows
  if ( tempStr.find("VIPEC_CIRCUIT_FILE") < 0 )
    {
      tempStr.replace( QRegExp("DOCTYPE"), "DOCTYPE VIPEC_CIRCUIT_FILE" );
    }

  filestream << tempStr;

  file.flush();
  file.close();
  statusBar()->message( Strings::translate(Strings::StatusMessageFileSaved), 2000 );

  fileChanged_ = FALSE;

}

//-----------------------------------------------------------------
bool MainWindow::readFile()
{
  QFile file( filename_ );

  if ( !file.open( IO_ReadOnly ) )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgCouldNotOpenFile),
                            Strings::translate(Strings::LabelOk),
                            0, 0, 0, 0);
      return FALSE;
    }

  QFileInfo fileInfo( file );
  QDomDocument doc( fileInfo.baseName() );

  if ( !doc.setContent( &file ) )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgCouldNotOpenFile),
                            Strings::translate(Strings::LabelOk),
                            0, 0, 0, 0);
      file.close();
      return FALSE;
    }

  file.close();

  QDomElement docElement = doc.documentElement();
  QDomNode docNode = docElement.firstChild();

  while ( !docNode.isNull() )
    {
      QDomElement element = docNode.toElement();
      if ( !element.isNull() )
        {
          QString tagName = element.tagName();
          if ( tagName == "CIRCUIT" )
            {
              QString circuitName = element.attribute( "NAME" );
              QString sizeStr = element.attribute( "SIZE" );
              Schematic::SchematicSize size = Schematic::mediumSize;
              if ( !sizeStr.isNull() )
                {
                  size = (Schematic::SchematicSize) (sizeStr.toInt());
                }
              Schematic& schematic = schematicMap_[circuitName];
              schematic.setName( circuitName );
              schematic.setSize( size );
              NavigationWindow::instance()->addSchematic( circuitName );
              bool success = schematic.readFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "VARIABLES" )
            {
              bool success = readVariablesFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "DIMENSIONS" )
            {
              bool success = readDimensionsFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "SWEEP" )
            {
              bool success = readSweepSettingsFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "GRAPHDEFINITIONS" )
            {
              bool success = readGraphDefinitionsFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "SUBSTRATES" )
            {
              bool success = readSubstrateDefinitionsFromDOM( element );
              if ( !success )
                return FALSE;
            }
          else if ( tagName == "FILEBLOCKS" )
            {
              bool success = readFileBlocksFromDOM( element );
              if ( !success )
                return FALSE;
            }
        }
      docNode = docNode.nextSibling();
    }


  statusBar()->message( Strings::translate(Strings::StatusMessageFileLoaded), 2000 );

  return TRUE;
}


//-----------------------------------------------------------------
bool MainWindow::readVariablesFromDOM( QDomElement& element )
{
  QDomNode node = element.firstChild();
  while( !node.isNull() )
    {
      QDomElement childElement = node.toElement();
      if( !childElement.isNull() )
        {
          if ( childElement.tagName() == "VAR" )
            {
              QString name = childElement.attribute( "NAME" );
              QString value = childElement.attribute( "VALUE" );
              variableMap_[name] = value;
              NavigationWindow::instance()->addVariable( name, value );
            }
          else
            {
              return FALSE;
            }
        }
      node = node.nextSibling();
    }
  return TRUE;
}

//-----------------------------------------------------------------
bool MainWindow::readDimensionsFromDOM( QDomElement& element )
{
  DimensionMap& map =  Setup::instance()->getDimensionMap();
  QDomNode node = element.firstChild();
  while( !node.isNull() )
    {
      QDomElement childElement = node.toElement();
      if( !childElement.isNull() )
        {
          if ( childElement.tagName() == "DIM" )
            {
              QString name = childElement.attribute( "NAME" );
              QString value = childElement.attribute( "VALUE" );
              map[name].setActiveValue( value );
              NavigationWindow::instance()->updateDimension( name, value );
            }
          else
            {
              return FALSE;
            }
        }
      node = node.nextSibling();
    }
  return TRUE;
}

//-----------------------------------------------------------------
bool MainWindow::readSweepSettingsFromDOM( QDomElement& element )
{
  QString linearStr = element.attribute( "LINEAR" );
  QString startStr = element.attribute( "START" );
  QString stopStr = element.attribute( "STOP" );
  QString pointsStr = element.attribute( "POINTS" );
  Setup* setup = Setup::instance();
  uint linear = (bool) linearStr.toInt();
  TReal start = startStr.toFloat();
  TReal stop = stopStr.toFloat();
  uint nrPoints = pointsStr.toInt();
  setup->setLinearSweep( linear );
  setup->setNumberOfFrequencyPoints( nrPoints );
  setup->setStartFrequency( start );
  setup->setStopFrequency( stop );
  NavigationWindow::instance()->updateSweep();
  return TRUE;
}

//-----------------------------------------------------------------
bool MainWindow::readGraphDefinitionsFromDOM( QDomElement& element )
{
  GraphDefinition* definition = 0;
  QDomNode node = element.firstChild();
  while( !node.isNull() )
    {
      QDomElement childElement = node.toElement();
      if( !childElement.isNull() )
        {
          QString name = childElement.attribute( "NAME" );
          QString title = childElement.attribute( "TITLE" );
          if ( childElement.tagName() == "GRID" )
            {
              definition = addGrid( name, title );
            }
          else if ( childElement.tagName() == "SMITH" )
            {
              definition = addSmith( name, title );
            }
          else if ( childElement.tagName() == "TABLE" )
            {
              definition = addTable( name, title );
            }
          else
            {
              return FALSE;
            }
          definition->readFromDOM( childElement );
        }
      node = node.nextSibling();
    }
  return TRUE;
}

//-----------------------------------------------------------------
bool MainWindow::readSubstrateDefinitionsFromDOM( QDomElement& element )
{
  QDomNode node = element.firstChild();
  while( !node.isNull() )
    {
      QDomElement childElement = node.toElement();
      if( !childElement.isNull() )
        {
          if ( childElement.tagName() != "SUB" )
            {
              return FALSE;
            }
          QString name = childElement.attribute( "NAME" );
          substrateMap_[name].readFromDOM( childElement );
          NavigationWindow::instance()->updateSubstrate( name,
              substrateMap_[name].type() );
        }
      node = node.nextSibling();
    }
  return TRUE;
}

//-----------------------------------------------------------------
bool MainWindow::readFileBlocksFromDOM( QDomElement& element )
{
  QDomNode node = element.firstChild();
  while( !node.isNull() )
    {
      QDomElement childElement = node.toElement();
      if( !childElement.isNull() )
        {
          if ( childElement.tagName() != "BLOCK" )
            {
              return FALSE;
            }
          QString name = childElement.attribute( "NAME" );
          QFileInfo info( name );
          if ( !info.exists() )
            {
              //Look for parameter file in circuit file directory
              QFileInfo circuitFileInfo( filename_ );
              info.setFile( circuitFileInfo.dir(), info.fileName() );
              name =  info.filePath();
            }
          readFileBlock( name );
        }
      node = node.nextSibling();
    }
  return TRUE;
}

//-----------------------------------------------------------------
void MainWindow::printSlot()
{
#ifdef WIN_DEMO
  QMessageBox::warning( this, Strings::LabelApplicationName,
                        "The print feature is disabled in the Windows demo",
                        Strings::translate(Strings::LabelOk),
                        0, 0, 0, 0);
#else

  SchematicFrame::instance()->print();
#endif
}

//-----------------------------------------------------------------
void MainWindow::newSchematicSlot()
{
  bool ok = FALSE;
  QString text = QInputDialog::getText( Strings::translate( Strings::NewSchematicWindowTitle ),
                                        Strings::translate( Strings::MsgNewSchematicName ),
                                        QLineEdit::Normal,
                                        QString::null, &ok, this );
  text = text.upper();
  if ( ok && !text.isEmpty() )
    {
      if ( schematicMap_.contains( text ) )
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgSchematicAlreadyExists));
        }
      else
        {
          Schematic& schematic = schematicMap_[text];
          schematic.setName(text);
          NavigationWindow::instance()->addSchematic( text );
          SchematicFrame::instance()->setActiveSchematic( &schematic );
          fileChanged_ = TRUE;
        }
    }
}

//-----------------------------------------------------------------
void MainWindow::renameSchematic( const QString& name )
{
  bool ok = FALSE;
  QString newName = QInputDialog::getText( Strings::translate(Strings::RenameSchematicWindowTitle),
                    Strings::translate(Strings::MsgRenameSchematic)
                    .arg(name),
                    QLineEdit::Normal,
                    QString::null, &ok, this );
  newName = newName.upper();
  if ( ok && !newName.isEmpty() )
    {
      schematicMap_[newName] = schematicMap_[name];
      schematicMap_[newName].setName( newName );
      schematicMap_.remove( name );
      NavigationWindow::instance()->removeSchematic( name );
      NavigationWindow::instance()->addSchematic( newName );
      SchematicFrame::instance()->setActiveSchematic( &schematicMap_[newName] );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::deleteSchematic( const QString& name )
{
  if ( confirm( Strings::translate(Strings::MsgConfirmDeleteSchematic).arg(name) ) )
    {
      QString activeName = SchematicFrame::instance()->getActiveSchematicName();
      if ( activeName == name )
        {
          SchematicFrame::instance()->setActiveSchematic( 0 );
        }
      schematicMap_.remove( name );
      NavigationWindow::instance()->removeSchematic( name );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::setActiveSchematic( const QString& name )
{
  ASSERT( schematicMap_.contains( name ) );
  Schematic& schematic = schematicMap_[name];
  SchematicFrame::instance()->setActiveSchematic( &schematic );
}

//-----------------------------------------------------------------
void MainWindow::getSchematicNames( QStringList& list )
{
  list.clear();
  SchematicMap::Iterator it;
  for( it = schematicMap_.begin(); it != schematicMap_.end(); ++it )
    {
      list.append( it.key() );
    }
}

//-----------------------------------------------------------------
void MainWindow::changeSchematicSize( const QString& name )
{
  if ( schematicSizeWindow_.isNull() )
    {
      schematicSizeWindow_
      = new SchematicSizeWindow( 0, Strings::translate(Strings::SchematicSizeWindowTitle) );
    }
  schematicSizeWindow_->setSchematicName( name );
  schematicSizeWindow_->setSchematicSize( schematicMap_[name].getSize() );
  schematicSizeWindow_->raise();
  schematicSizeWindow_->exec();
}

//-----------------------------------------------------------------
void MainWindow::setSchematicSize( const QString& name,
                                   Schematic::SchematicSize newSize )
{
  ASSERT( schematicMap_.contains( name ) );
  schematicMap_[name].setSize( newSize );
}

//-----------------------------------------------------------------
void MainWindow::helpSlot()
{
  if ( helpWindow_.isNull() )
    {
      helpWindow_ = new HelpWindow( 0, Strings::translate(Strings::HelpWindowTitle) );
    }
  helpWindow_->show();
}

//-----------------------------------------------------------------
void MainWindow::aboutSlot()
{
  QString msg;
  msg.sprintf( "<center><h3>ViPEC %s<br/>"
               "Copyright &copy  1991-2001</h3></center>"
               "<p><b>Authors:</b></p>"
               "<ul><li>J. Rossouw<br/>(johanrossouw@users.sourceforge.net)</li>"
               "<li>E. Jansen<br/>(eugenejansen@users.sourceforge.net)</li></ul>"
               "<p><b>Contributions by:</b></p>"
               "<ul><li>Y. Collette</li></ul>"
               "<ul><li>B. Dillmann</li></ul>"
               "<ul><li>J. Flucke</li></ul>"
               "<ul><li>N. S. Almeida</li></ul>"
               "<p><b>Homepage:</b></p>"
               "<ul><li>http://vipec.sourceforge.net</li></ul>", version);
  msg += "<p><center>Compiled on " __DATE__ " " __TIME__ "</center></p>";

  QPixmap aboutIcon( logo_xpm );

  QMessageBox mb( Strings::translate(Strings::AboutWindowTitle),
                  msg,
                  QMessageBox::NoIcon,
                  QMessageBox::Ok | QMessageBox::Default,
                  0, 0, this);
  mb.setIconPixmap(aboutIcon);
  mb.adjustSize();
  mb.setFixedSize(mb.width(), mb.height());
  mb.exec();
}

//-----------------------------------------------------------------
void MainWindow::aboutQtSlot()
{
  QMessageBox::aboutQt( this, Strings::translate(Strings::AboutQtWindowTitle) );
}

//-----------------------------------------------------------------
void MainWindow::newVariableSlot()
{
  bool ok = FALSE;
  QString name = QInputDialog::getText( Strings::translate(Strings::NewVariableWindowTitle),
                                        Strings::translate(Strings::MsgNewVariableName),
                                        QLineEdit::Normal,
                                        QString::null, &ok, this );
  name = name.upper();
  if ( ok && !name.isEmpty() )
    {
      if ( variableMap_.contains( name ) )
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgVariableAlreadyExists));
        }
      else
        {
          QString value = QInputDialog::getText( Strings::translate(Strings::NewVariableWindowTitle),
                                                 Strings::translate(Strings::MsgEnterVariableValue),
                                                 QLineEdit::Normal,
                                                 QString::null, &ok, this );
          value = value.upper();
          if ( ok && !value.isEmpty() )
            {
              variableMap_[name] = value;
              NavigationWindow::instance()->addVariable( name, value );
              fileChanged_ = TRUE;
            }
        }
    }
}

//-----------------------------------------------------------------
void MainWindow::changeVariable( const QString& name )
{
  bool ok = FALSE;
  QString value = QInputDialog::getText( Strings::translate(Strings::ChangeVariableWindowTitle),
                                         Strings::translate(Strings::MsgChangeVariableValue)
                                         .arg(name),
                                         QLineEdit::Normal,
                                         variableMap_[name], &ok, this );
  value = value.upper();
  if ( ok && !value.isEmpty() )
    {
      variableMap_[name] = value;
      NavigationWindow::instance()->updateVariable( name, value );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::renameVariable( const QString& name )
{
  bool ok = FALSE;
  QString newName = QInputDialog::getText( Strings::translate(Strings::RenameVariableWindowTitle),
                    Strings::translate(Strings::MsgRenameVariable)
                    .arg(name),
                    QLineEdit::Normal,
                    QString::null, &ok, this );
  newName = newName.upper();
  if ( ok && !newName.isEmpty() )
    {
      QString value = variableMap_[name];
      variableMap_.remove( name );
      NavigationWindow::instance()->removeVariable( name );
      variableMap_[newName] = value;
      NavigationWindow::instance()->addVariable( newName, value );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::deleteVariable( const QString& name )
{
  if ( confirm( Strings::translate(Strings::MsgConfirmDeleteVariable).arg(name) ) )
    {
      variableMap_.remove( name );
      NavigationWindow::instance()->removeVariable( name );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::updateVariable( const QString& name,
                                 const QString& value )
{
  variableMap_[name] = value;
  NavigationWindow::instance()->updateVariable( name, value );
  fileChanged_ = TRUE;
}

//-----------------------------------------------------------------
TReal MainWindow::getVariableValue( const QString& name )
{
  if ( !variableMap_.contains( name ) )
    {
      throw Exception::VariableNotDefined();
    }
  bool ok = FALSE;
  TReal value = 0;
  QString valueStr = variableMap_[name];
  if ( valueStr.contains( ':' ) == 2 )
    {
      value = Utils::getNumericRangePart( valueStr, 1 );
    }
  else
    {
      value = valueStr.toDouble(&ok);
      if ( !ok )
        {
          throw Exception::VariableHasNoValue();
        }
    }
  return value;
}

//-----------------------------------------------------------------
Schematic* MainWindow::getSchematic( const QString& name )
{
  Schematic* circuit = 0;
  if ( schematicMap_.contains( name ) )
    {
      circuit = &schematicMap_[name];
    }
  return circuit;
}

//-----------------------------------------------------------------
bool MainWindow::confirm( const QString& message )
{
  bool result = FALSE;
  switch( QMessageBox::information( this, Strings::LabelApplicationName,
                                    message,
                                    Strings::translate(Strings::LabelYes),
                                    Strings::translate(Strings::LabelCancel),
                                    0,
                                    1 ) )
    {
    case 0:
      result = TRUE;
      break;
    case 1:
      result = FALSE;
      break;
    }
  return result;
}

//-----------------------------------------------------------------
void MainWindow::setTranslator(QTranslator* translator)
{
  translator_ = translator;
}

//-----------------------------------------------------------------
QTranslator* MainWindow::getTranslator()
{
  return translator_;
}

//-----------------------------------------------------------------
void MainWindow::resetCircuits()
{
  SchematicMap::Iterator it;
  for( it = schematicMap_.begin(); it != schematicMap_.end(); ++it )
    {
      Schematic& circuit = it.data();
      circuit.reset();
    }
}

//-----------------------------------------------------------------
bool MainWindow::checkSchematics()
{
  SchematicMap::Iterator it;
  for( it = schematicMap_.begin(); it != schematicMap_.end(); ++it )
    {
      Schematic& circuit = it.data();
      try
        {
          QString msg = Strings::translate( Strings::StatusMessageCheckingSchematic ).arg( it.key() );
          statusBar()->message( msg, 2000 );
          qApp->processEvents();
          circuit.numberAllNodes();
          circuit.initSweep();
        }
      catch (Exception::FloatingNode)
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgFloatingNodes) );
          return FALSE;
        }
      catch (Exception::ShortedPorts)
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgPortNodesShorted) );
          return FALSE;
        }
      catch (Exception::AttributeHasNoValue)
        {
          QString msg = Strings::translate( Strings::MsgMissingAttrValue ).arg( it.key() );
          QMessageBox::warning( this, Strings::LabelApplicationName, msg );
          return FALSE;
        }
      catch (Exception::VariableNotDefined)
        {
          QString msg = Strings::translate( Strings::MsgUndefinedVariable ).arg( it.key() );
          QMessageBox::warning( this, Strings::LabelApplicationName, msg );
          return FALSE;
        }
      catch (Exception::VariableHasNoValue)
        {
          QString msg = Strings::translate( Strings::MsgVariableHasNoValue ).arg( it.key() );
          QMessageBox::warning( this, Strings::LabelApplicationName, msg );
          return FALSE;
        }
      catch (Exception::NoSuchSubstrate)
        {
          QString msg = Strings::translate( Strings::MsgUndefinedSubstrate ).arg( it.key() );
          QMessageBox::warning( this, Strings::LabelApplicationName, msg );
          return FALSE;
        }
      catch (...)
        {
          QString msg = Strings::translate( Strings::MsgUnknownException );
          QMessageBox::warning( this, Strings::LabelApplicationName, msg );
          return FALSE;
        }
    }
  statusBar()->message( Strings::translate( Strings::StatusMessageSchematicsOk ), 2000 );
  return TRUE;
}

//-----------------------------------------------------------------
void MainWindow::calculateResponse()
{
  if ( !checkSchematics() )
    {
      return;
    }
  Setup& setup = *Setup::instance();
  setup.buildFrequencyVector();
  Vector& frequencies = setup.getFrequencyVector();
  SchematicMap::Iterator it;
  try
    {
      for( it = schematicMap_.begin(); it != schematicMap_.end(); ++it )
        {
          Schematic& circuit = it.data();
          QString msg = Strings::translate( Strings::StatusMessageSweepingSchematic ).arg( it.key() );
          statusBar()->message( msg );
          qApp->processEvents();
          circuit.sweep( frequencies );
        }

      showAllGraphs();
      computeAllGraphOutputs();

    }
  catch ( Exception::NoSuchCircuit )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate( Strings::MsgOutputContainsInvalidCircuit ) );
    }
  catch ( Exception::StabilityFactorNotDefined )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate( Strings::MsgStabilityFactorOnlyFor2Port ) );
    }
  catch ( Matrix::ExceptionMatrixSingular )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate( Strings::MsgNoSolutionForCircuit ) );
    }
  catch ( Exception::NumberOfPortsDoesNotMatch )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate( Strings::MsgNumberOfPortsDoesNotMatch ) );
    }
  catch (Exception::NoSuchBlock)
    {
      QString msg = Strings::translate( Strings::MsgUndefinedBlock ).arg( it.key() );
      QMessageBox::warning( this, Strings::LabelApplicationName, msg );
    }
  catch (Exception::FrequencyOutOfRange)
    {
      QString msg = Strings::translate( Strings::MsgSweepBeyondBlockRange ).arg( it.key() );
      QMessageBox::warning( this, Strings::LabelApplicationName, msg );
    }
  QString msg = Strings::translate( Strings::StatusMessageSweepingDone );
  statusBar()->message( msg, 2000 );
}

//-----------------------------------------------------------------
GraphDefinition* MainWindow::findGraph( const QString& name )
{
  GraphDefinition* graph = 0;
  //Find graph view
  for ( graph = graphs_.first(); graph != 0; graph = graphs_.next() )
    {
      if ( graph->getName() == name )
        {
          break;
        }
    }
  return graph;
}

//-----------------------------------------------------------------
void MainWindow::graphFontChanged()
{
  GraphDefinition* graph = 0;
  for ( graph = graphs_.first(); graph != 0; graph = graphs_.next() )
    {
      graph->reDraw();
    }
}

//-----------------------------------------------------------------
void MainWindow::removeAllGraphs()
{
  graphs_.clear();
}

//-----------------------------------------------------------------
void MainWindow::showAllGraphs()
{
  GraphDefinition* graph = 0;
  for ( graph = graphs_.first(); graph != 0; graph = graphs_.next() )
    {
      graph->show();
    }
}

//-----------------------------------------------------------------
void MainWindow::computeAllGraphOutputs()
{
  GraphDefinition* graph = 0;
  for ( graph = graphs_.first(); graph != 0; graph = graphs_.next() )
    {
      graph->fill();
    }
}

//-----------------------------------------------------------------
void MainWindow::renameGraph( const QString& oldName,
                              const QString& newName )
{
  GraphDefinition* graph = findGraph( oldName );
  if ( graph )
    {
      graph->setName( newName );
      NavigationWindow::instance()->renameGraph( oldName, newName );
    }
  fileChanged_ = TRUE;
}

//-----------------------------------------------------------------
void MainWindow::deleteGraph( const QString& name )
{
  if ( !confirm( Strings::translate(Strings::MsgConfirmDeleteGraphView).arg(name) ) )
    {
      return;
    }

  GraphDefinition* graph = 0;
  for ( graph = graphs_.first(); graph != 0; graph = graphs_.next() )
    {
      if ( graph->getName() == name )
        {
          break;
        }
    }
  ASSERT( graph != 0 );
  NavigationWindow::instance()->removeGraph( name );
  graphs_.remove( graph );
  fileChanged_ = TRUE;
}

//-----------------------------------------------------------------
void MainWindow::newGraphSlot()
{
  if ( newGraphWindow_.isNull() )
    {
      newGraphWindow_ =
        new NewGraphWindow( this, Strings::translate(Strings::NewGraphViewWindowTitle) );
    }
  newGraphWindow_->show();
}

//-----------------------------------------------------------------
void MainWindow::addGraph( const QString& name, NewGraphWindow::GraphType graphType )
{
  if ( findGraph( name ) != 0 )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgGraphAlreadyExists).arg(name) );
    }
  else
    {
      switch ( graphType )
        {
        case NewGraphWindow::graphType:
          addGrid( name, "" );
          break;
        case NewGraphWindow::smithType:
          addSmith( name, "" );
          break;
        case NewGraphWindow::tableType:
          addTable( name, "" );
          break;
        default:
          ASSERT( "Unknown graph type!" == 0 );
        }
      fileChanged_ = TRUE;
    }
  cout << "addGraph" << endl;
}

//-----------------------------------------------------------------
void MainWindow::renameGraph( const QString& name )
{
  bool ok = FALSE;
  QString newName = QInputDialog::getText( Strings::translate(Strings::RenameGraphViewWindowTitle),
                    Strings::translate(Strings::MsgRenameGraphView)
                    .arg(name),
                    QLineEdit::Normal,
                    QString::null, &ok, this );
  newName = newName.upper();
  if ( ok && !newName.isEmpty() )
    {
      if ( findGraph( newName ) != 0 )
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgGraphAlreadyExists).arg( newName ) );
        }
      else
        {
          renameGraph( name, newName );
        }
    }
}

//-----------------------------------------------------------------
GridDefinition* MainWindow::addGrid( const QString& name,
                                     const QString& title )
{
  GridDefinition* grid = new GridDefinition();
  grid->setName( name );
  grid->setTitle( title );
  graphs_.append( grid );
  NavigationWindow::instance()->addGraph( *grid );
  return grid;
}

//-----------------------------------------------------------------
GridDefinition* MainWindow::findGrid( const QString& name )
{
  GraphDefinition* graph = findGraph( name );
  GridDefinition* grid = 0;
  if ( graph )
    {
      ASSERT( graph->graphType() == GraphDefinition::gridType );
      grid = (GridDefinition*) graph;
    }
  return grid;
}

//-----------------------------------------------------------------
SmithDefinition* MainWindow::addSmith( const QString& name,
                                       const QString& title )
{
  SmithDefinition* smith = new SmithDefinition();
  smith->setName( name );
  smith->setTitle( title );
  graphs_.append( smith );
  NavigationWindow::instance()->addGraph( *smith );
  return smith;
}


//-----------------------------------------------------------------
SmithDefinition* MainWindow::findSmith( const QString& name )
{
  GraphDefinition* graph = findGraph( name );
  SmithDefinition* smith = 0;
  if ( graph )
    {
      ASSERT( graph->graphType() == GraphDefinition::smithType );
      smith = (SmithDefinition*) graph;
    }
  return smith;
}

//-----------------------------------------------------------------
TableDefinition* MainWindow::addTable( const QString& name,
                                       const QString& title )
{
  TableDefinition* table = new TableDefinition();
  table->setName( name );
  table->setTitle( title );
  graphs_.append( table );
  NavigationWindow::instance()->addGraph( *table );
  return table;
}


//-----------------------------------------------------------------
TableDefinition* MainWindow::findTable( const QString& name )
{
  GraphDefinition* graph = findGraph( name );
  TableDefinition* table = 0;
  if ( graph )
    {
      ASSERT( graph->graphType() == GraphDefinition::tableType );
      table = (TableDefinition*) graph;
    }
  return table;
}

//-----------------------------------------------------------------
void MainWindow::microStripCalculator()
{
  if ( microStripCalculator_.isNull() )
    {
      QString title = Strings::translate( Strings::MicroStripCalcWindowTitle );
      microStripCalculator_ = new MicroStripCalcWindow( this,
                              title );
    }
  microStripCalculator_->show();
}

//-----------------------------------------------------------------
void MainWindow::tuner()
{
  if ( !tunerWindow_.isNull() )
    {
      delete tunerWindow_;
    }

  QList<QString> nameList;
  QList<QString> valueList;
  nameList.setAutoDelete( TRUE );
  valueList.setAutoDelete( TRUE );

  VariableMap::Iterator it;
  for( it = variableMap_.begin(); it != variableMap_.end(); ++it )
    {
      QString name = it.key();
      QString value = it.data();
      if ( value.contains( ':' ) == 2 )
        {
          nameList.append( new QString(name) );
          valueList.append( new QString(value) );
        }
    }

  if ( nameList.count() == 0 )
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgNoRangeVariables));
    }
  else
    {
      if ( tunerWindow_.isNull() )
        {
          QString title = Strings::translate( Strings::CircuitTunerWindowTitle );
          tunerWindow_ = new TunerWindow( this, title );
        }
      tunerWindow_->setRangeList( nameList, valueList );
      tunerWindow_->show();
    }
}

//-----------------------------------------------------------------
void MainWindow::newSubstrateSlot()
{
  if ( substrateWindow_.isNull() )
    {
      QString title = Strings::translate( Strings::DefineSubstrateWindowTitle );
      substrateWindow_ = new SubstrateWindow( this, title );
    }
  substrateWindow_->enableNameField( TRUE );
  substrateWindow_->show();
}

//-----------------------------------------------------------------
void MainWindow::changeSubstrate( const QString& name )
{
  ASSERT( substrateMap_.contains( name ) );
  if ( substrateWindow_.isNull() )
    {
      QString title = Strings::translate( Strings::DefineSubstrateWindowTitle );
      substrateWindow_ = new SubstrateWindow( this, title );
    }
  substrateWindow_->enableNameField( FALSE );
  substrateWindow_->update( name, substrateMap_[name] );
  substrateWindow_->show();
}

//-----------------------------------------------------------------
void MainWindow::updateSubstrate( const QString& name,
                                  const SubstrateDefinition& definition )
{
  NavigationWindow::instance()->updateSubstrate( name,
      definition.type() );
  substrateMap_[ name ] = definition;
}

//-----------------------------------------------------------------
void MainWindow::renameSubstrate( const QString& name )
{
  ASSERT( substrateMap_.contains( name ) );
  bool ok = FALSE;
  QString newName = QInputDialog::getText( Strings::translate(Strings::RenameSubstrateWindowTitle),
                    Strings::translate(Strings::MsgRenameSubstrate)
                    .arg(name),
                    QLineEdit::Normal,
                    QString::null, &ok, this );
  newName = newName.upper();
  if ( ok && !newName.isEmpty() )
    {
      SubstrateDefinition sub = substrateMap_[name];
      substrateMap_.remove( name );
      NavigationWindow::instance()->removeSubstrate( name );
      substrateMap_[newName] = sub;
      NavigationWindow::instance()->updateSubstrate( newName, sub.type() );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
void MainWindow::deleteSubstrate( const QString& name )
{
  ASSERT( substrateMap_.contains( name ) );
  if ( confirm( Strings::translate(Strings::MsgConfirmDeleteSubstrate).arg(name) ) )
    {
      substrateMap_.remove( name );
      NavigationWindow::instance()->removeSubstrate( name );
      fileChanged_ = TRUE;
    }
}

//-----------------------------------------------------------------
SubstrateDefinition* MainWindow::getSubstrate( const QString& name )
{
  SubstrateDefinition* sub = 0;
  if ( substrateMap_.contains( name ) )
    {
      sub = &substrateMap_[name];
    }
  return sub;
}

//-----------------------------------------------------------------
void MainWindow::newDataFileSlot()
{
  QString filter = Strings::translate( Strings::ParameterFileFilter );
  QString filename =  QFileDialog::getOpenFileName( QString::null, filter, this );
  if ( filename.isEmpty() )
    {
      return;
    }
  readFileBlock( filename );
}

//-----------------------------------------------------------------
void MainWindow::readFileBlock( const QString& filename )
{
  try
    {
      FileBlock fileblock;
      if ( fileblock.openFile( filename ) )
        {
          QFileInfo fileinfo( filename );
          QString mapName = fileinfo.fileName().upper();
          NavigationWindow::instance()->addFileBlock( mapName );
          fileBlockMap_[ mapName ] = fileblock;
        }
      else
        {
          QMessageBox::warning( this, Strings::LabelApplicationName,
                                Strings::translate(Strings::MsgCouldNotOpenFile), Strings::translate(Strings::LabelOk),
                                0, 0, 0, 0);
        }
    }
  catch (...)
    {
      QMessageBox::warning( this, Strings::LabelApplicationName,
                            Strings::translate(Strings::MsgCouldNotOpenFile), Strings::translate(Strings::LabelOk),
                            0, 0, 0, 0);
    }
}

//-----------------------------------------------------------------
void MainWindow::deleteDataFile( const QString& name )
{
  ASSERT( fileBlockMap_.contains( name ) );
  fileBlockMap_.remove( name );
  NavigationWindow::instance()->removeFileBlock( name );
}

//-----------------------------------------------------------------
QList<DataPoint>* MainWindow::getFileData( const QString& name )
{
  QList<DataPoint>* list = 0;
  if ( fileBlockMap_.contains( name ) )
    {
      list = & (fileBlockMap_[ name ].data());
    }
  return list;
}

//-----------------------------------------------------------------
void MainWindow::setLanguage()
{
  if ( setupLanguageWindow_.isNull() )
    {
      QString title = Strings::translate( Strings::SetupLanguageWindowTitle );
      setupLanguageWindow_ = new SetupLanguageWindow( this,
                             title );
    }
  if (setupLanguageWindow_->init())
    {
      setupLanguageWindow_->show();
    }
}

//-----------------------------------------------------------------
void MainWindow::notifyConfigChange()
{
  QMessageBox::information( this, Strings::LabelApplicationName,
                            Strings::translate( Strings::MsgTakeEffectWhenRestarted ) );
}
