//
//
// This file is part of MorphoGraphX - http://www.MorphoGraphX.org
// Copyright (C) 2012-2019 Richard S. Smith and collaborators.
//
// If you use MorphoGraphX in your work, please cite:
//   http://dx.doi.org/10.7554/eLife.05864
//
// MorphoGraphX is free software, and is licensed under under the terms of the 
// GNU General (GPL) Public License version 2.0, http://www.gnu.org/licenses.
// 
#include <ProcessParms.hpp>
#include <Information.hpp>

namespace mgx
{
  // Process name that is using the parameters
  QString ProcessParms::name() const { return _name; };

  // Process description
  QString ProcessParms::description() const { return _description; };

  // List of named parameters.
  QStringList ProcessParms::parmNames() const { return _parmNames; }

  // List of parameters descriptions.
  QStringList ProcessParms::parmDescs() const { return _parmDescs; }

  // List of default parms.
  QStringList ProcessParms::parmDefaults() const { return _parmDefaults; }

  // Pick lists
  ParmChoiceList ProcessParms::parmChoice() const { return _parmChoices; }

  // The icon
  QIcon ProcessParms::icon() const { return _icon; }

  // Get an individual named parameter value
  QString ProcessParms::parm(const QString &parmName) const
  {
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end() or it->second >= _parms.size()) {
      Information::out << "ProcessParms::parm: Process '" << _name
                       << "' parameter '" << parmName
                       << "' does not exist." << endl;
      return QString();
    }
    return _parms.at(it->second);
  }

  // Get the list of parameters
  const QStringList &ProcessParms::getParms() { return _parms; }

  // Set the name
  bool ProcessParms::setName(const QString &name) { _name = name; return true; }

  // Set the description
  bool ProcessParms::setDesc(const QString &description) { _description = description; return true; }

  // Set the icon
  bool ProcessParms::setIcon(const QIcon &icon) { _icon = icon; return true; }

  // Add a named parameter
  bool ProcessParms::addParm(const QString &parmName, const QString &desc, const QString &def, const QStringList &choices)
  {
    return insertParm(parmName, desc, def, _parmNames.count(), choices);
  }

  // Insert a named parameter
  bool ProcessParms::insertParm(const QString &parmName, const QString &desc, const QString &def, int pos, const QStringList &choices)
  {
    if(pos < 0) pos = 0;
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end()) {
      // New parm
      int count = _parmNames.count();
      if(pos >= count) {
        // Just add to the end
        pos = count;
        _parmNames << parmName;
        _parmDescs << desc;
        _parmDefaults << def;
        _parmChoices << choices;
        _parms << def; // Initially set as default
      } else {
        // If we are inserting, shift existing indices
        for(auto &pr : _parmIdx)
          if(pr.second >= pos)
            pr.second++;
        _parmNames.insert(pos, parmName);
        _parmDescs.insert(pos, desc);
        _parmDefaults.insert(pos, def);
        _parmChoices.insert(pos, choices);
        _parms.insert(pos, def); // Initially set as default
      }
      _parmIdx[parmName] = pos;
    } else if(it->second < _parms.size()) {
      // Update existing
      _parmNames[it->second] = parmName;
      _parmDescs[it->second] = desc;
      _parmDefaults[it->second] = def;
      _parmChoices[it->second] = choices;
    } else {
      Information::out << "ProcessParms::addParm: Process '"
                       << _name << "' parameter '"
                       << parmName << "'; err in parm table." << endl;
      return false;
    }

    return true;
  }

  bool ProcessParms::setParm(const QString &parmName, const QString &parm)
  {
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end()) {
      Information::out << QString("ProcessParms::setParm: Process '%1' Parameter '%2' does not exist.").arg(_name).arg(parmName) << endl;
      return false;
    }
    if(_parms.size() <= it->second) {
      Information::out << QString("ProcessParms::setParm: Process '%1' Parameter '%1' position %2 is too big for parms list size %3.")
                    .arg(_name).arg(parmName).arg(it->second).arg(_parms.size()) << endl;
      return false;
    }
    _parms[it->second] = parm;
    return true;
  }

  bool ProcessParms::setParms(const QStringList &parms)
  {
    if(parms.size() != _parmNames.size() and _parmNames.size() != 0) {
      Information::out << QString("ProcessParms::setParms: Process '%1' Parms size mismatch, %2 parms provided, s/b %3.")
                .arg(_name).arg(parms.size()).arg(_parmNames.size()) << endl;
      return false;
    }
    _parms = parms;
    return true;
  }

  bool ProcessParms::setParmDesc(const QString &parmName, const QString &desc)
  {
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end()) {
      Information::out << QString("ProcessParms::setParmDesc: Process '%1' Parameter '%2' does not exist.").arg(_name).arg(parmName) << endl;
      return false;
    }
    if(_parms.size() <= it->second) {
      Information::out << QString("ProcessParms::setParmDesc: Process '%1' Parameter '%2' position %3 is too big for parms list size %4.")
                    .arg(_name).arg(parmName).arg(it->second).arg(_parms.size()) << endl;
      return false;
    }
    _parmDescs[it->second] = desc;

    return true;
  }

  bool ProcessParms::setParmDefault(const QString &parmName, const QString &def)
  {
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end()) {
      Information::out << QString("ProcessParms::setParmDefault: Process '%1' Parameter '%2' does not exist\n").arg(_name).arg(parmName) << endl;
      return false;
    }
    if(_parms.size() <= it->second) {
      Information::out << QString("ProcessParms::setParmDefault: Process '%1' Parameter '%2' position %3 is too big for parms list size %4.")
                    .arg(_name).arg(parmName).arg(it->second).arg(_parms.size()) << endl;
      return false;
    }
    _parmDefaults[it->second] = def;

    return true;
  }

  bool ProcessParms::setParmChoices(const QString &parmName, const QStringList &choices)
  {
    auto it = _parmIdx.find(parmName);
    if(it == _parmIdx.end()) {
      Information::out << QString("ProcessParms::setParmChoices: Process '%1' Parameter '%2' does not exist.").arg(_name).arg(parmName) << endl;
      return false;
    }
    if(_parms.size() <= it->second) {
      Information::out << QString("ProcessParms::setParmChoices: Process '%1' Parameter '%2' position %3 is too big for parms list size %4.")
                    .arg(_name).arg(parmName).arg(it->second).arg(_parms.size()) << endl;
      return false;
    }
    _parmChoices[it->second] = choices;

    return true;
  }

  QStringList ProcessParms::parmList(const QString &key) const
  {
    QStringList list;

    if(key.isEmpty())
      return _parmNames;
    else {
      QRegExp regExp(key);
      for(auto &s : _parmNames)
        if(s.indexOf(regExp) >= 0)
          list << s;
    }
    return list;
  }
}
