//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Job/JobparQModel.cpp
//! @brief     Implements class JobparQModel.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/View/Job/JobparQModel.h"
#include "GUI/Model/Job/BatchInfo.h"
#include "GUI/Model/Job/JobItem.h"
#include "GUI/Model/Job/JobStatus.h"
#include "GUI/Model/Job/JobsSet.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/Model/Sample/SampleItem.h"
#include "GUI/Model/Sim/InstrumentItems.h"

namespace {

namespace Column {
enum Columns { Name, Value };
} // namespace Column
const QString ColumnNames[] = {"Name", "Value"};
const int NumColumns = (int)std::size(ColumnNames);

namespace Row {
enum Rows { Name, Sample, Instrument, Status, Begin, End, Duration };
} // namespace Row
const QString RowNames[] = {"Name", "Sample", "Instrument", "Status", "Begin", "End", "Duration"};
const int NumRows = (int)std::size(RowNames);

const QString ModelDateShortFormat = "yyyy.MM.dd hh:mm:ss";

JobItem* jobRW()
{
    return gDoc->jobsRW()->currentItem();
}

const JobItem* job()
{
    return gDoc->jobs()->currentItem();
}

} // namespace


JobparQModel::JobparQModel(QObject* parent)
    : QAbstractTableModel(parent)
{
}

int JobparQModel::rowCount(const QModelIndex&) const
{
    return NumRows;
}

int JobparQModel::columnCount(const QModelIndex&) const
{
    return NumColumns;
}

QVariant JobparQModel::data(const QModelIndex& index, int role) const
{
    if ((role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::ToolTipRole)
        || index.column() < 0 || index.column() >= NumColumns || index.row() < 0
        || index.row() >= NumRows || !::job())
        return {};

    switch (index.column()) {
    case Column::Name:
        return RowNames[index.row()];
    case Column::Value: {
        switch (index.row()) {
        case Row::Name:
            return ::job()->batchInfo()->jobName();
        case Row::Sample:
            return ::job()->sampleItem()->name();
        case Row::Instrument:
            return ::job()->instrumentItem()->name();
        case Row::Status:
            return jobStatusToString(::job()->batchInfo()->status());
        case Row::Begin:
            if (role == Qt::ToolTipRole)
                return QLocale().toString(::job()->batchInfo()->beginTime(), QLocale::LongFormat);
            return ::job()->batchInfo()->beginTime().toString(ModelDateShortFormat);
        case Row::End:
            if (role == Qt::ToolTipRole)
                return QLocale().toString(::job()->batchInfo()->endTime(), QLocale::LongFormat);
            return ::job()->batchInfo()->endTime().toString(ModelDateShortFormat);
        case Row::Duration: {
            std::optional<size_t> duration = ::job()->batchInfo()->duration();
            if (duration)
                return QString("%1 s").arg(duration.value() / 1000., 0, 'f', 3);
            return {};
        }
        default:
            return {};
        }
    }
    default:
        return {};
    }
}

QVariant JobparQModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section >= 0
        && section < NumColumns)
        return ColumnNames[section];
    return {};
}

Qt::ItemFlags JobparQModel::flags(const QModelIndex& index) const
{
    Qt::ItemFlags f = QAbstractTableModel::flags(index);
    if (index.column() == Column::Value && index.row() == Row::Name && ::job())
        f.setFlag(Qt::ItemIsEditable);
    return f;
}

bool JobparQModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
    if (role != Qt::EditRole || index.column() != Column::Value || index.row() != Row::Name
        || !::job())
        return false;
    ::jobRW()->batchInfo()->setJobName(value.toString());
    return true;
}
