/***************************************************************************
**
**  This file is part of gplivemodel.
**
**  gplivemodel is free software: you can redistribute it and/or modify
**  it under the terms of the GNU General Public License as published by
**  the Free Software Foundation, either version 3 of the License, or
**  (at your option) any later version.
**
**  gplivemodel 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 General Public License
**  along with Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2008-10-15
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QWhatsThis>
#include <QDesktopServices>
#include <QTextStream>
#include <QUrl>

#include <QGpCoreWave.h>
#include <QGpGuiTools.h>
#include "MainWindow.h"
#include "Results.h"
#include "ResultsThread.h"
#include "ControlPanel.h"
#include "CurvesThread.h"
#include "ModelSlider.h"

/*!
  \class MainWindow MainWindow.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

/*!
  Description of constructor still missing
*/
MainWindow::MainWindow(QWidget * parent)
    : QMainWindow(parent)
{
  TRACE;
  setAttribute(Qt::WA_DeleteOnClose, false);

  _templateModel=0;
  _results=new Results(this);
  setCentralWidget(_results);

  _backgroundModels=new QPlainTextEdit(this);
  _backgroundModels->setLineWrapMode(QPlainTextEdit::NoWrap);
  connect(_backgroundModels, SIGNAL(textChanged()), this, SLOT(setBackground()) );

  DockWidget * dockBg=new DockWidget(this);
  connect(dockBg, SIGNAL(hidden()), this, SLOT(setToolsMenuState()), Qt::QueuedConnection);
  dockBg->setObjectName( "BackgroundModels" );
  dockBg->setWindowTitle(tr("Background models"));
  dockBg->setFeatures (QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);
  dockBg->setAllowedAreas(Qt::AllDockWidgetAreas);
  dockBg->setWidget(_backgroundModels);
  addDockWidget(Qt::BottomDockWidgetArea, dockBg);

  _referenceModel=new QPlainTextEdit(this);
  _referenceModel->setLineWrapMode(QPlainTextEdit::NoWrap);
  connect(_referenceModel, SIGNAL(textChanged()), this, SLOT(setReferenceModel()) );

  DockWidget * dockRef=new DockWidget(this);
  connect(dockRef, SIGNAL(hidden()), this, SLOT(setToolsMenuState()), Qt::QueuedConnection);
  dockRef->setObjectName( "ReferenceModel" );
  dockRef->setWindowTitle(tr("Reference model"));
  dockRef->setFeatures (QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);
  dockRef->setAllowedAreas(Qt::AllDockWidgetAreas);
  dockRef->setWidget(_referenceModel);
  addDockWidget(Qt::BottomDockWidgetArea, dockRef);
  tabifyDockWidget(dockBg, dockRef);

  _foregroundModel=new QPlainTextEdit(this);
  _foregroundModel->setLineWrapMode(QPlainTextEdit::NoWrap);
  _foregroundModel->setReadOnly(true);

  DockWidget * dockFg=new DockWidget(this);
  connect(dockFg, SIGNAL(hidden()), this, SLOT(setToolsMenuState()), Qt::QueuedConnection);
  dockFg->setObjectName( "ForegroundModel" );
  dockFg->setWindowTitle(tr("Foreground model"));
  dockFg->setFeatures (QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);
  dockFg->setAllowedAreas(Qt::AllDockWidgetAreas);
  dockFg->setWidget(_foregroundModel);
  addDockWidget(Qt::BottomDockWidgetArea, dockFg);
  tabifyDockWidget(dockRef, dockFg);

  _controlPanel=new ControlPanel(this);
  connect(_controlPanel, SIGNAL(modelChanged(GeophysicalModel * )), this, SLOT(setForeground(GeophysicalModel *)) );

  DockWidget * dockCp=new DockWidget(this);
  connect(dockCp, SIGNAL(hidden()), this, SLOT(setToolsMenuState()), Qt::QueuedConnection);
  dockCp->setObjectName( "ControlPanel" );
  dockCp->setWindowTitle(tr("Control Panel"));
  dockCp->setFeatures (QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);
  dockCp->setAllowedAreas(Qt::AllDockWidgetAreas);
  dockCp->setWidget(_controlPanel);
  addDockWidget(Qt::BottomDockWidgetArea, dockCp);

  addActions();
}

