/* -*- C++ -*-
 
  This file is part of ViPEC
  Copyright (C) 1991-2000 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 <MicroStripCalcWindow.h>

#include <Strings.h>

#include <math.h>
#include <stdio.h>
#include <iostream>

#include <qwidget.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qkeycode.h>
#include <qpixmap.h>
#include <qbitmap.h>
#include <qmessagebox.h>
#include <qlineedit.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qstring.h>


//--------------------------------------------------------------------------------
MicroStripCalcWindow::MicroStripCalcWindow( QWidget* parent, const char* name )
    : QDialog( parent, name , FALSE ),
    topLayout_(0)
{
  setCaption( name );

  topLayout_ = new QVBoxLayout( this );
  QGridLayout* gridLayout = new QGridLayout ( 0 );
  QHBoxLayout* buttonLayout = new QHBoxLayout( 0 );

  topLayout_->addSpacing( 10 );
  topLayout_->addItem( gridLayout );
  topLayout_->addSpacing( 10 );
  topLayout_->addItem( buttonLayout );

  gridLayout->expand( 7, 7 );
  gridLayout->addColSpacing( 0, 20 );
  gridLayout->addColSpacing( 1, 100 );
  gridLayout->addColSpacing( 2, 10 );
  gridLayout->addColSpacing( 3, 50 );
  gridLayout->addColSpacing( 4, 10 );
  gridLayout->addColSpacing( 5, 50 );
  gridLayout->addColSpacing( 6, 20 );

  erEdit_ = new QLineEdit( this, "er" );
  erEdit_->setMaxLength(10);
  erEdit_->setText("4.5");
  QLabel* erTitle
  = new QLabel( erEdit_,
                Strings::translate( Strings::CalcDielectricConstant ),
                this );
  QLabel* erLabel = new QLabel( 0, "Er", this );
  gridLayout->addWidget(erTitle,0,1);
  gridLayout->addWidget(erEdit_,0,3);
  gridLayout->addWidget(erLabel,0,5);

  hEdit_ = new QLineEdit( this, "height" );
  hEdit_->setMaxLength(10);
  hEdit_->setText("1.5");
  QLabel* hTitle
  = new QLabel( hEdit_,
                Strings::translate( Strings::CalcSubstraceHeight ),
                this );
  QLabel * hLabel = new QLabel( 0, "mm", this );
  gridLayout->addWidget(hTitle,1,1);
  gridLayout->addWidget(hEdit_,1,3);
  gridLayout->addWidget(hLabel,1,5);

  fEdit_ = new QLineEdit( this, "freq" );
  fEdit_->setMaxLength(10);
  fEdit_->setText("10.0");
  QLabel* fTitle
  = new QLabel( fEdit_,
                Strings::translate( Strings::CalcFrequency ),
                this );
  QLabel * fLabel = new QLabel( 0, "GHz", this );
  gridLayout->addWidget(fTitle,2,1);
  gridLayout->addWidget(fEdit_,2,3);
  gridLayout->addWidget(fLabel,2,5);

  // Physical parameters
  lEdit_ = new QLineEdit( this, "length" );
  lEdit_->setMaxLength(10);
  lEdit_->setText("10.0");
  QLabel* lTitle
  = new QLabel( lEdit_,
                Strings::translate( Strings::CalcLineLength ),
                this );
  QLabel * lLabel = new QLabel( 0, "mm", this );
  gridLayout->addWidget(lTitle,3,1);
  gridLayout->addWidget(lEdit_,3,3);
  gridLayout->addWidget(lLabel,3,5);

  wEdit_ = new QLineEdit( this, "width" );
  wEdit_->setMaxLength(10);
  wEdit_->setText("2.0");
  QLabel* wTitle
  = new QLabel( wEdit_,
                Strings::translate( Strings::CalcLineWidth ),
                this );
  QLabel * wLabel = new QLabel( 0, "mm", this );
  gridLayout->addWidget(wTitle,4,1);
  gridLayout->addWidget(wEdit_,4,3);
  gridLayout->addWidget(wLabel,4,5);

  // Electrical parameters
  elEdit_ = new QLineEdit( this, "elength" );
  elEdit_->setMaxLength(10);
  QLabel* elTitle
  = new QLabel( elEdit_,
                Strings::translate( Strings::CalcElectricalLength ),
                this );
  QLabel * elLabel = new QLabel( 0,
                                 Strings::translate( Strings::CalcDegrees ),
                                 this );
  gridLayout->addWidget(elTitle,5,1);
  gridLayout->addWidget(elEdit_,5,3);
  gridLayout->addWidget(elLabel,5,5);

  zEdit_ = new QLineEdit( this,
                          Strings::translate( Strings::CalcImpedance ) );
  zEdit_->setMaxLength(10);
  QLabel* zTitle
  = new QLabel( zEdit_,
                Strings::translate( Strings::CalcLineImpedance ),
                this );
  QLabel * zLabel = new QLabel( 0, "ohm", this );
  gridLayout->addWidget(zTitle,6,1);
  gridLayout->addWidget(zEdit_,6,3);
  gridLayout->addWidget(zLabel,6,5);

  QPushButton* but
  = new QPushButton( Strings::translate( Strings::CalcElectrical ),
                     this );
  connect( but, SIGNAL(pressed()), SLOT(calcElectrical()) );
  buttonLayout->addWidget(but);


  QPushButton* but2
  = new QPushButton( Strings::translate( Strings::CalcPhysical ),
                     this );
  connect( but2, SIGNAL(pressed()), SLOT(calcPhysical()) );
  buttonLayout->addWidget(but2);

  topLayout_->activate();
}


//--------------------------------------------------------------------------------
MicroStripCalcWindow::~MicroStripCalcWindow()
{}

//--------------------------------------------------------------------------------
void MicroStripCalcWindow::errorMsg(QString msg)
{
  QMessageBox::information( this, "LiNECALC message", msg);
}

//--------------------------------------------------------------------------------
void MicroStripCalcWindow::calcPhysical()
{
  if (!getSubstrateValues())
    return;

  bool convertOk;
  QString buffer;

  buffer = elEdit_->text();
  el_ = buffer.toDouble(&convertOk);
  if (!convertOk)
    {
      errorMsg("Invalid electrical length value!");
      return;
    }


  buffer = zEdit_->text();
  z_ = buffer.toDouble(&convertOk);
  if (!convertOk)
    {
      errorMsg("Invalid line impedance value!");
      return;
    }

  w_ = estimateW(z_,er_,h_);

  TReal ratio = w_/h_;
  TReal Ef = calcEf(ratio,er_);
  TReal temp = 3E8/(f_*sqrt(Ef));
  l_ = el_ / 360 * temp;

  buffer.sprintf( "%3.3f", (w_/1E-3));
  wEdit_->setText(buffer);
  buffer.sprintf( "%3.3f", (l_/1E-3));
  lEdit_->setText(buffer);


}

//--------------------------------------------------------------------------------
void MicroStripCalcWindow::calcElectrical()
{
  if (!getSubstrateValues())
    return;

  bool convertOk;
  QString buffer;

  buffer = wEdit_->text();
  w_ = buffer.toDouble(&convertOk);
  if (!convertOk)
    {
      errorMsg("Invalid line width value!");
      return;
    }


  buffer = lEdit_->text();
  l_ = buffer.toDouble(&convertOk);
  if (!convertOk)
    {
      errorMsg("Invalid substrate height value!");
      return;
    }

  w_ = w_ * 1E-3;
  l_ = l_ * 1E-3;

  TReal ratio = w_/h_;

  z_ = calcZo(ratio);
  TReal Ef = calcEf(ratio,er_);
  z_ = z_/sqrt(Ef);

  TReal temp = 3E8/(f_*sqrt(Ef));
  el_ = 360 * l_ / temp;

  buffer.sprintf( "%3.3f", z_);
  zEdit_->setText(buffer);
  buffer.sprintf( "%3.3f", el_);
  elEdit_->setText(buffer);

}

//--------------------------------------------------------------------------------
bool MicroStripCalcWindow::getSubstrateValues()
{
  bool convertOk;
  QString buffer;

  buffer = erEdit_->text();
  er_ = buffer.toDouble(&convertOk);
  if (!convertOk)
    errorMsg("Invalid Er value!");

  if (convertOk)
    {
      buffer = hEdit_->text();
      h_ = buffer.toDouble(&convertOk);
      if (!convertOk)
        errorMsg("Invalid substrate height value!");
      h_ = h_ * 1E-3;
    }

  if (convertOk)
    {
      buffer = fEdit_->text();
      f_ = buffer.toDouble(&convertOk);
      if (!convertOk)
        errorMsg("Invalid frequency value!");
      f_ = f_ * 1E9;
    }

  return convertOk;
}

//--------------------------------------------------------------------------------
TReal MicroStripCalcWindow::calcEf(TReal ratio, TReal Er)
{
  TReal a  = 1 + 1/49*log((pow(ratio,4)+pow(ratio/54,2))/(pow(ratio,4)+0.432))
             + 1/18.7*log(1+pow(ratio/18.1,3));
  TReal b = 0.564*pow((Er-0.9)/(Er+3),0.053);
  TReal Ef = (Er+1)/2+(Er-1)/2*pow(1+10/ratio,-a*b);
  return Ef;
}

//--------------------------------------------------------------------------------
TReal MicroStripCalcWindow::calcZo(TReal ratio)
{
  TReal Zo = 120*M_PI/(ratio + 1.98*pow(ratio,0.172));
  return Zo;
}

//--------------------------------------------------------------------------------
TReal MicroStripCalcWindow::estimateW(TReal Z, TReal Er, TReal H)
{
  TReal w = 8*sqrt((exp(Z*sqrt(Er+1)/42.4)-1)*((7+4/Er)/11)+
                   (1+1/Er)/0.81)/(exp(Z*sqrt(Er+1)/42.4)-1);
  w = w*H;
  return w;
}
