/*
 *  Copyright (C) 2007-2008 CMM Sigma Andrzej Chmielowiec 
<cmmsigma@cmmsigma.eu>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  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.
 */

#include "STokenDialog.h"

#include "crd_ut10xx.h"
#include <QtGui>

static const int StateClear = 0;
static const int StateInit = 1;
static const int StateConf = 2;
static const int StateLock = 3;

static const int TokenItemType = QTreeWidgetItem::UserType;
static const int KeyItemType = QTreeWidgetItem::UserType + 1;
static const int FileItemType = QTreeWidgetItem::UserType + 2;

static int
sTokenState(CRD_UT10XX_t *ut)
{
	if (ut->info.info & 0x04)
		return StateLock;
	
	else if (ut->info.info & 0x02)
		return StateConf;
	
	else if (ut->info.info & 0x01)
		return StateInit;
	
	else
		return StateClear;
}

STokenDialog::STokenDialog(int dialogType, QWidget *parent): QDialog(parent)
{
	libInit();
	mDialogType = dialogType;
	createLayout();
	fillSTokenList();
	setWindowIcon(QIcon(QString(":img/stoken_32.png")));
}

STokenDialog::~STokenDialog()
{
	CRD_UT10XX_lib_finish();
}

const QString&
STokenDialog::text() const
{
	return mText;
}

const QByteArray&
STokenDialog::data() const
{
	return mData;
}

QString
STokenDialog::getKeyName(QString title, QWidget *parent)
{
	QString keyName;
	
	STokenDialog *dialog = new STokenDialog(KeyDialogType, parent);
	dialog->setWindowTitle(title);
	
	if (dialog->exec() == QDialog::Accepted)
	{
		keyName = dialog->text();
	}
	
	delete dialog;
	
	return keyName;
}

QString
STokenDialog::getFileName(QString title, QWidget *parent)
{
	QString fileName;
	
	STokenDialog *dialog = new STokenDialog(FileDialogType, parent);
	dialog->setWindowTitle(title);
	
	if (dialog->exec() == QDialog::Accepted)
	{
		fileName = dialog->text();
	}
	
	delete dialog;
	
	return fileName;
}

QString
STokenDialog::getFileNameAndData(QByteArray &data, QString title, QWidget *parent)
{
	QString fileName;
	
	STokenDialog *dialog = new STokenDialog(FileDialogType, parent);
	dialog->setWindowTitle(title);
	
	if (dialog->exec() == QDialog::Accepted)
	{
		fileName = dialog->text();
		data = dialog->data();
	}
	
	delete dialog;
	
	return fileName;
}

void
STokenDialog::acceptSlot()
{
	if ((mDialogType == TokenDialogType) && 
		(mSTokenList->currentItem()->type() != TokenItemType))
	{
		QMessageBox::information(this, tr("Token selection"), 
			tr("Select <b>token</b> from list and press <b>Accept</b> button."));
		return;
	}
	
	if ((mDialogType == KeyDialogType) && 
		(mSTokenList->currentItem()->type() != KeyItemType))
	{
		QMessageBox::information(this, tr("Key selection"), 
			tr("Select <b>key</b> from list and press <b>Accept</b> button."));
		return;
	}
	
	if ((mDialogType == FileDialogType) && 
		(mSTokenList->currentItem()->type() != FileItemType))
	{
		QMessageBox::information(this, tr("File selection"), 
			tr("Select <b>file</b> from list and press <b>Accept</b> button."));
		return;
	}
	
	if (mDialogType == TokenDialogType)
	{
		mText = mSTokenList->currentItem()->text(0);
	}
	else if ((mDialogType == KeyDialogType) || (mDialogType == FileDialogType))
	{
		mText = mSTokenList->currentItem()->parent()->data(0, Qt::UserRole).toString();
		mText += "/";
		mText += mSTokenList->currentItem()->data(0, Qt::UserRole).toString();
	}
	
	if (mDialogType == FileDialogType)
	{
		QByteArray utSerialNumber = mSTokenList->currentItem()->parent()->data(0, Qt::UserRole).toString().toUtf8();
		utSerialNumber.remove(0, utSerialNumber.lastIndexOf(QChar(':')) + 1);
		QByteArray fileName = mSTokenList->currentItem()->text(0).toUtf8();
		
		CRD_UT10XX_t *ut = CRD_UT10XX_find_by_serial_number(utSerialNumber.data());
		
		if (!ut)
		{
			QMessageBox::critical(this, tr("Token not found"), 
				tr("Cannot find token. Check if <i>%1</i> token is connected.").
				arg(mSTokenList->currentItem()->parent()->text(0)));
			return;
		}
		
		CRD_UT10XX_session_open(ut);
		CRD_UT10XX_file_t* fd = CRD_UT10XX_file_open(ut, fileName.data());
		
		if (!fd)
		{
			QMessageBox::critical(this, tr("File not found"), tr("Cannot access <i>%1</i> file. "
				"Check if <i>%2</i> token is connected.").arg(mSTokenList->currentItem()->text(0)).
				arg(mSTokenList->currentItem()->parent()->text(0)));
			return;
		}
		
		mData.resize(fd->size);
		
		CRD_UT10XX_file_read(fd, mData.data(), fd->size);
		CRD_UT10XX_file_close(fd);
		CRD_UT10XX_session_close(ut);
	}
	
	accept();
}

