/***************************************************************************
**
**  This file is part of dinvermatlab.
**
**  This file is distributed under the terms of the Geopsy.org Commercial
**  License appearing in the file LICENSE.COMMERCIAL included in the packaging
**  of this file.
**
**  This file 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 Geopsy.org Commercial License for
**  more details.
**
**  You should have received a copy of the Geopsy.org Commercial License
**  along with this program. If not, see <http://www.geopsy.org>.
**
**  See http://www.geopsy.org for more information.
**
**  Created : 2008-11-23
**  Authors :
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QtPlugin>

#include <DinverCore.h>
#include <DinverGui.h>

#include "MatlabPlugin.h"
#include "MatlabTargetWidget.h"
#include "MatlabTarget.h"
#include "Forward.h"
#include "dinvermatlabVersion.h"

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

  Full description of class still missing
*/

MatlabPlugin::MatlabPlugin()
{
  _paramWidget=0;
  _targetWidget=0;
  _param=0;
  _target=0;
}

MatlabPlugin::~MatlabPlugin()
{
  delete _param;
  delete _target;
}

DinverInterface * MatlabPlugin::clone()
{
  TRACE;
  return new MatlabPlugin;
}

/*!
  Unique tag to identify in .report files models generated by this plugin.
*/
QString MatlabPlugin::tag() const
{
  TRACE;
  return "DinverMatlab";
}

/*!
  User friendly title, displayed at Dinver startup.
*/
QString MatlabPlugin::title() const
{
  TRACE;
  return tr("Matlab forward computation");
}

QString MatlabPlugin::version() const
{
  TRACE;
  return DINVERMATLAB_VERSION;
}

QWidget * MatlabPlugin::createParamWidget()
{
  TRACE;
  _paramWidget=new ParamSpaceEditor;
  connect(_paramWidget, SIGNAL(check()), this, SLOT(checkScript()));
  return _paramWidget;
}

QWidget * MatlabPlugin::createTargetWidget()
{
  TRACE;
  _targetWidget=new MatlabTargetWidget;
  return _targetWidget;
}

void MatlabPlugin::checkScript()
{
  TRACE;
  ParamSpaceScript * s=_paramWidget->script();
  Forward testInv;
  if(s->apply(&testInv.parameterSpace()) ) {
    testInv.parameterSpace().humanInfo();
  }
  delete s;
}

void MatlabPlugin::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(dinverContext->targets()) {
    MatlabTarget * t=_targetWidget->target();
    t->xml_save(s, context);
    delete t;
  }
  if(dinverContext->parameters()) {
    ParamSpaceScript * p=_paramWidget->script();
    p->xml_save(s, context);
    delete p;
  }
}

XMLMember MatlabPlugin::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(tag=="MatlabTarget" ) {
    if(dinverContext->targets()) {
      if(_targetWidget) {
        return XMLMember(new MatlabTarget, true);
      } else {
        delete _target;
        _target=new MatlabTarget;
        return XMLMember(_target);
      }
    } else {
      return XMLMember(XMLMember::Skip);
    }
  } else if(tag=="ParamSpaceScript") {
    if(dinverContext->parameters()) {
      if(_paramWidget) {
        return XMLMember(new ParamSpaceScript, true);
      } else {
        delete _param;
        _param=new ParamSpaceScript;
        return XMLMember(_param);
      }
    } else {
      return XMLMember(XMLMember::Skip);
    }
  } else return XMLMember(XMLMember::Unknown);
}

bool MatlabPlugin::xml_polishChild(XML_POLISHCHILD_ARGS)
{
  TRACE;
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(dinverContext->targets() && child->xml_tagName()=="MatlabTarget") {
    if(_targetWidget) {
      _targetWidget->setFrom(static_cast<MatlabTarget *>(child));
    }
    return true;
  } else if(dinverContext->parameters() && child->xml_tagName()=="ParamSpaceScript") {
    if(_paramWidget) {
      _paramWidget->setFrom(static_cast<ParamSpaceScript *>(child));
    }
    return true;
  } else
    return false;
}

/*!
  More explanations about the inversion plugin, displayed in Tooltips at Dinver startup.
*/
QString MatlabPlugin::description() const
{
  TRACE;
  return tr("<p>With this plugin you can build your own parameterization<br/>"
            "within the graphical interface and use a Matlab script<br/>"
            "to calculate the misfit function.</p>");
}

/*!
  Creates the forward object
*/
AbstractForward * MatlabPlugin::createForward()
{
  TRACE;
  return new Forward;
}

/*!
  Initializes the forward object
*/
bool MatlabPlugin::initForward(AbstractForward * forward)
{
  TRACE;
  ParamSpaceScript * param;
  if(_paramWidget) {
    param=_paramWidget->script();
  } else {
    param=new ParamSpaceScript(*_param);
  }
  MatlabTarget * target;
  if(_targetWidget) {
    target=_targetWidget->target();
  } else if(_target) {
    target=new MatlabTarget(*_target);
  } else {
    target=new MatlabTarget;
  }
  Forward * f=static_cast<Forward *>(forward);
  if( !f->setParam(param) ) {
      App::log(tr("Error building parameter space, see above messages\n") );
      return false;
    }
  if( !f->setTarget(target, false)) {
    App::log(tr("Error setting target, see above messages\n") );
    return false;
  }
  return true;
}


void MatlabPlugin::setCurrentForward(AbstractForward * forward, const QString& )
{
  TRACE;
  if(forward) {
    if(!_param) {
      // Means that last list of forwards was null or contained more than 1 forward
      // Hence the main global parameterization and target are currently active
      // Save them before showing a particular case
      ASSERT(!_target);
      _param=_paramWidget->script();
      _target=_targetWidget->target();
    }
    Forward * f=static_cast<Forward *>(forward);
    _paramWidget->setFrom(f->parameters());
    _paramWidget->setEditable(false);
    _targetWidget->setEditable(false);
    _targetWidget->setFrom(f->target());
    //_importTargetAction->setEnabled(false);
    //_importParamAction->setEnabled(false);
  } else if(_param) {
    ASSERT(_target);
    _paramWidget->setFrom(_param);
    _paramWidget->setEditable(true);
    _targetWidget->setFrom(_target);
    _targetWidget->setEditable(true);
    //_importTargetAction->setEnabled(true);
    //_importParamAction->setEnabled(true);
    delete _param;
    delete _target;
    _param=0;
    _target=0;
  }
}

PACKAGE_INFO("dinvermatlab", DINVERMATLAB)
#if(QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_EXPORT_PLUGIN2(dinvermatlab, MatlabPlugin)
#endif
