/****************************************************************************
 ** ui.h extension file, included from the uic-generated form implementation.
 **
 ** If you wish to add, delete or rename functions or slots use
 ** Qt Designer which will update this file, preserving your code. Create an
 ** init() function in place of a constructor, and a destroy() function in
 ** place of a destructor.
 *****************************************************************************/

#include <cmath>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>

#include <qmessagebox.h>
#include <qfile.h>
#include <qfiledialog.h>

#include "popassert.h"
#include "CColor.h"
#include "CVector3f.h"
#include "CVectBase.h"
#include "compute.h"
#include "CMathExpression.h"
#include "CRenderObj.h"
#include "CProgressDialog.h"
#include "CColorWidget.h"
#include "CTripleColorWidget.h"
#include "CGLPreview.h"

void SettingsForm::init()
{
  m_pSurfaceObj = new CRenderObj;
  m_pSurfaceObj->Update();

  m_pDoubleValidator = new QDoubleValidator( this );
  m_pPositiveDoubleValidator = new QDoubleValidator( this );
  m_pPositiveDoubleValidator->setBottom( 0 );
  m_pIntValidator = new QIntValidator( this );
  m_pIntValidator->setBottom( 1 );

  // Initialising the form
  EquationLineEdit->setText(m_pSurfaceObj->m_FormulaString.c_str());

  SignIncLineEdit->setValidator(m_pPositiveDoubleValidator);
  SignIncLineEdit->setText(QString::number(m_pSurfaceObj->m_SignIncrement));
  NoSignIncLineEdit->setValidator(m_pPositiveDoubleValidator);
  NoSignIncLineEdit->setText(QString::number(m_pSurfaceObj->m_NoSignIncrement));
  NoSignPrecLineEdit->setValidator(m_pPositiveDoubleValidator);
  NoSignPrecLineEdit->setText(QString::number(m_pSurfaceObj->m_NoSignPrecision));
  ZoomLineEdit->setValidator(m_pPositiveDoubleValidator);
  ZoomLineEdit->setText(QString::number(m_pSurfaceObj->m_Zoom));

  XminLineEdit->setValidator(m_pDoubleValidator);
  XminLineEdit->setText(QString::number(m_pSurfaceObj->m_MinVector.x));
  XmaxLineEdit->setValidator(m_pDoubleValidator);
  XmaxLineEdit->setText(QString::number(m_pSurfaceObj->m_MaxVector.x));
  YminLineEdit->setValidator(m_pDoubleValidator);
  YminLineEdit->setText(QString::number(m_pSurfaceObj->m_MinVector.y));
  YmaxLineEdit->setValidator(m_pDoubleValidator);
  YmaxLineEdit->setText(QString::number(m_pSurfaceObj->m_MaxVector.y));
  ZminLineEdit->setValidator(m_pDoubleValidator);
  ZminLineEdit->setText(QString::number(m_pSurfaceObj->m_MinVector.z));
  ZmaxLineEdit->setValidator(m_pDoubleValidator);
  ZmaxLineEdit->setText(QString::number(m_pSurfaceObj->m_MaxVector.z));
  ZmaxLineEdit->setValidator(m_pDoubleValidator);
  ZmaxLineEdit->setText(QString::number(m_pSurfaceObj->m_MaxVector.z));

  XviewerLineEdit->setValidator(m_pDoubleValidator);
  XviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.x));
  YviewerLineEdit->setValidator(m_pDoubleValidator);
  YviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.y));
  ZviewerLineEdit->setValidator(m_pDoubleValidator);
  ZviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.z));
  XlightLineEdit->setValidator(m_pDoubleValidator);
  XlightLineEdit->setText(QString::number(m_pSurfaceObj->m_LightDirection.x));
  YlightLineEdit->setValidator(m_pDoubleValidator);
  YlightLineEdit->setText(QString::number(m_pSurfaceObj->m_LightDirection.y));
  ZlightLineEdit->setValidator(m_pDoubleValidator);
  ZlightLineEdit->setText(QString::number(m_pSurfaceObj->m_LightDirection.z));

  BackgroundColorWidget->setColor((float *) &m_pSurfaceObj->m_BackgroundColor);
  BoxTripleColorWidget->setColor(2, (float *) &m_pSurfaceObj->m_BoxSpecularColor);
  BoxTripleColorWidget->setColor(1, (float *) &m_pSurfaceObj->m_BoxDiffuseColor);
  BoxTripleColorWidget->setColor(0, (float *) &m_pSurfaceObj->m_BoxAmbientColor);
  SurfaceTripleColorWidget->setColor(2, (float *) &m_pSurfaceObj->m_SurfaceSpecularColor);
  SurfaceTripleColorWidget->setColor(1, (float *) &m_pSurfaceObj->m_SurfaceDiffuseColor);
  SurfaceTripleColorWidget->setColor(0, (float *) &m_pSurfaceObj->m_SurfaceAmbientColor);

  PerspectiveCheckBox->setChecked(m_pSurfaceObj->m_Options & OPTION_PERSPECTIVE);
  BoxCheckBox->setChecked(m_pSurfaceObj->m_Options & OPTION_BOUNDINGBOX);
  SignModeCheckBox->setChecked(m_pSurfaceObj->m_Options & OPTION_SIGN);

  WidthLineEdit->setValidator(m_pIntValidator);
  WidthLineEdit->setText(QString::number(m_pSurfaceObj->m_Width));
  HeightLineEdit->setValidator(m_pIntValidator);
  HeightLineEdit->setText(QString::number(m_pSurfaceObj->m_Height));

  GLPreview->setObj(m_pSurfaceObj);
  GLPreview->updateGL();

  // Slot connections
  connect( BackgroundColorWidget , SIGNAL(Changed()),
           this                  , SLOT(BackgroundColor()) );
  connect( BoxTripleColorWidget , SIGNAL(Changed(int)),
           this                 , SLOT(BoxColor(int))   );
  connect( SurfaceTripleColorWidget , SIGNAL(Changed(int)),
           this                     , SLOT(SurfaceColor(int))   );

  connect( SignIncLineEdit    , SIGNAL(textChanged(const QString&)),
           this               , SLOT(SignInc(const QString&))       );
  connect( NoSignIncLineEdit  , SIGNAL(textChanged(const QString&)),
           this               , SLOT(NoSignInc(const QString&))     );
  connect( NoSignPrecLineEdit , SIGNAL(textChanged(const QString&)),
           this               , SLOT(NoSignPrec(const QString&))    );
  connect( ZoomLineEdit       , SIGNAL(textChanged(const QString&)),
           this               , SLOT(Zoom(const QString&))          );
  connect( WidthLineEdit      , SIGNAL(textChanged(const QString&)),
           this               , SLOT(Width(const QString&))         );
  connect( HeightLineEdit     , SIGNAL(textChanged(const QString&)),
           this               , SLOT(Height(const QString&))        );

  connect( XminLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( YminLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( ZminLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( XmaxLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( YmaxLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( ZmaxLineEdit , SIGNAL(textChanged(const QString&)),
           this         , SLOT(ViewingVolume())               );
  connect( XviewerLineEdit , SIGNAL(textChanged(const QString&)),
           this            , SLOT(ViewingVolume())               );
  connect( YviewerLineEdit , SIGNAL(textChanged(const QString&)),
           this            , SLOT(ViewingVolume())               );
  connect( ZviewerLineEdit , SIGNAL(textChanged(const QString&)),
           this            , SLOT(ViewingVolume())               );
  connect( XlightLineEdit , SIGNAL(textChanged(const QString&)),
           this           , SLOT(ViewingVolume())               );
  connect( YlightLineEdit , SIGNAL(textChanged(const QString&)),
           this           , SLOT(ViewingVolume())               );
  connect( ZlightLineEdit , SIGNAL(textChanged(const QString&)),
           this           , SLOT(ViewingVolume())               );

  connect( OptionsButtonGroup , SIGNAL(clicked(int)),
           this               , SLOT(Options())      );

  connect( EquationLineEdit , SIGNAL(returnPressed()) ,
           this             , SLOT(CheckEquation())    );
  connect( EquationLineEdit , SIGNAL(lostFocus())     ,
           this             , SLOT(CheckEquation())    );

  connect( GLPreview , SIGNAL(UpdatedVectorBase()) ,
           this      , SLOT(UpdateVectorBase())      );
}

void SettingsForm::destroy()
{
  if (m_pIntValidator)
    delete m_pIntValidator;
  if (m_pPositiveDoubleValidator)  
    delete m_pPositiveDoubleValidator;
  if (m_pDoubleValidator)
    delete m_pDoubleValidator;
  if (m_pSurfaceObj)
    delete m_pSurfaceObj;
}


void SettingsForm::BackgroundColor()
{
  BackgroundColorWidget->getFloatColor((float *) &m_pSurfaceObj->m_BackgroundColor);
  GLPreview->updateGL();
}


void SettingsForm::BoxColor( int component )
{
  switch (component)
    {
    case (0):
      BoxTripleColorWidget->
        getFloatColor(component, (float *) &m_pSurfaceObj->m_BoxAmbientColor);
      break;
    case (1):
      BoxTripleColorWidget->
        getFloatColor(component, (float *) &m_pSurfaceObj->m_BoxDiffuseColor);
      break;
    case (2):
      BoxTripleColorWidget->
        getFloatColor(component, (float *) &m_pSurfaceObj->m_BoxSpecularColor);
      break;
    }
  GLPreview->updateGL();
}


void SettingsForm::SurfaceColor( int component )
{
  switch (component)
    {
    case (0):
      SurfaceTripleColorWidget->
        getFloatColor(component, (float *) &m_pSurfaceObj->m_SurfaceAmbientColor);
      break;
    case (1):
      SurfaceTripleColorWidget->
        getFloatColor(component ,(float *) &m_pSurfaceObj->m_SurfaceDiffuseColor);
      break;
    case (2):
      SurfaceTripleColorWidget->
        getFloatColor(component, (float *) &m_pSurfaceObj->m_SurfaceSpecularColor);
      break;
    }
  GLPreview->updateGL();
}


void SettingsForm::SignInc(const QString& text)
{
  m_pSurfaceObj->m_SignIncrement = text.toFloat();
  GLPreview->updateGL();
}


void SettingsForm::NoSignInc(const QString& text)
{
  m_pSurfaceObj->m_NoSignIncrement = text.toFloat();
  GLPreview->updateGL();
}


void SettingsForm::NoSignPrec(const QString& text)
{
  m_pSurfaceObj->m_NoSignPrecision = text.toFloat();
  GLPreview->updateGL();
}


void SettingsForm::Zoom(const QString& text)
{
  m_pSurfaceObj->m_Zoom = text.toFloat();
  GLPreview->updateGL();
}


void SettingsForm::Width(const QString& text)
{
  m_pSurfaceObj->m_Width = text.toInt();
}


void SettingsForm::Height(const QString& text)
{
  m_pSurfaceObj->m_Height = text.toInt();
}


void SettingsForm::ViewingVolume()
{
  m_pSurfaceObj->m_MinVector.x = XminLineEdit->text().toFloat();
  m_pSurfaceObj->m_MinVector.y = YminLineEdit->text().toFloat();
  m_pSurfaceObj->m_MinVector.z = ZminLineEdit->text().toFloat();

  m_pSurfaceObj->m_MaxVector.x = XmaxLineEdit->text().toFloat();
  m_pSurfaceObj->m_MaxVector.y = YmaxLineEdit->text().toFloat();
  m_pSurfaceObj->m_MaxVector.z = ZmaxLineEdit->text().toFloat();

  m_pSurfaceObj->m_ViewerPos.x = XviewerLineEdit->text().toFloat();
  m_pSurfaceObj->m_ViewerPos.y = YviewerLineEdit->text().toFloat();
  m_pSurfaceObj->m_ViewerPos.z = ZviewerLineEdit->text().toFloat();

  m_pSurfaceObj->m_LightDirection.x = XlightLineEdit->text().toFloat();
  m_pSurfaceObj->m_LightDirection.y = YlightLineEdit->text().toFloat();
  m_pSurfaceObj->m_LightDirection.z = ZlightLineEdit->text().toFloat();

  m_pSurfaceObj->Update();
  GLPreview->updateGL();
}


void SettingsForm::Options()
{
  m_pSurfaceObj->m_Options =
    (PerspectiveCheckBox->isChecked() ? OPTION_PERSPECTIVE    : 0) |
    (BoxCheckBox        ->isChecked() ? OPTION_BOUNDINGBOX    : 0) |
    (SignModeCheckBox   ->isChecked() ? OPTION_SIGN           : 0) |
    (OpenGLCheckBox     ->isChecked() ? OPTION_OPENGLSPECULAR : 0);
  GLPreview->updateGL();
}


void SettingsForm::Run()
{
  BackgroundColor();
  BoxColor(0);
  BoxColor(1);
  BoxColor(2);
  SurfaceColor(0);
  SurfaceColor(1);
  SurfaceColor(2);
  Zoom(ZoomLineEdit->text());
  ViewingVolume();
  Options();
  CheckEquation();

  std::string strParameterCheck = m_pSurfaceObj->Validate();
  if (strParameterCheck != "")
    {
      QMessageBox::warning( this, "Parameter error",
                            strParameterCheck.c_str(),
                            QMessageBox::Ok,
                            QMessageBox::NoButton,
                            QMessageBox::NoButton );
      return;
    }

  if (FileNameLineEdit->text().isEmpty())
    {
      QMessageBox::information( this, "Invalid file name",
                                "The name of the output file can't be empty",
                                QMessageBox::Ok);
      return;
    }

  if (QFile::exists(FileNameLineEdit->text()))
    {
      if (QMessageBox::question( this, "File exists",
                                 "A file with the same name as the output "
                                 "file already exists.  Overwrite?",
                                 QMessageBox::Yes,
                                 QMessageBox::No,
                                 QMessageBox::Cancel)
          != QMessageBox::Yes)
        return;
    }

  CProgressDialog *ProgressDialog =
    new CProgressDialog(*m_pSurfaceObj,
                        FileNameLineEdit->text(),
                        "Progress",
                        "Cancel",
                        101);

  connect( ProgressDialog , SIGNAL(canceled(CProgressDialog *)), 
           this           , SLOT(DeleteDialog(CProgressDialog *)));

  ProgressDialog->show();
}


void SettingsForm::DeleteDialog( CProgressDialog * p)
{
  if (p)
    delete p;
}


void SettingsForm::CheckEquation()
{
  int Value[2] = {0, 0};
  std::string tmpEquation = EquationLineEdit->text().ascii();
  if (!CMathExpression::Validate(tmpEquation, Value))
    EquationLineEdit->setSelection(Value[0], Value[1]);

  m_pSurfaceObj->m_FormulaString = tmpEquation;
}


void SettingsForm::ChooseFile()
{
  QString FileName = QFileDialog::getSaveFileName(QString::null,
                                                  "BMP files (*.bmp)",
                                                  this,
                                                  "0",
                                                  "Choose output file");

  if (FileName != QString::null)
    FileNameLineEdit->setText(FileName);
}


void SettingsForm::UpdateVectorBase()
{  
  XviewerLineEdit->blockSignals(true);
  XviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.x));
  XviewerLineEdit->blockSignals(false);

  YviewerLineEdit->blockSignals(true);
  YviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.y));
  YviewerLineEdit->blockSignals(false);

  ZviewerLineEdit->blockSignals(true);
  ZviewerLineEdit->setText(QString::number(m_pSurfaceObj->m_ViewerPos.z));  
  ZviewerLineEdit->blockSignals(false);
}
