/*****************************************************************************
 *
 * Testmanager - Graphical Automation and Visualisation Tool
 *
 * Copyright (C) 2018 - 2023  Florian Pose <fp@igh.de>
 *
 * This file is part of Testmanager.
 *
 * Testmanager 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.
 *
 * Testmanager 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 Testmanager. If not, see <http://www.gnu.org/licenses/>.
 *
 ****************************************************************************/

#include "TableViewPluginDialog.h"

#include "TableViewPluginPrivate.h"

#include <QAbstractTableModel>

#include <algorithm>  // std::sort()

/****************************************************************************/

class TableViewPluginDialog::Model: public QAbstractTableModel
{
    public:
        enum { HeaderColumn, DecimalsColumn, ColumnCount };

        Model(TableViewPluginPrivate *priv):
            priv(priv)
        {
            for (auto col : priv->columns) {
                Row row;
                row.header = col->getHeader();
                row.decimals = col->getDecimals();
                rows.append(row);
            }
        }

        /********************************************************************/

        int rowCount(const QModelIndex &index) const
        {
            if (index.isValid()) {
                return 0;
            }
            else {
                return rows.size();
            }
        }

        /********************************************************************/

        int columnCount(const QModelIndex &) const { return ColumnCount; }

        /********************************************************************/

        QVariant data(const QModelIndex &index, int role) const
        {
            if (not index.isValid() or index.row() < 0
                or index.row() >= rows.size()) {
                return QVariant();
            }

            switch (index.column()) {
                case HeaderColumn:
                    switch (role) {
                        case Qt::DisplayRole:
                        case Qt::EditRole:
                            return rows[index.row()].header;
                        default:
                            return QVariant();
                    }
                    break;

                case DecimalsColumn:
                    switch (role) {
                        case Qt::DisplayRole:
                        case Qt::EditRole:
                            return rows[index.row()].decimals;
                        default:
                            return QVariant();
                    }
                    break;

                default:
                    return QVariant();
            }
        }

        /********************************************************************/

        bool
        setData(const QModelIndex &index, const QVariant &value, int role)
        {
            if (role != Qt::EditRole or not index.isValid() or index.row() < 0
                or index.row() >= rows.size() or index.column() < HeaderColumn
                or index.column() >= ColumnCount) {
                return false;
            }

            switch (index.column()) {
                case HeaderColumn:
                    rows[index.row()].header = value.toString();
                    return true;

                case DecimalsColumn: {
                    bool ok;
                    int num = value.toUInt(&ok);
                    if (!ok) {
                        return false;
                    }
                    rows[index.row()].decimals = num;
                    return true;
                }
            }

            return false;
        }

        /********************************************************************/

        QVariant headerData(int section, Qt::Orientation o, int role) const
        {
            if (role == Qt::DisplayRole && o == Qt::Horizontal) {
                switch (section) {
                    case HeaderColumn:
                        return TableViewPluginDialog::tr("Header");

                    case DecimalsColumn:
                        return TableViewPluginDialog::tr("Decimals");

                    default:
                        return QVariant();
                }
            }
            else {
                return QVariant();
            }
        }

        /********************************************************************/

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

            return Qt::ItemIsEnabled | Qt::ItemIsEditable
                    | Qt::ItemIsSelectable;
        }

        /********************************************************************/

        void addRow()
        {
            beginInsertRows(QModelIndex(), rows.size(), rows.size());
            Row row;
            rows.append(row);
            endInsertRows();
        }

        /********************************************************************/

        void remove(const QModelIndexList &indexes)
        {
            QList<QPersistentModelIndex> persistentIndexes;

            foreach (QModelIndex index, indexes) {
                persistentIndexes << index;
            }

            foreach (const QPersistentModelIndex &index, persistentIndexes) {
                if (index.isValid()) {
                    beginRemoveRows(QModelIndex(), index.row(), index.row());
                    rows.removeAt(index.row());
                    endRemoveRows();
                }
            }
        }

        /********************************************************************/

        bool save()
        {
            priv->clearColumns();
            foreach (Row row, rows) {
                QtPdCom::TableColumn *col = new QtPdCom::TableColumn();
                col->setHeader(row.header);
                col->setDecimals(row.decimals);
                priv->columns.append(col);
                priv->model->addColumn(col);
            }
            return true;
        }

        /********************************************************************/

    private:
        TableViewPluginPrivate *const priv;
        struct Row
        {
                Row():
                    decimals {0} {};

                QString header;
                quint32 decimals;
        };
        QList<Row> rows;
};

/****************************************************************************/

TableViewPluginDialog::TableViewPluginDialog(
        TableViewPluginPrivate *priv,
        QWidget *parent):
    QDialog(parent),
    priv(priv),
    model(new Model(priv))
{
    setupUi(this);

    tableView->setModel(model);

    connect(tableView->selectionModel(),
            SIGNAL(selectionChanged(
                    const QItemSelection &,
                    const QItemSelection &)),
            this,
            SLOT(selectionChanged(
                    const QItemSelection &,
                    const QItemSelection &)));
}

/****************************************************************************/

TableViewPluginDialog::~TableViewPluginDialog()
{
    tableView->setModel(nullptr);
    delete model;
}

/****************************************************************************/

void TableViewPluginDialog::on_buttonBox_accepted()
{
    if (model->save()) {
        accept();
    }
}

/****************************************************************************/

void TableViewPluginDialog::on_toolButtonAdd_clicked()
{
    model->addRow();
}

/****************************************************************************/

void TableViewPluginDialog::on_toolButtonRemove_clicked()
{
    model->remove(tableView->selectionModel()->selectedIndexes());
}

/****************************************************************************/

void TableViewPluginDialog::selectionChanged(
        const QItemSelection &,
        const QItemSelection &)
{
    toolButtonRemove->setEnabled(tableView->selectionModel()->hasSelection());
}

/****************************************************************************/