void
STokenDialog::listItemDoubleClickedSlot(QTreeWidgetItem *item, int column)
{
	item = 0;
	column = 0;
	acceptSlot();
}

void
STokenDialog::libInit()
{
	if ((CRD_UT10XX_lib_init() < 0) || ((mSTokenNum = CRD_UT10XX_lib_find_devices()) < 0)
		    || (CRD_UT10XX_lib_actualize_devices() < 0))
	{
		QMessageBox::critical(this, tr("Error"), tr("Cannot initialize token library!"));
		qApp->quit();
	}
}

void
STokenDialog::createLayout()
{
	QGridLayout *layout = new QGridLayout;
	
	mSTokenList = new QTreeWidget();
	connect(mSTokenList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, 
		SLOT(listItemDoubleClickedSlot(QTreeWidgetItem*, int)));
	mCancel = new QPushButton(tr("Cancel"));
	connect(mCancel, SIGNAL(clicked()), this, SLOT(reject()));
	mAccept = new QPushButton(tr("Accept"));
	connect(mAccept, SIGNAL(clicked()), this, SLOT(acceptSlot()));
	
	layout->addWidget(mSTokenList, 0, 0, 1, 3);
	layout->addWidget(mAccept, 1, 1);
	layout->addWidget(mCancel, 1, 2);
	layout->setColumnStretch(0, 1);
	
	setLayout(layout);
}

void
STokenDialog::fillSTokenList()
{
	mSTokenList->setColumnCount(1);
	mSTokenList->setHeaderLabel(tr("Available tokens"));
	
	for (int i = 0; i < mSTokenNum; i++)
	{
		CRD_UT10XX_t *ut = CRD_UT10XX_find_by_index(i);
		
		QTreeWidgetItem *sToken = new QTreeWidgetItem(TokenItemType);
		mSTokenList->addTopLevelItem(sToken);
		
		if (sTokenState(ut) == StateConf)
		{
			sToken->setIcon(0, QIcon(QString(":img/stoken_32.png")));
			sToken->setText(0, QString(ut->info.name));
			sToken->setData(0, Qt::ToolTipRole, QVariant(QString(ut->info.name) +
				QString(":%1").arg(ut->serial_number)));
			sToken->setData(0, Qt::UserRole, QVariant(QString(ut->info.name) +
				QString(":%1").arg(ut->serial_number)));
		}
		else if (sTokenState(ut) == StateLock)
		{
			sToken->setIcon(0, QIcon(QString(":img/stoken_lock_32.png")));
			continue;
		}
		else
		{
			sToken->setIcon(0, QIcon(QString(":img/stoken_no_32.png")));
			continue;
		}
		
		if (mDialogType == KeyDialogType)
		{
			for (int j = 0; j < ut->info.keys_num; j++)
			{
				if (ut->keys[j].info == 0)
					continue;
				
				QTreeWidgetItem *key = new QTreeWidgetItem(KeyItemType);
				key->setIcon(0, QIcon(QString(":img/key_32.png")));
				key->setText(0, QString(ut->keys[j].name));
				key->setData(0, Qt::ToolTipRole, QVariant(QString(ut->keys[j].name) + 
					QString(":%1").arg(j)));
				key->setData(0, Qt::UserRole, QVariant(QString(ut->keys[j].name) + 
					QString(":%1").arg(j)));
				sToken->addChild(key);
			}
		}
		else if (mDialogType == FileDialogType)
		{
			for (int j = 0; j < ut->files_no; j++)
			{
				if (ut->file_types[j] == CRD_UT10XX_FT_EMPTY)
					continue;
				
				QTreeWidgetItem *file = new QTreeWidgetItem(FileItemType);
				QString fileType(":img/filetype_unknown_32.png");
				
				if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_CRT)
					fileType = QString(":img/filetype_usercert_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_CACRT)
					fileType = QString(":img/filetype_cacert_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_REQ)
					fileType = QString(":img/filetype_userreq_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_TXT)
					fileType = QString(":img/filetype_txt_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_HTML)
					fileType = QString(":img/filetype_html_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_CONF)
					fileType = QString(":img/filetype_conf_32.png");
				else if ((ut->file_types[j] & 0xF0) == CRD_UT10XX_FT_BIN)
					fileType = QString(":img/filetype_bin_32.png");
				
				file->setIcon(0, QIcon(fileType));
				file->setText(0, QString(ut->file_names[j]));
				file->setData(0, Qt::ToolTipRole, QVariant(QString(ut->file_names[j])));
				file->setData(0, Qt::UserRole, QVariant(QString(ut->file_names[j])));
				sToken->addChild(file);
			}
		}
	}
}
