#include <Setup.h>

#include <Logger.h>
#include <Strings.h>
#include <Types.h>
#include <Utils.h>

#include <qdir.h>
#include <qfile.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qregexp.h>

#include <stdlib.h>
#include <iostream>

using namespace std;

Setup* Setup::instance_ = 0;

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

//-----------------------------------------------------------------
Setup::Setup()
    : debugMode_( FALSE ),
    componentTextEnabled_( TRUE )
{
  initialize();
}

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

//-----------------------------------------------------------------
void Setup::setDebugMode(bool debugMode)
{
  debugMode_ = debugMode;
}

//-----------------------------------------------------------------
bool Setup::isDebugMode() const
  {
    return debugMode_;
  }

//-----------------------------------------------------------------
void Setup::setComponentTextEnabled(bool enabled)
{
  componentTextEnabled_ = enabled;
}

//-----------------------------------------------------------------
bool Setup::isComponentTextEnabled() const
  {
    return componentTextEnabled_;
  }

//-----------------------------------------------------------------
DimensionMap& Setup::getDimensionMap()
{
  return dimensionMap_;
}

//-----------------------------------------------------------------
DimensionDefinition* Setup::getDimensionDefinition( const QString& name,
    bool translateKey )
{
  DimensionDefinition* item = 0;
  DimensionMap::Iterator it;
  for( it = dimensionMap_.begin(); it != dimensionMap_.end(); ++it )
    {
      QString trEntry = it.key();
      if ( translateKey )
        {
          trEntry = Strings::translate( it.key() );
        }
      if ( trEntry == name )
        {
          item = &(it.data());
        }
    }
  return item;
}

//-----------------------------------------------------------------
TReal Setup::getDimensionValue( const QString& name )
{
  DimensionDefinition* definition = getDimensionDefinition( name );
  return definition->getActiveValue();
}

//-----------------------------------------------------------------
void Setup::initialize()
{
  DimensionDefinition& freqDim = dimensionMap_[Strings::FrequencyDim];
  freqDim.addEntry( "Hz",  2*M_PI );
  freqDim.addEntry( "KHz", 2*M_PI*1E3 );
  freqDim.addEntry( "MHz", 2*M_PI*1E6 );
  freqDim.addEntry( "GHz", 2*M_PI*1E9 );
  freqDim.setActiveValue( "Hz" );

  DimensionDefinition& resDim = dimensionMap_[Strings::ResistanceDim];
  resDim.addEntry( "Ohm", 1 );
  resDim.addEntry( "KOhm", 1E3 );
  resDim.addEntry( "MOhm", 1E6 );
  resDim.setActiveValue( "Ohm" );

  DimensionDefinition& capDim = dimensionMap_[Strings::CapacitanceDim];
  capDim.addEntry( "F", 1 );
  capDim.addEntry( "mF", 1E-3 );
  capDim.addEntry( "uF", 1E-6 );
  capDim.addEntry( "nF", 1E-9 );
  capDim.addEntry( "pF", 1E-12 );
  capDim.addEntry( "fF", 1E-15 );
  capDim.setActiveValue( "nF" );

  DimensionDefinition& indDim = dimensionMap_[Strings::InductanceDim];
  indDim.addEntry( "H", 1 );
  indDim.addEntry( "mH", 1E-3 );
  indDim.addEntry( "uH", 1E-6 );
  indDim.addEntry( "nH", 1E-9 );
  indDim.addEntry( "pH", 1E-12 );
  indDim.setActiveValue( "uH" );

  DimensionDefinition& angDim = dimensionMap_[Strings::AngularDim];
  angDim.addEntry( "DEG", 180/M_PI );
  angDim.addEntry( "RAD", 1 );
  angDim.setActiveValue( "DEG" );

  DimensionDefinition& lngDim = dimensionMap_[Strings::LengthDim];
  lngDim.addEntry( "m", 1 );
  lngDim.addEntry( "cm", 1E-1 );
  lngDim.addEntry( "mm", 1E-3 );
  lngDim.addEntry( "um", 1E-6 );
  lngDim.addEntry( "nm", 1E-9 );
  lngDim.setActiveValue( "um" );

  DimensionDefinition& timeDim = dimensionMap_[Strings::TimeDim];
  timeDim.addEntry( "s", 1 );
  timeDim.addEntry( "ms", 1E-3 );
  timeDim.addEntry( "us", 1E-6 );
  timeDim.addEntry( "ns", 1E-9 );
  timeDim.setActiveValue( "us" );

  sweepLinear_ = FALSE;
  sweepStartFrequency_ = 0.01;
  sweepStopFrequency_ = 10;
  sweepNumberOfPoints_ = 200;

  //Init some directory/file names
  QDir dir;
  vipecHome_ = QString(getenv("VIPECHOME"));
  if ( vipecHome_.isEmpty() )
    {
      vipecHome_ = dir.absPath();
      Logger::warning("VIPECHOME not set, assuming " + vipecHome_);
    }
  helpFilename_ = vipecHome_ + "/help/index.html";
  configFilename_ = vipecHome_ + "/vipec.cfg";

  Logger::debug("Help filename is " + helpFilename_ );
  Logger::debug("Config filename is " + configFilename_);

  parseConfig();

}