/*!
  Description of destructor still missing
*/
MainWindow::~MainWindow()
{
  TRACE;
}

void MainWindow::loadPanel(QString fileName)
{
  TRACE;
  _controlPanel->load(fileName);
}

int MainWindow::scan(GeophysicalModel * m, QString sliderName, int nSteps)
{
  TRACE;
  ModelSlider * slider=_controlPanel->slider(sliderName);
  nSteps--;
  double fac=1.0/(double)nSteps;
  CurvesThread * calc=qobject_cast<CurvesThread *>(_results->calculator());
  if(!calc) {
    App::log(tr("Only curve types are accepted for scan: e.g. dispersion, ellipticity,...\n") );
    return 2;
  }
  QTextStream sOut(stdout);
  for(int i=0; i<=nSteps; i++) {
    if( !slider->modify(m, i*fac) ) {
      App::log(tr("Bad model generated\n") );
      return 2;
    }
    calc->run(m);
    sOut << tr("# p=%1").arg(i*fac) << endl;
    QList< Curve<Point2D> > cList=calc->curves();
    for(QList< Curve<Point2D> >::const_iterator it=cList.begin(); it!= cList.end(); it++ ) {
      sOut << it->toString();
    }
  }
  return 0;
}

void MainWindow::setBackground()
{
  TRACE;
  QString str=_backgroundModels->toPlainText();
  GeophysicalModel * m;
  QTextStream s(&str);
  _results->clearBackground();
  int n=0;
  while(!s.atEnd()) {
    m=_results->createModel();
    if(!m->fromStream(s)) {
      App::log(tr("Error parsing background models\n") );
      delete m;
      return;
    }
    if(!m->isEmpty()) {
      _results->addBackground(m);
      n++;
    }
  }
  App::log(tr("%1 background model(s)\n").arg(n) );
  _results->calculateBackground();
}

void MainWindow::setReferenceModel()
{
  TRACE;
  QString str=_referenceModel->toPlainText();
  GeophysicalModel * m=_results->createModel();
  QTextStream s(&str);
  if(!m->fromStream(s)) {
    App::log(tr("Error parsing foreground model\n") );
    delete m;
    return;
  }
  if(!m->isEmpty()) {
    _controlPanel->setReferenceModel(m);
  }
}

void MainWindow::setForeground(GeophysicalModel * m)
{
  TRACE;
  _results->setForeground(m->clone());
  QString mText;
  QTextStream s(&mText);
  m->toStream(s);
  _foregroundModel->setPlainText(mText);
}

void MainWindow::addBackground(GeophysicalModel * m, QString comments)
{
  TRACE;
  _backgroundModels->blockSignals(true);
  if(!comments.isEmpty()) {
    if(comments.right(1)=="\n") comments.chop(1);
    _backgroundModels->appendPlainText(comments);
  }
  QString mText;
  QTextStream s(&mText);
  m->toStream(s);
  _backgroundModels->appendPlainText(mText);
  _backgroundModels->blockSignals(false);
  _results->addBackground(m);
}

void MainWindow::addActions()
{
  TRACE;
  QAction * a;
  QMenu * m;

  // File menu
  m=new QMenu(this);
  m->setTitle(tr( "&File" ));
  _results->addFileActions(m, 0);

  a=new QAction(tr( "&Quit" ), this);
  connect(a, SIGNAL(triggered()), this, SLOT(quit()) );
  m->addAction(a);
  menuBar()->addMenu(m);
  _results->addMenu(m);

  // Edit menu
  m=new QMenu(this);
  m->setTitle(tr( "&Edit" ));
  _results->addEditActions(m, 0);
  menuBar()->addMenu(m);
  _results->addMenu(m);

  // Insert menu
  m=new QMenu(this);
  m->setTitle(tr( "&Insert" ));
  _results->addInsertActions(m, 0);
  menuBar()->addMenu(m);
  _results->addMenu(m);

  // Format menu
  m=new QMenu(this);
  m->setTitle(tr( "&Format" ));
  _results->addFormatActions(m);

  a=new QAction(tr( "Automatic limits" ), this);
  a->setStatusTip(tr( "Switch on/off automatic adjustment of graph limits" ));
  a->setCheckable(true);
  a->setChecked(true);
  connect(a, SIGNAL(toggled(bool)), _results, SLOT(setAutomaticLimits(bool)) );
  m->addAction(a);
  menuBar()->addMenu(m);
  _results->addMenu(m);

  addToolsActions();
  addHelpActions();
}

