//
// 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 "ProcessParmsModel.hpp"
#include <QVariant>
#include <QComboBox>
#include <QLineEdit>

#include <QTextStream>
#include <stdio.h>

using namespace mgx;

static const int ParmChoiceRole = Qt::UserRole + 1;

FreeFloatDelegate::FreeFloatDelegate(QObject* parent) : QStyledItemDelegate(parent) {}

QWidget* FreeFloatDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
{
  QStringList choices = index.model()->data(index, ParmChoiceRole).toStringList();
  QWidget* edit;
  if(!choices.empty())
    edit = new QComboBox(parent);
  else
    edit = new QLineEdit(parent);
  return edit;
}

void FreeFloatDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
  QVariant data = index.model()->data(index, Qt::EditRole);
  QStringList choices = index.model()->data(index, ParmChoiceRole).toStringList();
  if(!choices.isEmpty()) {
    QComboBox* edit = dynamic_cast<QComboBox*>(editor);
    edit->addItems(choices);
    edit->setEditable(true);
    edit->setEditText(data.toString());
  } else {
    QLineEdit* edit = dynamic_cast<QLineEdit*>(editor);
    edit->setText(data.toString());
  }
}

void FreeFloatDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
  QLineEdit* edit = dynamic_cast<QLineEdit*>(editor);
  QString txt;
  if(edit) {
    txt = edit->text();
  } else {
    QComboBox* edit = dynamic_cast<QComboBox*>(editor);
    txt = edit->currentText();
  }
  model->setData(index, txt, Qt::EditRole);
}

void FreeFloatDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option,
                                             const QModelIndex&) const
{
  editor->setGeometry(option.rect);
}

QVariant ProcessParmsModel::data(const QModelIndex& index, int role) const
{
  if(!index.isValid())
    return QVariant();
  int r = index.row();
  int c = index.column();
  if(r < 0 or r >= names.size() or c > 1 or c < 0)
    return QVariant();
  if(c == 0) {
    if(role == Qt::DisplayRole)
      return names[r];
    else if(role == Qt::ToolTipRole)
      return (descs.size() > r ? descs[r] : names[r]);
    else if(role == Qt::BackgroundRole)
      return QColor(220, 255, 220);
  } else {
    if(role == Qt::DisplayRole or role == Qt::EditRole) {
      if(r < (int)_parms.size())
        return _parms[r];
    } else if(role == ParmChoiceRole)
      return parmChoice(r);
  }
  return QVariant();
}

QVariant ProcessParmsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if(role != Qt::DisplayRole)
    return QVariant();
  if(orientation == Qt::Vertical)
    return QVariant();
  if(section == 0)
    return "Parameter";
  else if(section == 1)
    return "Value";
  return QVariant();
}

Qt::ItemFlags ProcessParmsModel::flags(const QModelIndex& index) const
{
  if(!index.isValid())
    return Qt::ItemIsEnabled;

  int c = index.column();
  if(c == 0) {
    return Qt::ItemIsEnabled;
  } else if(c == 1) {
    return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
  }

  return Qt::ItemIsEnabled;
}

bool ProcessParmsModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
  if(!index.isValid() or index.row() >= names.size() or index.column() != 1 or role != Qt::EditRole)
    return false;

  int r = index.row();
  if(r < (int)_parms.size())
    _parms[r] = value.toString();
  emit dataChanged(index, index);
  emit valuesChanged();
  return true;
}

void ProcessParmsModel::clear()
{
  beginResetModel();
  if(!names.empty()) {
    names.clear();
    _parms.clear();
    _parmChoice.clear();
  }
  endResetModel();
}

void ProcessParmsModel::setParms(const QStringList &parms)
{
  beginResetModel();
  if(parms != _parms)
    _parms = parms;
  endResetModel();
}

void ProcessParmsModel::setParms(const ProcessDefinition& def)
{
  beginResetModel();
  names = def.parmNames;
  descs = def.parmDescs;
  _parms = def.parms;
  _parmChoice = def.parmChoice;
  endResetModel();
}

QStringList ProcessParmsModel::parmChoice(int pos) const
{
  if(pos < _parmChoice.size())
    return _parmChoice[pos];
  return QStringList();
}