//-----------------------------------------------------------------
void Setup::initConfig()
{
  QString content =
    "<!DOCTYPE VIPEC_CONFIG_FILE >"
    "<FILE CREATOR=\"ViPEC\" >"
    "<LANGUAGEFILE NAME=\"\" /></FILE>";
  config_.setContent( content );
}

//-----------------------------------------------------------------
void Setup::parseConfig()
{
  QStringList list;
  QFile file( configFilename_ );
  if ( !file.open(IO_ReadOnly) )
    {
      Logger::error("Config file " + configFilename_ + " could not be read");
      initConfig();
      return;
    }
  if ( !config_.setContent( &file ) )
    {
      file.close();
      Logger::error("Error parsing config file " + configFilename_);
      initConfig();
      return;
    }
  file.close();

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

  while ( !docNode.isNull() )
    {
      QDomElement element = docNode.toElement();
      if ( !element.isNull() )
        {
          QString tagName = element.tagName();
          if ( tagName == "LANGUAGEFILE" )
            {
              languageFile_ = element.attribute( "NAME" );
            }
        }
      docNode = docNode.nextSibling();
    }
}

//-----------------------------------------------------------------
void Setup::writeConfig()
{
  QFile file( configFilename_ );
  if ( !file.open(IO_WriteOnly) )
    {
      Logger::error("Config file " + configFilename_ + " could not be written");
    }
  QString docStr;
  QTextStream filestream( &file );
  QTextStream stream( docStr, IO_WriteOnly );
  //config_.save( stream, 1 );
  QString tempStr = config_.toString();
  //Fix for Qt bug under Windows
  if ( tempStr.find("VIPEC_CONFIG_FILE") < 0 )
    {
      tempStr.replace( QRegExp("DOCTYPE"), "DOCTYPE VIPEC_CONFIG_FILE" );
    }
  filestream << tempStr;
  file.flush();
  file.close();
}

//-----------------------------------------------------------------
bool Setup::solveByInversion()
{
  return TRUE;
}

//-----------------------------------------------------------------
bool Setup::isLinearSweep() const
  {
    return sweepLinear_;
  }

//-----------------------------------------------------------------
void Setup::setLinearSweep( bool isLinear )
{
  sweepLinear_ = isLinear;
}

//-----------------------------------------------------------------
TReal Setup::getStartFrequency() const
  {
    return sweepStartFrequency_;
  }

//-----------------------------------------------------------------
void Setup::setStartFrequency( TReal start )
{
  sweepStartFrequency_ = start;
}

//-----------------------------------------------------------------
TReal Setup::getStopFrequency() const
  {
    return sweepStopFrequency_;
  }

//-----------------------------------------------------------------
void Setup::setStopFrequency( TReal stop )
{
  sweepStopFrequency_ = stop;
}

//-----------------------------------------------------------------
uint Setup::getNumberOfFrequencyPoints() const
  {
    return sweepNumberOfPoints_;
  }

//-----------------------------------------------------------------
void Setup::setNumberOfFrequencyPoints( uint nrPoints )
{
  sweepNumberOfPoints_ = nrPoints;
}

//-----------------------------------------------------------------
void Setup::buildFrequencyVector()
{
  frequencies_.resize (sweepNumberOfPoints_ );
  Utils::buildFrequencyVector( frequencies_,sweepStartFrequency_ ,
                               sweepStopFrequency_, sweepLinear_ );
}

//-----------------------------------------------------------------
Vector& Setup::getFrequencyVector()
{
  return frequencies_;
}

//-----------------------------------------------------------------
const QString& Setup::vipecHome()
{
  return vipecHome_;
}

//-----------------------------------------------------------------
const QString& Setup::languageFile()
{
  return languageFile_;
}

//-----------------------------------------------------------------
void Setup::setLanguageFile(const QString& languageFile )
{
  QDomElement docElement = config_.documentElement();
  QDomNode docNode = docElement.firstChild();
  while ( !docNode.isNull() )
    {
      QDomElement element = docNode.toElement();
      if ( !element.isNull() )
        {
          QString tagName = element.tagName();
          if ( tagName == "LANGUAGEFILE" )
            {
              QDomElement newElement = element;
              newElement.setAttribute( "NAME", languageFile );
              config_.replaceChild(newElement, element);
              break;
            }
        }
      docNode = docNode.nextSibling();
    }
  writeConfig();
  Logger::debug("Config updated\n" + config_.toString() );
}

