/***************************************************************************
**
**  This file is part of dinver.
**
**  dinver 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.
**
**  dinver 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: 2005-11-06
**  Copyright: 2005-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <DinverCore.h>
#include <QGpGuiTools.h>

#include "PluginSelector.h"
#include "PluginPaths.h"
#include "dinverVersion.h"

const char * PluginSelector::_noticeContents =
  QT_TRANSLATE_NOOP(
    "PluginSelector", "<p>Dinver is a framework for inversion problems. The core engine is a "
    "Neighbourhood Algorithm originally proposed by Sambridge (1999), implemented in C++ "
    "and improved by <a href=\"http://www.geopsy.org/#References\">Wathelet(2008)</a>.</p>"
    "<p>Each specific inversion problem can be coded with a simple API and packaged in a "
    "dynamic library (plugin).</p>"
    "<p>Using, Copying and Modifying this program is granted to everyone under the terms "
    "of the GNU Public License version 3. <b>However, we would appreciate that you properly "
    "reference this work, released for free, in all your publications or reports achieved "
    "with this software.</b></p>" );

QString dinverDLLDir();


PluginSelector::PluginSelector(QWidget * parent, bool debug)
    : Dialog(parent), _debug(debug)
{
  TRACE;
  setupUi(this);

  dinverNotice->setHtml(QApplication::translate("PluginSelector", _noticeContents));
  DinverPluginSettings reg;
  if(!reg.hasPluginList()) {
    setLibList(File::getLibList(DinverCoreEngine::defaultPluginPaths()));
  } else {
    if(!setLibList(reg.pluginList())) {
      printf("Detected wrong dinvercore interface version reset to default\n");
      setLibList(File::getLibList(DinverCoreEngine::defaultPluginPaths()));
    }
  }
  QListWidgetItem * defItem=pluginList->item(reg.defaultPlugin());
  if(defItem) defItem->setCheckState(Qt::Checked);
}

PluginSelector::~PluginSelector()
{
  TRACE;
  DinverPluginSettings reg;
  reg.setPluginList(_pluginFileList);
}

void PluginSelector::on_searchPaths_clicked()
{
  TRACE;
  PluginPaths * d=new PluginPaths(this);
  Settings::getWidget(d);
  if(d->exec()==QDialog::Accepted) {
    Settings::setWidget(d);
    QStringList paths=d->getPaths();
    delete d;
    QApplication::processEvents();
    pluginList->clear();
    setLibList(File::getLibList(paths));
  } else delete d;
}

/*!
  Return false if one plugin has not the correct interface version. This is use to detect upgrades.
  In case of upgrade, the stored list of plugins must be redefined.
*/
bool PluginSelector::setLibList(QStringList libs)
{
  TRACE;
  _pluginFileList.clear();
  pluginList->clear();
  int n=libs.count();
  searchProgress->setMaximum(n);

  bool correctBuildKey=true;
  for(int i=0;i < n;i++ ) {
    QString libFile=libs.at(i);
    DinverInterface * dinverInstance=DinverCoreEngine::loadPlugin(libFile, _debug);
    searchProgress->setValue(i + 1);
    if(dinverInstance) {
      if(dinverInstance->isValid()) {
        QListWidgetItem * item=new QListWidgetItem(dinverInstance->title() + " - " + dinverInstance->version());
        item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
        item->setCheckState(Qt::Unchecked);
        item->setToolTip(dinverInstance->description());
        pluginList->addItem(item);
        _pluginFileList.append(libFile);
      } else {
        App::log(tr("%1 has not a compatible plugin interface version.\n").arg(libFile) );
        correctBuildKey=false;
      }
      CoreApplication::instance()->deletePlugin(dinverInstance);
    }
  }
  return correctBuildKey;
}

void PluginSelector::on_pluginList_itemChanged (QListWidgetItem * selItem)
{
  TRACE;
  pluginList->blockSignals(true);
  int n=pluginList->count();
  for(int i=0; i<n; i++) {
    QListWidgetItem * item=pluginList->item(i);
    if(item!=selItem) {
      item->setCheckState(Qt::Unchecked);
    }
  }
  pluginList->blockSignals(false);
}

QString PluginSelector::file() const
{
  TRACE;
  int n=pluginList->count();
  for(int i=0; i<n; i++) {
    if(pluginList->item(i)->checkState()==Qt::Checked) {
      DinverPluginSettings reg;
      reg.setDefaultPlugin(i);
      return _pluginFileList.at(i);
    }
  }
  return QString();
}
