/*****************************************************************************
 *
 * Testmanager - Graphical Automation and Visualisation Tool
 *
 * Copyright (C) 2018 - 2019  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 "TextPluginDialog.h"

#include <QAbstractTableModel>

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

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

class TextPluginDialog::Model:
    public QAbstractTableModel
{
    public:
        Model(Pd::Text::Hash *hash):
            hash(hash)
        {
            QList<int> keys(hash->keys());
            std::sort(keys.begin(), keys.end());
            foreach (int key, keys) {
                Row row;
                row.value = QString::number(key);
                row.text = hash->value(key).text;
                rows.append(row);
            }
        }

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

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

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

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

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

        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 0: // value
                    switch (role) {
                        case Qt::DisplayRole:
                        case Qt::EditRole:
                            return rows[index.row()].value;
                        default:
                            return QVariant();
                    }
                    break;

                case 1: // text
                    switch (role) {
                        case Qt::DisplayRole:
                        case Qt::EditRole:
                            return rows[index.row()].text;
                        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() < 0 or index.column() >= 2) {
                return false;
            }

            switch (index.column()) {

                case 0: // value
                    rows[index.row()].value = value.toString();
                    return true;

                case 1: // text
                    rows[index.row()].text = value.toString();
                    return true;
            }

            return false;
        }

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

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

                    case 1:
                        return TextPluginDialog::tr("Text");

                    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()
        {
            QMap<int, QString> map;
            foreach (Row row, rows) {
                bool ok;
                int key = row.value.toInt(&ok);
                if (!ok) {
                    return false;
                }
                map[key] = row.text;
            }

            hash->clear();
            foreach (int key, map.keys()) {
                hash->insert(key, map[key]);
            }
            return true;
        }

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

    private:
        Pd::Text::Hash * const hash;
        struct Row {
            QString value;
            QString text;
        };
        QList<Row> rows;
};

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

TextPluginDialog::TextPluginDialog(Pd::Text::Hash *hash, QWidget *parent):
    QDialog(parent),
    hash(hash),
    model(new Model(hash))
{
    setupUi(this);

    tableView->setModel(model);

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

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

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

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

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

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

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

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

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

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

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

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