/*
 * model.cpp - key view model
 *
 * Copyright (C) 2013  Ivan Romanov <drizt@land.ru>
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "model.h"
#include "gpgprocess.h"
#include <QDateTime>

inline QString epochToHuman(const QString &seconds)
{
	qint64 ms = seconds.toLongLong() * 1000;
	if (ms)
		return QDateTime::fromMSecsSinceEpoch(ms).date().toString();
	else
		return QString();
}

inline QString uidToName(const QString &uid)
{
	if (uid.contains('(')) {
		return uid.section('(', 0, 0).trimmed();
	}
	else if (uid.contains('<')) {
		return uid.section('<', 0, 0).trimmed();
	}
	else {
		return uid.trimmed();
	}
}

inline QString uidToEMail(const QString &uid)
{
	if (uid.contains('<') && uid.contains('>')) {
		return uid.section('<', 1).section('>', 0, 0).trimmed();
	}
	else
		return "";
}

inline QString uidToComment(const QString &uid)
{
	if (uid.contains('(') && uid.contains(')')) {
		return uid.section('(', 1).section(')', 0, 0).trimmed();
	}
	else {
		return "";
	}
}

QList<QStandardItem*> parseLine(const QString &line)
{
	QList<QStandardItem*> rows;

	// Used ID
	QString uid = line.section(':', 9, 9);

	// Type
	rows << new QStandardItem(line.section(':', 0, 0));

	// Name
	rows << new QStandardItem(uidToName(uid));

	// E-mail
	rows << new QStandardItem(uidToEMail(uid));

	// Creation key time in human readable format
	rows << new QStandardItem(epochToHuman(line.section(':', 5, 5)));

	// Expiration time
	rows << new QStandardItem(epochToHuman(line.section(':', 6, 6)));

	// Length of key
	rows << new QStandardItem(line.section(':', 2, 2));

	// Comment
	rows << new QStandardItem(uidToComment(uid));

	// Algorithm
	int alg = line.section(':', 3, 3).toInt();
	switch(alg) {
	case 1: rows << new QStandardItem("RSA"); break;
	case 16: rows << new QStandardItem("ELG-E"); break;
	case 17: rows << new QStandardItem("DSA"); break;
	case 18: rows << new QStandardItem("ECC"); break;
	default: rows << new QStandardItem(""); break;
	}

	// Short ID
	rows << new QStandardItem(line.section(':', 4, 4).right(8));

	// Fingerprint
	rows << new QStandardItem("");

	return rows;
}

Model::Model(QObject *parent)
	: QStandardItemModel(parent)
{
}

void Model::listKeys()
{
	clear();

	static QStringList headerLabels;

	if (headerLabels.isEmpty()) {
		for (int i = 0; i < Model::Count; ++i) {
			headerLabels << QString();
		}

		headerLabels[Type] = tr("Type");
		headerLabels[Name] = tr("Name");
		headerLabels[Email] = tr("E-Mail");
		headerLabels[Created] = tr("Created");
		headerLabels[Expiration] = tr("Expiration");
		headerLabels[Length] = tr("Length");
		headerLabels[Comment] = tr("Comment");
		headerLabels[Algorithm] = tr("Algorithm");
		headerLabels[ShortId] = tr("Short ID");
		headerLabels[Fingerprint] = tr("Fingerprint");
	}

	setHorizontalHeaderLabels(headerLabels);

	QStringList arguments;
	arguments << "--with-fingerprint"
			  << "--list-secret-keys"
			  << "--with-colons"
			  << "--fixed-list-mode";

	GpgProcess process;
	process.start(arguments);
	process.waitForFinished();
	QString keysRaw = QString::fromUtf8(process.readAll());

	arguments.clear();
	arguments << "--with-fingerprint"
			  << "--list-public-keys"
			  << "--with-colons"
			  << "--fixed-list-mode";

	process.start(arguments);
	process.waitForFinished();
	keysRaw += QString::fromUtf8(process.readAll());


	showKeys(keysRaw);
}

void Model::showKeys(const QString &keysRaw)
{
	QStringList list = keysRaw.split("\n");
	QList<QStandardItem*> lastRow;
	QList<QStandardItem*> row;
	QStringList secretKeys;
	foreach (QString line, list) {
		QString type = line.section(':', 0, 0);
		if (type == "pub" || type == "sec") {
			row = parseLine(line);

			// Show only secret part for keys pair
			if (type == "sec") {
				secretKeys << row.at(Algorithm)->text();
			}
			else if (secretKeys.indexOf(row.at(ShortId)->text()) >= 0) {
				lastRow.clear();
				continue;
			}

			appendRow(row);
			lastRow = row;
		}
		else if ((type == "uid" || type == "ssb" || type == "sub") && !lastRow.isEmpty()) {
			row = parseLine(line);
			lastRow.first()->appendRow(row);
			if (lastRow.first()->rowCount() == 1) {
				lastRow.at(Name)->setText(row.at(Name)->text());
				lastRow.at(Email)->setText(row.at(Email)->text());
				lastRow.at(Comment)->setText(row.at(Comment)->text());
			}
		}
		else if (type == "fpr") {
			row.at(Fingerprint)->setText(line.section(':', Fingerprint, Fingerprint));
		}
	}
}
