/***************************************************************************
**
**  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: 2017-09-18
**  Copyright: 2017-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "CoreToolInterface.h"
#include "SignalDatabase.h"

namespace GeopsyCore {

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

    Full description of class still missing
  */

  /*!
    Generally a global object initialized before CoreApplication.
    If default outputFileName is something else than 'a.max',
    use setOuputFileName() before initializing CoreApplication
  */
  CoreToolInterface::CoreToolInterface()
  {
    TRACE;
    _param=nullptr;
  }

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

  void CoreToolInterface::setParameters(AbstractParameters * param)
  {
    TRACE;
    delete _param;
    _param=param;
  }

  bool CoreToolInterface::setOptions(int& argc, char ** argv)
  {
    App::setPrefix(CoreApplication::applicationName()+": ");
    CoreApplication::instance()->debugUserInterrupts(false);

    QString databaseFileName;
    QStringList groupPaths;
    QStringList groupPatterns;
    QList<int> groupIds;
    bool showGroups=false;

    int i, j = 1;
    for (i=1; i<argc; i++) {
      QByteArray arg = argv[i];
      if (arg[0]=='-') {
        if(arg=="-db") {
          CoreApplication::checkOptionArg(i, argc, argv);
          if(!databaseFileName.isEmpty()) {
            App::log(tr("only one option '-db' is allowed\n") );
            return false;
          }
          databaseFileName=argv[i];
        } else if(arg=="-no-file-key") {
          GeopsyCoreEngine::instance()->setFileContentKey(false);
        } else if(arg=="-groups") {
          showGroups=true;
        } else if(arg=="-group" || arg=="-group-path") {
          CoreApplication::checkOptionArg(i, argc, argv);
          groupPaths.append(argv[i]);
        } else if(arg=="-group-pattern") {
          CoreApplication::checkOptionArg(i, argc, argv);
          groupPatterns.append(argv[i]);
        } else if(arg=="-group-id") {
          CoreApplication::checkOptionArg(i, argc, argv);
          groupIds.append(atoi(argv[i]));
        } else if(arg=="-o") {
          CoreApplication::checkOptionArg(i, argc, argv);
          _outputBaseName=argv[i];
          if(!_outputBaseName.endsWith("-")) {
            _outputBaseName+="-";
          }
        } else if(arg=="-station-list") {
          CoreApplication::checkOptionArg(i, argc, argv);
          QString l(argv[i]);
          _stationList=l.split(QRegExp("[, ]"), QString::SkipEmptyParts);
        } else if(arg=="-param") {
          CoreApplication::checkOptionArg(i, argc, argv);
          if(!_param->load(argv[i], "# BEGIN PARAMETERS", "# END PARAMETERS")) {
            App::log(tr("error loading parameters from '%1', see '-param-example'\n").arg(argv[i]) );
            return false;
          }
        } else if(arg=="-set") {
          CoreApplication::checkOptionArg(i, argc, argv);
          if(!_param->parse(argv[i])) {
            App::log(tr("Error setting parameter '%1'.\n").arg(argv[i]) );
            return false;
          }
        } else if(arg=="-fix-signal-paths") {
          CoreApplication::instance()->setBatch(false);
          if(databaseFileName.isEmpty()) {
            App::log(tr("Option '-db' must be defined before '-fix-signal-path'.\n") );
            return false;
          }
          ::exit(fixDatabasePaths(databaseFileName) ? 0 : 2);
        } else {
          argv[j++]=argv[i];
        }
      } else {
        argv[j++]=argv[i];
      }
    }
    if(j<argc) {
      argv[j]=nullptr;
      argc=j;
    }

    if(databaseFileName.isEmpty()) {
      App::log(tr("no database specified, see -help\n") );
      return false;
    }
    SignalDatabase * db=GeopsyCoreEngine::instance()->defaultDatabase();
    if(!db->open(databaseFileName)) {
      return false;
    }
    if(showGroups) {
      db->masterGroup()->printList(QString());
      ::exit(0);
    }
    if(!groupIds.isEmpty()) {
      for(QList<int>::iterator it=groupIds.begin(); it!=groupIds.end(); it++) {
        AbstractSignalGroup * g=db->findGroup(*it);
        if(!g) {
          App::log(tr("group id %1 does not exist\n").arg(*it) );
          return false;
        }
        _groups.append(g->list());
      }
    }
    if(!groupPaths.isEmpty()) {
      for(QStringList::iterator it=groupPaths.begin(); it!=groupPaths.end(); it++) {
        AbstractSignalGroup * g=db->findGroup(*it);
        if(!g) {
          App::log(tr("group '%1' does not exist\n").arg(*it) );
          return false;
        }
        _groups.append(g->list());
      }
    }
    if(!groupPatterns.isEmpty()) {
      for(QStringList::iterator it=groupPatterns.begin(); it!=groupPatterns.end(); it++) {
        QList<const AbstractSignalGroup *> list=const_cast<const SignalDatabase *>(db)->findGroups(QRegExp(*it));
        if(list.isEmpty()) {
          App::log(tr("group pattern '%1' has no match\n").arg(*it) );
          return false;
        }
        _groups.append(list);
      }
    }
    if(_groups.isEmpty()) {
      if(!groupIds.isEmpty() ||
         !groupPaths.isEmpty() ||
         !groupPatterns.isEmpty()) {
        App::log(tr("Empty group selection\n") );
        return false;
      }
      _groups=db->masterGroup()->list();
    }
    App::log(tr("Selected groups:\n"));
    for(QList<const AbstractSignalGroup *>::iterator it=_groups.begin();
        it!=_groups.end(); it++) {
      App::log(tr("  '%1': %2 signals\n").arg((*it)->name()).arg((*it)->signalCount()) );
    }
    return true;
  }

  /*!
    Return subpool corresponding to group \a g. Excluded stations are removed from the returned subpool.
  */
  SubSignalPool CoreToolInterface::subPool(const AbstractSignalGroup * g) const
  {
    TRACE;
    SubSignalPool p;
    p.addGroup(g);
    if(!_stationList.isEmpty()) {
      p.remove(_stationList);
    }
    return p;
  }

  bool CoreToolInterface::fixDatabasePaths(QString databaseFileName)
  {
    TRACE;
    SignalDatabase * db=GeopsyCoreEngine::instance()->defaultDatabase();
    if(!db->open(databaseFileName)) {
      return false;
    }
    return db->save();
  }

  void CoreToolInterface::setHelp(ApplicationHelp * h)
  {
    h->addOption("-db","Database file to process");
    h->addOption("-no-file-key","Skip file content key when loading database (only for old database before 2017-09).");
    h->addOption("-interactive","Allow interactions through stdin/out.");
    h->addOption("-groups","List the available groups and exit.");
    h->addOption("-group-id <ID>","Group ID to process. Several entries are allowed. "
                                  "If no group is selected, all groups are processed. If group with ID contains several children, "
                                  "the children are processed.");
    h->addOption("-group <PATH>","Alias to -group-path.");
    h->addOption("-group-path <PATH>","Group path to process. Several entries are allowed. "
                                      "If no group is selected, all groups are processed. If group with PATH contains several children, "
                                      "the children are processed.");
    h->addOption("-group-pattern <REGEXP>","Select for processing all groups whose name matches REGEXP. Only one entry is allowed. "
                                           "If no group is selected, all groups are processed.");
    h->addOption("-station-list <STATIONS>","STATIONS is a coma separated list of station names to be processed. "
                                            "'-group-*' options are still required but only a subset of the group "
                                            "can be selected with option '-station-list'.");
    h->addOption("-o <FILE>","Ouput file name (default='a')");
    h->addOption("-param <PARAM>","Load parameters in PARAM");
    h->addOption("-set <PARAM>=<VALUE>","Set VALUE to parameter PARAM.");
    h->addOption("-fix-signal-paths","Only '-db' option is required. Absolute paths stored in a '.gpy' can be changed "
                                     "without opening a graphical user interface. Useful when moving a database to a "
                                     "remote server without X display.");
  }

} // namespace GeopsyCore

