/***************************************************************************
**
**  This file is part of dinverext.
**
**  dinverext 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.
**
**  dinverext 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: 2007-04-10
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <DinverGui.h>

#include "ExtPlugin.h"
#include "dinverextVersion.h"
#include "ExtTarget.h"
#include "ExtTargetWidget.h"
#include "Forward.h"

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

  Full description of class still missing
*/

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

ExtPlugin::~ExtPlugin()
{
  TRACE;
  delete _target;
  delete _param;
}

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

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

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

QString ExtPlugin::version() const
{
  TRACE;
  return DINVEREXT_VERSION;
}

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

QWidget * ExtPlugin::createTargetWidget()
{
  TRACE;
  _targetWidget=new ExtTargetWidget;
  return _targetWidget;
}

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

void ExtPlugin::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(dinverContext->targets()) {
    ExtTarget * 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 ExtPlugin::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(attributes)
  Q_UNUSED(context)
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(tag=="ExtTarget") {
    if(dinverContext->targets()) {
      if(_targetWidget) {
        return XMLMember(new ExtTarget, true);
      } else {
        delete _target;
        _target=new ExtTarget;
        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 ExtPlugin::xml_polishChild(XML_POLISHCHILD_ARGS)
{
  TRACE;
  XMLDinverContext * dinverContext=static_cast<XMLDinverContext *>(context);
  if(dinverContext->targets() && child->xml_tagName()=="ExtTarget") {
    if(_targetWidget) {
      _targetWidget->setFrom(static_cast<ExtTarget *>(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 ExtPlugin::description() const
{
  TRACE;
  return tr("<p>With this plugin you can build your own parameterization<br/>"
            "within the graphical interface and specify an external program<br/>"
            "to calculate the misfit function.</p>");
}

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

/*!
  Initializes the forward object
*/
bool ExtPlugin::initForward(AbstractForward * forward)
{
  TRACE;
  ParamSpaceScript * param;
  if(_paramWidget) {
    param=_paramWidget->script();
  } else {
    param=new ParamSpaceScript(*_param);
  }
  ExtTarget * target;
  if(_targetWidget) {
    target=_targetWidget->target();
  } else if(_target) {
    target=new ExtTarget(*_target);
  } else {
    target=new ExtTarget();
  }
  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) ) {
    App::log(tr("Error setting target, see above messages\n") );
    return false;
  }
  return true;
}

void ExtPlugin::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("dinverext", DINVEREXT)
#if(QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
Q_EXPORT_PLUGIN2(dinverext, ExtPlugin)
#endif
