/*
 * Copyright (C) 2014-2024 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/message_download_model.h"

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

MsgDownloadModel::MsgDownloadModel(QObject *parent)
    : QAbstractTableModel(parent),
    m_entries()
{
}

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

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

QVariant MsgDownloadModel::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_MSG_ID:
			return m_entries[row].msgId.dmId();
			break;
		case COL_STATE:
			return QVariant();
			break;
		case COL_ERROR:
			return m_entries[row].error;
			break;
		default:
			Q_ASSERT(0);
			return QVariant();
			break;
		}
		break;

	case Qt::DecorationRole:
		switch (col) {
		case COL_STATE:
			switch (m_entries[row].state) {
			case STAT_FAILED:
				return inconContainer.icon(IconContainer::ICON_DATOVKA_ERROR);
				break;
			case STAT_SUCCEEDED:
				return inconContainer.icon(IconContainer::ICON_DATOVKA_OK);
				break;
			default:
				return QVariant();
				break;
			}
			break;
		default:
			return QVariant();
			break;
		}
		break;

	case Qt::ToolTipRole:
		if (col == COL_STATE) {
			switch (m_entries[row].state) {
			case STAT_NOT_ATTEMPTED:
				return tr("Not attempted");
				break;
			case STAT_FAILED:
				return tr("Failed");
				break;
			case STAT_SUCCEEDED:
				return tr("Succeeded");
				break;
			default:
				Q_ASSERT(0);
				return QVariant();
				break;
			}
		}
		return QVariant();
		break;

	case Qt::AccessibleTextRole:
		{
			QString str =
			    headerData(col, Qt::Horizontal).toString() +
			    QStringLiteral(" ");
			switch (col) {
			case COL_MSG_ID:
				str += QString::number(m_entries[row].msgId.dmId());
				break;
			case COL_STATE:
				str += data(index, Qt::ToolTipRole).toString();
				break;
			case COL_ERROR:
				str += m_entries[row].error;
				break;
			default:
				Q_ASSERT(0);
				break;
			}
			return str;
		}
		break;

	case ROLE_PROXYSORT:
		switch (col) {
		case COL_MSG_ID:
			return m_entries[row].msgId.dmId();
			break;
		case COL_STATE:
			return (int)m_entries[row].state;
			break;
		case COL_ERROR:
			return m_entries[row].error;
			break;
		default:
			Q_ASSERT(0);
			return QVariant();
			break;
		}
		break;

	default:
		return QVariant();
		break;
	}
}

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

	switch (role) {
	case Qt::DisplayRole:
		switch (section) {
		case COL_MSG_ID:
			return tr("Message ID");
			break;
		case COL_STATE:
			return tr("Downloaded");
			break;
		case COL_ERROR:
			return tr("Download Error");
			break;
		default:
			Q_ASSERT(0);
			return QVariant();
			break;
		}
		break;

	default:
		return QVariant();
		break;
	}
}

void MsgDownloadModel::appendData(const AcntIdDb &anctIdDb, const MsgId &msgId,
    enum DownloadState state, const QString &error)
{
	Entry entry(anctIdDb, msgId, state, error);

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

	m_entries.append(entry);

	endInsertRows();
}

void MsgDownloadModel::updateDownloadState(const AcntIdDb &anctIdDb,
    const MsgId &msgId, enum DownloadState state, const QString &error)
{
	for (int row = 0; row < m_entries.size(); ++row) {
		const Entry &entry = m_entries.at(row);
		/* Message delivery time may have changed, store new value. */
		if ((entry.acntIdDb == anctIdDb) &&
		    (entry.msgId.dmId() == msgId.dmId())) {
			m_entries[row].msgId = msgId;
			m_entries[row].state = state;
			m_entries[row].error = error;
			emit dataChanged(index(row, COL_STATE), index(row, COL_ERROR));
			return;
		}
	}
}

bool MsgDownloadModel::allDownloaded(void) const
{
	foreach (const Entry &entry, m_entries) {
		if (entry.state != STAT_SUCCEEDED) {
			return false;
		}
	}

	return true;
}

bool MsgDownloadModel::someDownloaded(void) const
{
	foreach (const Entry &entry, m_entries) {
		if (entry.state == STAT_SUCCEEDED) {
			return true;
		}
	}

	return false;
}

QList< QPair<AcntIdDb, MsgId> > MsgDownloadModel::downloaded(void) const
{
	QList< QPair<AcntIdDb, MsgId> > list;
	foreach (const Entry &entry, m_entries) {
		if (entry.state == STAT_SUCCEEDED) {
			list.append(QPair<AcntIdDb, MsgId>(
			    entry.acntIdDb, entry.msgId));
		}
	}
	return list;
}
