/***************************************************************************
**
**  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: 2006-04-01
**  Copyright: 2006-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpGuiTools.h>

#include "WindowEnvironment.h"
#include "MainWindow.h"
#include "LaunchThreadItem.h"
#include "InversionThread.h"

LaunchThreadItem::LaunchThreadItem(QObject * parent)
    : QAbstractItemModel(parent)
{
  TRACE;
  MainWindow * w=WindowEnvironment::window(this);
  ASSERT(w);
  connect(w, SIGNAL(beginClearThreads()), this, SLOT(beginClearThreads()));
  connect(w, SIGNAL(endClearThreads()), this, SLOT(endClearThreads()));
  connect(w, SIGNAL(beginNewThread()), this, SLOT(beginNewThread()));
  connect(w, SIGNAL(endNewThread()), this, SLOT(endNewThread()));
  connect(w, SIGNAL(beginRemoveThread(int)), this, SLOT(beginRemoveThread(int)));
  connect(w, SIGNAL(endRemoveThread()), this, SLOT(endRemoveThread()));
}

LaunchThreadItem::~LaunchThreadItem()
{
  TRACE;
}

void LaunchThreadItem::beginClearThreads()
{
  TRACE;
  beginResetModel();
}

void LaunchThreadItem::endClearThreads()
{
  TRACE;
  endResetModel();
}

void LaunchThreadItem::beginNewThread()
{
  TRACE;
  int n=rowCount();
  beginInsertRows(QModelIndex(), n, n);
}

void LaunchThreadItem::endNewThread()
{
  TRACE;
  endInsertRows();
}

void LaunchThreadItem::beginRemoveThread(int index)
{
  TRACE;
  beginRemoveRows(QModelIndex(), index, index);
}

void LaunchThreadItem::endRemoveThread()
{
  TRACE;
  endRemoveRows();
}

int LaunchThreadItem::rowCount(const QModelIndex &parent) const
{
  TRACE;
  if(!parent.isValid()) {
    return WindowEnvironment::window(this)->threads().count();
  }
  return 0;
}

int LaunchThreadItem::columnCount(const QModelIndex & ) const
{
  TRACE;
  return 6;
}

QVariant LaunchThreadItem::data(const QModelIndex &index, int role) const
{
  TRACE;
  MainWindow * w=WindowEnvironment::window(this);
  InversionThread * t=w->threads().at(index.row());
  switch (role) {
  case Qt::DisplayRole:
    switch (index.column()) {
    case 0: return t->objectName();
    case 1: return t->ns0();
    case 2: return t->ns();
    case 3: return t->nr();
    case 4: return 100.0*t->giveUp();
    case 5: return t->nw();
    default: return QVariant();
    }
  default:
    return QVariant();
  }
}

bool LaunchThreadItem::setData (const QModelIndex & index, const QVariant & value, int role)
{
  TRACE;
  MainWindow * w=WindowEnvironment::window(this);
  InversionThread * t=static_cast<InversionThread *>(index.internalPointer());
  switch (role) {
  case Qt::EditRole:
    switch (index.column()) {
    case 0:
      if(t->setObjectName(value.toString())) {
        w->logs()->setViewName(t, value.toString());
        App::log(t, tr("Renaming to %1\n").arg(value.toString()));
        emit dataChanged(index, index);
        return true;
      } else {
        return false;
      }
    case 1:
      t->setNs0(value.toInt());
      emit dataChanged(index, index);
      return true;
    case 2:
      t->setNs(value.toInt());
      emit dataChanged(index, index);
      return true;
    case 3:
      t->setNr(value.toInt());
      emit dataChanged(index, index);
      return true;
    case 4:
      t->setGiveUp(value.toInt()/100.0);
      emit dataChanged(index, index);
      return true;
    case 5:
      t->setNw(value.toInt());
      emit dataChanged(index, index);
      return true;
    default:
      return false;
    }
  default:
    return false;
  }
}

QVariant LaunchThreadItem::headerData(int section, Qt::Orientation orientation, int role) const
{
  TRACE;
  switch (role) {
  case Qt::DisplayRole:
    if(orientation==Qt::Horizontal) {
      switch (section) {
      case 0: return tr( "Run name" );
      case 1: return tr( "Ns0" );
      case 2: return tr( "Ns" );
      case 3: return tr( "Nr" );
      case 4: return tr( "GiveUp" );
      case 5: return tr( "Nw" );
      default: return QVariant();
      }
    } else {
      return section + 1;
    }
  case Qt::ToolTipRole:
    if(orientation==Qt::Horizontal) {
      switch (section) {
      case 0: return tr("A user name, must be unique inside an environment.");
      case 1: return tr("Number of models generated randomly (Monte-Carlo).");
      case 2: return tr("Number of models generated with Neighborhood.");
      case 3: return tr("Number of best solution models to consider when resampling (higher is more explorative).");
      case 4: return tr("When it is difficult to generate new models (misfit computation fails), it is possible to discard "
                        "some cells after un certain number of fails relative to the number of success.");
      case 5: return tr("Number of Markov-chain walks to generate one model (1 or 2 is ok).");
      default: return QVariant();
      }
    } else {
      return QVariant();
    }
  default:
    return QVariant();
  }
}

QModelIndex LaunchThreadItem::parent (const QModelIndex &) const
{
  TRACE;
  return QModelIndex();
}

QModelIndex LaunchThreadItem::index (int row, int column, const QModelIndex &) const
{
  TRACE;
  MainWindow * w=WindowEnvironment::window(this);
  // 2019-01-21
  // One of the strange behavior under Windows, count() is apparently not called
  // and this function is used with row==0 and an empty thread list
#ifdef Q_OS_WIN
  if(row<w->threads().count()) {
#endif
  InversionThread * t=w->threads().at(row);
  return createIndex(row, column, t);
#ifdef Q_OS_WIN
  } else {
    return QModelIndex();
  }
#endif
}

Qt::ItemFlags LaunchThreadItem::flags (const QModelIndex &) const
{
  return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
