/***************************************************************************
**
**  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-13
**  Copyright: 2008-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QAction>
#include <QLabel>
#include <QSlider>
#include <QHBoxLayout>

#include <QGpCoreTools.h>
#include <QGpGuiTools.h>
#include "ModelSlider.h"
#include "ModelSliderEditor.h"

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

  Full description of class still missing
*/

const QString ModelSlider::xmlModelSliderTag="ModelSlider";

/*!
  Description of constructor still missing
*/
ModelSlider::ModelSlider(QWidget * parent)
    : QWidget(parent)
{
  TRACE;

  _referenceModel=0;
  _codeContext=0;

  QAction * a=new QAction(tr( "Edit" ), this);
  connect(a, SIGNAL(triggered()), this, SLOT(edit()) );
  addAction(a);

  setContextMenuPolicy(Qt::ActionsContextMenu);

  QHBoxLayout * layout=new QHBoxLayout(this);
  _titleWidget=new QLabel(this);
  layout->addWidget(_titleWidget);
  _sliderWidget=new QSlider(this);
  _sliderWidget->setOrientation(Qt::Horizontal);
  _sliderWidget->setMinimum(0);
  _sliderWidget->setMaximum(100);
  layout->addWidget(_sliderWidget);
  connect(_sliderWidget, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged()));
}

/*!
  Description of destructor still missing
*/
ModelSlider::~ModelSlider()
{
  TRACE;
  qDeleteAll(_codeActions);
  delete _codeContext;
}

void ModelSlider::setReferenceModel(GeophysicalModel * m)
{
  TRACE;
  if(m) {
    _referenceModel=m;
    delete _codeContext;
    _codeContext=_referenceModel->expressionContext();
    if(_code.isEmpty()) {
      _code+="/*\n"
             "Model parameters:\n"+
             _codeContext->helpCode()+
             "Slider parameter:\n"
             "   p      Current slider value between 0 and 1\n"
             "*/\n";
    } else {
      ExpressionParser pEngine;
      qDeleteAll(_codeActions);
      _codeActions=pEngine.parse(_code, _codeContext);
    }
    sliderChanged();
  }
}

void ModelSlider::setTitle(const QString& t)
{
  TRACE;
  _titleWidget->setText(t);
}

QString ModelSlider::title() const
{
  TRACE;
  return _titleWidget->text();
}

void ModelSlider::setCode(const QString& c)
{
  TRACE;
  _code=c;
  if(_referenceModel) {
    ExpressionParser pEngine;
    qDeleteAll(_codeActions);
    _codeActions=pEngine.parse(_code, _codeContext);
    // Debug purpose ...
    /*for(int i=0;i<_codeActions.count();i++) {
      _codeActions.at(i)->xml_saveFile(QString("/home/mwathele/debugaction-%1.xml").arg(i));
    }*/
    sliderChanged();
  }
}

void ModelSlider::edit()
{
  TRACE;
  ModelSliderEditor * d=new ModelSliderEditor(this);
  Settings::getWidget(d);
  d->setTitle(_titleWidget->text());
  d->setCode(_code);
  if(d->exec()==QDialog::Accepted) {
    Settings::setWidget(d);
    setCode(d->code());
    setTitle(d->title());
  }
  delete d;
}

void ModelSlider::sliderChanged()
{
  TRACE;
  if(_codeActions.isEmpty()) {
    App::log(tr("model slider: no code defined\n") );
  } else if(!_referenceModel || _referenceModel->isEmpty()) {
    App::log(tr("model slider: no layers in reference model\n") );
  } else {
    if(modify( _referenceModel, _sliderWidget->value()*0.01) ) {
      emit modelChanged(_referenceModel);
    }
  }
}

bool ModelSlider::modify(GeophysicalModel * m, double p)
{
  TRACE;
  if(_codeActions.isEmpty()) return false;
  _codeContext->addVariable("p", p);
  _codeContext->setModel(m);
  for(ExpressionActions::iterator ita=_codeActions.begin();ita!=_codeActions.end();++ita) {
    (*ita)->value();
  }
  return m->isValid();
}

void ModelSlider::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
{
  TRACE;
  Q_UNUSED(context)
  writeProperty(s, "title", title());
  writeProperty(s, "code", code());
}

XMLMember ModelSlider::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  if(tag=="title" ) return XMLMember(0);
  else if(tag=="code" ) return XMLMember(1);
  return XMLMember(XMLMember::Unknown);
}

bool ModelSlider::xml_setProperty(XML_SETPROPERTY_ARGS)
{
  TRACE;
  Q_UNUSED(tag)
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  switch (memberID) {
  case 0: setTitle(content.toString()); return true;
  case 1: setCode(content.toString()); return true;
  default: return false;
  }
}
