/*
 * Copyright (C) 2014-2026 CZ.NIC
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations including
 * the two.
 */

#include "src/gui/icon_container.h"
#include "src/models/restore_selection_model.h"

static IconContainer inconContainer; /* Local icon container. */

RestoreSelectionModel::RestoreSelectionModel(QObject *parent)
    : QAbstractTableModel(parent),
    m_entries(),
    m_numMsgsSelected(0)
{
}

int RestoreSelectionModel::rowCount(const QModelIndex &parent) const
{
	if (parent.isValid()) {
		return 0;
	} else {
		return m_entries.size();
	}
}

int RestoreSelectionModel::columnCount(const QModelIndex &parent) const
{
	if (parent.isValid()) {
		return 0;
	} else {
		return MAX_COLNUM;
	}
}

/*!
 * @brief Convert action into selection state.
 *
 * @param[in] a Action.
 * @return Selection state.
 */
static inline
enum Qt::CheckState actionToCheckState(enum RestoreSelectionModel::Action a) {
	return (a != RestoreSelectionModel::ACT_NONE) ? Qt::Checked : Qt::Unchecked;
}

QVariant RestoreSelectionModel::data(const QModelIndex &index, int role) const
{
	const int row = index.row();
	const int col = index.column();
	if (Q_UNLIKELY((row < 0) || (row >= rowCount()))) {
		Q_ASSERT(0);
		return QVariant();
	}
	if (Q_UNLIKELY((col < 0) || (col >= columnCount()))) {
		Q_ASSERT(0);
		return QVariant();
	}

	switch (role) {
	case Qt::DisplayRole:
		switch (col) {
		case COL_MSGS_CHECKBOX:
			return QVariant();
			break;
		case COL_RESTORE_ACTION:
			return actionString(m_entries[row].action);
			break;
		case COL_ACCOUNT_NAME:
			return m_entries[row].accountName;
			break;
		case COL_USERNAME:
			return m_entries[row].acntId.username();
			break;
		case COL_TESTING:
			return m_entries[row].acntId.testing();
			break;
		case COL_BOX_ID:
			return m_entries[row].boxId;
			break;
		default:
			Q_ASSERT(0);
			return QVariant();
			break;
		}
		break;
	case Qt::CheckStateRole:
		if (col == COL_MSGS_CHECKBOX) {
			return actionToCheckState(m_entries[row].action);
		} else {
			return QVariant();
		}
		break;
	default:
		return QVariant();
		break;
	}
}

Qt::ItemFlags RestoreSelectionModel::flags(const QModelIndex &index) const
{
	Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);

	if (index.column() == COL_MSGS_CHECKBOX) {
		defaultFlags |= Qt::ItemIsUserCheckable;
	}

	return defaultFlags;
}

bool RestoreSelectionModel::setData(const QModelIndex &index,
    const QVariant &value, int role)
{
	if (Q_UNLIKELY(!index.isValid())) {
		return false;
	}

	const int row = index.row();
	if (Q_UNLIKELY((row < 0) || (row >= rowCount()))) {
		Q_ASSERT(0);
		return false;
	}

	Action newAct = ACT_NONE;
	enum Qt::CheckState newState = Qt::Unchecked;

	if ((index.column() == COL_MSGS_CHECKBOX) && (role == Qt::CheckStateRole)) {
		newAct = (value == Qt::Checked) ? ACT_REPLACE : ACT_NONE;
		newState = (value == Qt::Checked) ? Qt::Checked : Qt::Unchecked;
	} else if ((index.column() == COL_RESTORE_ACTION) && (role == Qt::EditRole)) {
		if (!value.canConvert<Action>()) {
			return false;
		}
		newAct = qvariant_cast<Action>(value);
		newState = actionToCheckState(newAct);
	} else {
		return QAbstractTableModel::setData(index, value, role);
	}

	if (newState != actionToCheckState(m_entries[row].action)) {
		m_entries[row].action = newAct;
		if (newState == Qt::Checked) {
			++m_numMsgsSelected;
		} else {
			--m_numMsgsSelected;
		}
		emit dataChanged(index.sibling(row, COL_MSGS_CHECKBOX),
		    index.sibling(row, COL_RESTORE_ACTION));
		return true;
	} else if (newAct != m_entries[row].action) {
		m_entries[row].action = newAct;
		emit dataChanged(index.sibling(row, COL_RESTORE_ACTION),
		    index.sibling(row, COL_RESTORE_ACTION));
		return true;
	}

	return false;
}

QVariant RestoreSelectionModel::headerData(int section,
    Qt::Orientation orientation, int role) const
{
	Q_UNUSED(orientation);

	switch (role) {
	case Qt::DisplayRole:
		switch (section) {
		case COL_MSGS_CHECKBOX:
			return QVariant(); /* Hide text. */
			break;
		case COL_RESTORE_ACTION:
			return tr("Restoration action");
			break;
		case COL_ACCOUNT_NAME:
			return tr("Data box");
			break;
		case COL_USERNAME:
			return tr("Username");
			break;
		case COL_TESTING:
			return tr("Testing");
			break;
		case COL_BOX_ID:
			return tr("Box identifier");
			break;
		default:
			Q_ASSERT(0);
			return QVariant();
			break;
		}
		break;

	case Qt::DecorationRole:
		switch (section) {
		case COL_MSGS_CHECKBOX:
			return inconContainer.icon(IconContainer::ICON_MESSAGE);
			break;
		default:
			return QVariant();
			break;
		}
		break;

	case Qt::ToolTipRole:
		switch (section) {
		case COL_MSGS_CHECKBOX:
			return tr("Messages");
			break;
		default:
			return QVariant();
			break;
		}
		break;

	default:
		return QVariant();
		break;
	}
}

void RestoreSelectionModel::appendData(enum Action action, const QString &aName,
    const AcntId &acntId, const QString &bId)
{
	Entry entry(action, aName, acntId, bId);

	beginInsertRows(QModelIndex(), rowCount(), rowCount());

	m_entries.append(entry);
	if (action != ACT_NONE) {
		++m_numMsgsSelected;
	}

	endInsertRows();
}

int RestoreSelectionModel::numChecked(void) const
{
	return m_numMsgsSelected;
}

void RestoreSelectionModel::clear(void)
{
	if (m_entries.size() > 0) {
		beginResetModel();
		m_entries.clear();
		m_numMsgsSelected = 0;
		endResetModel();
	}
}

QList<RestoreSelectionModel::Entry> RestoreSelectionModel::selectedEntries(
    void) const
{
	QList<Entry> checked;
	foreach (const Entry &e, m_entries) {
		if (e.action != ACT_NONE) {
			checked.append(e);
		}
	}
	Q_ASSERT(checked.size() == numChecked());
	return checked;
}

QString RestoreSelectionModel::actionString(enum Action action)
{
	switch (action) {
	case ACT_NONE:
		return QString();
		break;
	case ACT_REPLACE:
		return tr("Replace");
		break;
	case ACT_CREATE:
		return tr("Create");
		break;
	default:
		Q_ASSERT(0);
		return QString();
		break;
	}
}