void MainWindow::addToolsActions()
{
  TRACE;
  QAction * a;
  QMenu * m;

  m=menuBar() ->addMenu(tr( "&Tools" ));
  m->setTearOffEnabled (true);
  _toolsMenu=m;

  QList<DockWidget *> dockwidgetList=findChildren<DockWidget *>();
  for(QList<DockWidget *>::iterator it=dockwidgetList.begin();it!=dockwidgetList.end();++it) {
    a=new QAction(( *it) ->windowTitle(), this);
    QByteArray wPtr(( const char * ) & ( *it), sizeof(DockWidget * ));
    a->setData(wPtr);
    a->setCheckable(true);
    connect(a, SIGNAL(toggled( bool) ), *it, SLOT(setVisible( bool) ));
    m->addAction(a);
  }

  /*m->addSeparator();

  QList<QToolBar *> toolBarList=findChildren<QToolBar *>();
  for(QList<QToolBar *>::iterator it=toolBarList.begin();it!=toolBarList.end();++it) {
    a=new QAction(( *it) ->windowTitle(), this);
    QByteArray wPtr(( const char * ) & ( *it), sizeof(QToolBar * ));
    a->setData(wPtr);
    a->setCheckable(true);
    connect(a, SIGNAL(toggled( bool) ), *it, SLOT(setVisible( bool) ));
    m->addAction(a);
  }*/
}

void MainWindow::addHelpActions()
{
  TRACE;
  QAction * a;
  QMenu * m;

  m=menuBar() ->addMenu(tr( "&Help" ));
  m->setTearOffEnabled (true);

  a=new QAction(tr( "Online gplivemodel &Documentation" ), this);
  a->setShortcut(tr( "F1" ));
  a->setStatusTip(tr( "Access to online html documentation" ));
  connect(a, SIGNAL(triggered()), this, SLOT(helpDocumentation()) );
  m->addAction(a);

  a=QWhatsThis::createAction(this);
  m->addAction(a);

  m->addSeparator();

  a=new QAction(tr( "&About" ), this);
  a->setStatusTip(tr( "Show gplivemodel's About box" ));
  connect(a, SIGNAL(triggered()), this, SLOT(helpAbout()) );
  m->addAction(a);

  a=new QAction(tr( "About &Qt" ), this);
  a->setStatusTip(tr( "Show the Qt library's About box" ));
  connect(a, SIGNAL(triggered()), qApp, SLOT(aboutQt()) );
  m->addAction(a);
}

/*!
  Set the state of one particular tool if the sender is a DockWidget. DockWidget emit a signal every time the user click on the
  close box. If the function is called without signal/slot, all states are checked.
*/
void MainWindow::setToolsMenuState()
{
  TRACE;
  DockWidget * w=qobject_cast<DockWidget *>(sender());
  QList<QAction *> aList=_toolsMenu->actions();
  int n=aList.count();
  if(w) {
    for(int i=0;i < n;i++ ) {
      QAction * a=aList.at(i);
      if(w==*reinterpret_cast<DockWidget **>(a->data().toByteArray().data())) {
        a->setChecked(w->isVisible());
      }
    }
  } else {
    for(int i=0;i < n;i++ ) {
      QAction * a=aList.at(i);
      if(!a->isSeparator()) {
        w=*reinterpret_cast<DockWidget **>(a->data().toByteArray().data());
        a->setChecked(w->isVisible());
      }
    }
  }
}

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

void MainWindow::quit()
{
  TRACE;
  qApp->quit();
}

void MainWindow::helpDocumentation()
{
  TRACE;
  QDesktopServices::openUrl(QUrl("http://www.geopsy.org/documentation/gplivemodel/index.html"));
}

void MainWindow::helpAbout()
{
  TRACE;
  //DinverGuiAboutDialog * d=new DinverGuiAboutDialog(this);
  //d->exec();
  //delete d;
}
