/* -*- 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 <FileBlock.h>

#include <Logger.h>
#include <Utils.h>
#include <Matrix.h>
#include <DataPoint.h>
#include <Exception.h>
#include <Setup.h>

#include <qfile.h>
#include <qfileinfo.h>
#include <qtextstream.h>

#include <iostream>


using namespace std;

//-----------------------------------------------------------------
FileBlock::FileBlock()
    : filename_(0),
    extension_(0),
    isRead_( FALSE ),
    impedance_(50.0)
{
  lastModified_ = QDateTime::currentDateTime();
  data_.setAutoDelete( TRUE );
}

//-----------------------------------------------------------------
FileBlock::~FileBlock()
{
  data_.clear();
}

//-----------------------------------------------------------------
FileBlock::FileBlock( const FileBlock& source )
{
  copy( source );
}

//-----------------------------------------------------------------
FileBlock& FileBlock::operator= ( const FileBlock& source )
{
  copy( source );
  return *this;
}

//-----------------------------------------------------------------
bool FileBlock::openFile( const QString& filename )
{
  filename_ = filename;
  QFile file( filename_ );
  bool success = file.open( IO_ReadOnly | IO_Translate );
  if ( success )
    {
      QFileInfo info( file );
      extension_ = info.extension();
      readFile( file );
    }
  file.close();
  return success;
}

//-----------------------------------------------------------------
void FileBlock::readFile( QFile& file )
{
  QFileInfo info( file );
  if ( isRead_ )
    {
      if ( lastModified_ == info.lastModified() )
        {
          return;
        }
      else
        {
          lastModified_ = info.lastModified();
          data_.clear();
        }
    }

  QTextStream s( &file );
  QString str;

  double unit_freq=1.0;

  Matrix zo(2);
  zo(0,0) = impedance_;
  zo(1,1) = impedance_;

  while ( !s.eof() )
    {
      QString line = s.readLine();
      str = line.simplifyWhiteSpace();
      if ( Setup::instance()->isDebugMode() )
        {
          Logger::debug("Parsing parameter line " + str);
        }
      if (!str.isEmpty())
        {
          QString tmp;
          Utils::getFirstPart(str, tmp);
          // new
          if (tmp.find( QChar( '!' ), 0 ) != -1)
            { //  line beginning with !,
              // check if the following lines are noise parameters
              if (str.find( QString ( "Noise" ), 0) != -1)
                return;
            }
          else
            { // proceed lines NOT beginning with !
              if (tmp.find( QChar( '#' ), 0 ) != -1)
                { // line beginning with #, containing unit of frequency
                  if (line.find( QString ( "KH" ), 0 ) != -1)
                    unit_freq=1e3;
                  if (line.find( QString ( "MH" ), 0 ) != -1)
                    unit_freq=1e6;
                  if (line.find( QString ( "GH" ), 0 ) != -1)
                    unit_freq=1e9;
                  if ( Setup::instance()->isDebugMode() )
                    {
                      QString message = QString("Setting unit of frequency to %1 Hz").arg(unit_freq);
                      Logger::debug(message);
                    }
                }
              else
                { // Normal line, not beginning with ! or # sign
                  bool   ok;
                  double freq = tmp.toDouble(&ok)*unit_freq; // Unit MHz

                  if ( Setup::instance()->isDebugMode() )
                    {
                      QString message = QString("Frequency is %1").arg(freq);
                      Logger::debug(message);
                    }

                  if (!ok)
                    {
                      throw Exception::FileFormatError();
                    }

                  double mag, ang;

                  Matrix S(2);
                  Matrix Y(2);

                  for (int r=0; r<2; r++)
                    for (int c=0; c<2; c++)
                      {
                        //Extract magnitude parameter
                        Utils::getFirstPart(str, tmp);
                        mag = tmp.toDouble(&ok);
                        if (!ok)
                          {
                            throw Exception::FileFormatError();
                          }
                        //Extract angle parameter
                        Utils::getFirstPart(str, tmp);
                        ang = tmp.toDouble(&ok) / 180 * M_PI;
                        if (!ok)
                          {
                            throw Exception::FileFormatError();
                          }
                        //Place in matrix
                        if ( Setup::instance()->isDebugMode() )
                          {
                            QString message = QString("Parameter [%1,%2]: MAG=%3, ANG=%4").arg(c).arg(r).arg(mag).arg(ang);
                            Logger::debug(message);
                          }
                        S(c,r) = polar(mag, ang);
                      }

                  //Convert to Y parameter set
                  if (extension_ == "s2p")
                    {
                      Utils::convertStoY(S, zo, Y);
                    }
                  else if (extension_ == "z2p")
                    {
                      Y = ~S;
                    }
                  else if (extension_ == "y2p")
                    {
                      Y = S;
                    }
                  else
                    {
                      throw Exception::UnknownFileType();
                    }

                  DataPoint* dataPoint = new DataPoint( 2*M_PI*freq, Y );
                  data_.append( dataPoint );
                }
            }
        }
    }
  isRead_ = TRUE;

}

//-----------------------------------------------------------------
void FileBlock::copy( const FileBlock& source )
{
  filename_ = source.filename_;
  extension_ = source.extension_;
  isRead_ = source.isRead_;
  impedance_ = source.impedance_;
  data_.clear();
  //Copy data
  QList<DataPoint>& datalist = (QList<DataPoint>&) source.data_;
  const DataPoint* data = 0;
  for ( data = datalist.first(); data != 0; data = datalist.next() )
    {
      data_.append( new DataPoint( *data ) );
    }
}

//-----------------------------------------------------------------
const QString& FileBlock::filename() const
  {
    return filename_;
  }

//-----------------------------------------------------------------
QList<DataPoint>& FileBlock::data()
{
  return data_;
}

//-----------------------------------------------------------------
void FileBlock::dump()
{
  DataPoint* data = 0;
  int counter = 0;
  for ( data = data_.first(); data != 0; data = data_.next() )
    {
      counter++;
      cout << "Point " << counter << " @ " << data << " freq = " << data->frequency() << ":\n";
      (data->data()).dump();
      cout << "\n\n";
    }
}
