/***************************************************************************
**
**  This file is part of GeopsyCore.
**
**  GeopsyCore 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.
**
**  GeopsyCore 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: 2010-08-04
**  Copyright: 2010-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "GeopsyPlugins.h"
#include "GeopsyCoreInterface.h"
#include "GeopsyPluginSettings.h"
#include "GeopsyCoreVersion.h"

namespace GeopsyCore {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  GeopsyPlugins::GeopsyPlugins(bool debug)
  {
    TRACE;
    GeopsyPluginSettings reg;
    if(debug || !reg.hasPluginList()) {
      init(debug);
    }
    if(!load()) {
      printf("Detected wrong interface version reset to default\n");
      // Clean all previously loaded plugins (there will be deleted by application)
      _list.clear();
      reg.clear();  // remove current paths and force default ones
      init(debug);
      load();
    }
  }

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

  /*!
    Actions to be executed after a complete initialization of GeopsyCoreEngine.
  */
  void GeopsyPlugins::polish()
  {
    TRACE;
    foreach(GeopsyCoreInterface * p, _list) {
      p->polish();
    }
  }

  /*!
    Return false is one or more plugins have the wrong interface version.
  */
  bool GeopsyPlugins::load()
  {
    TRACE;
    // Load all plugins
    GeopsyPluginSettings reg;
    bool correctInterfaceVersion=true;
    QStringList libs;
    if(!reg.hasPluginList()) { // In case all plugin were removed try to reload them auto
      init(false);
    }
    libs=reg.pluginList();
    for(QStringList::Iterator it=libs.begin();it!=libs.end();++it) {
      if(( *it).isEmpty()) { // Separator for menus and bar see GUI section
        _list.append(nullptr);
      } else {
        GeopsyCoreInterface * p=load(*it);
        if(p) {
          if(p->isValid()) {
            _list.append(p);
            CoreApplication::instance()->addPlugin(p);
          } else {
            printf("Wrong interface version for %s\n",(*it).toLatin1().data());
            correctInterfaceVersion=false;
            CoreApplication::instance()->deletePlugin(p);
          }
        }
      }
    }
    return correctInterfaceVersion;
  }

  /*!
    Set default directory to search paths and search for plugins
  */
  void GeopsyPlugins::init(bool debug)
  {
    TRACE;
    GeopsyPluginSettings reg;
    QStringList paths=reg.paths();
    if(paths.isEmpty()) {
      QString dll;
  #ifdef Q_OS_MAC
      dll=QString("/Library/Geopsy.org/%1/plugins").arg(GEOPSYCORE_VERSION_TYPE);
  #elif defined(Q_OS_WIN)
      dll=QCoreApplication::applicationDirPath();
  #else
      const PackageInfo * p=PackageInfo::package("GeopsyCore");
      if(p) { // can be null in case of static library
        dll=p->dllDir();
      }
  #endif
      App::log(1, tr("Adding default plugin path: %1\n").arg(dll));
      if(!dll.isEmpty()) {
        QDir d(dll);
        if(d.exists()) {
          paths << dll;
          reg.setPaths(paths);
        }
      }
    }
    QStringList libs=File::getLibList(paths);
    bool ok;
    QStringList plugins=getList(libs, ok, debug);
    reg.setPluginList(plugins);
  }

  /*!
    \a ok is set to false if plugins with wrong interface versions are detected.
  */
  QStringList GeopsyPlugins::getList(QStringList libs, bool& ok, bool debug)
  {
    TRACE;
    ok=true;
    QStringList plugins;
    int n=libs.count();
    if(n<=0) return plugins;
    /*QProgressDialog * d;
    if(Application::instance()->hasGui()) {
      d=new QProgressDialog(tr("Searching plugins ..."), QString(), 0, n-1,
                             QApplication::activeWindow());
    } else {
      d=0;
    }*/
    for(int i=0;i<n;i++) {
      //if(d) d->setValue(i);
      QString libFile=libs.at(i);
      if(libFile.isEmpty()) {
        plugins << "";
      } else {
        GeopsyCoreInterface * p=load(libFile, debug);
        if(p) {
          if(p->isValid()) {
            plugins << libFile;
          } else {
            App::log(tr("%1 has not a correct interface version.\n").arg(libFile) );
            ok=false;
          }
          CoreApplication::instance()->deletePlugin(p);
        }
      }
    }
    //delete d;
    return plugins;
  }

  GeopsyCoreInterface * GeopsyPlugins::load(QString pluginFile, bool debug)
  {
    TRACE;
    if(debug) {
      printf("Load library %s\n",pluginFile.toLatin1().data());
      fflush(stdout);
    }
    QPluginLoader pluginTest;
    pluginTest.setFileName(pluginFile);
    QObject * instance=pluginTest.instance();
    if(instance) {
      if(debug) {
        printf("  Library loaded successfully\n");
        fflush(stdout);
      }
      GeopsyCoreInterface * p=qobject_cast<GeopsyCoreInterface *>(instance);
      if(p) {
        if(debug) {
          printf("  Geopsy tool interface\n");
          printf("  Geopsy interface version=%s\n",p->interfaceVersion());
          fflush(stdout);
        }
        return p;
      }
    } else if(debug) {
      printf("  %s\n",pluginTest.errorString().toLatin1().data());
      fflush(stdout);
    }
    CoreApplication::instance()->deletePlugin(instance);
    return nullptr;
  }

} // namespace GeopsyCore
