/*
 * QDigiDoc4
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "FileList.h"
#include "ui_ItemList.h"

#include "dialogs/FileDialog.h"
#include "dialogs/WarningDialog.h"
#include "widgets/FileItem.h"

#include <QDrag>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox>
#include <QMimeData>
#include <QMouseEvent>

using namespace ria::qdigidoc4;


FileList::FileList(QWidget *parent)
: ItemList(parent)
{
	connect(this, &FileList::add, this, &FileList::selectFile);
	connect(ui->download, &QToolButton::clicked, this, &FileList::saveAll);
}

void FileList::addFile( const QString& file )
{
	auto *item = new FileItem(file, state);
	item->installEventFilter(this);
	addWidget(item);

	connect(item, &FileItem::open, this, &FileList::open);
	connect(item, &FileItem::download, this, &FileList::save);
	connect(item, &FileItem::destroyed, this, &FileList::updateDownload);
	updateDownload();
}

void FileList::clear()
{
	ItemList::clear();
	documentModel = nullptr;
}

bool FileList::eventFilter(QObject *obj, QEvent *event)
{
	if(!qobject_cast<FileItem*>(obj))
		return ItemList::eventFilter(obj, event);
	switch(event->type())
	{
	case QEvent::MouseButtonPress:
	{
		auto *mouse = static_cast<QMouseEvent*>(event);
		if (mouse->button() == Qt::LeftButton)
			obj->setProperty("dragStartPosition", mouse->pos());
		break;
	}
	case QEvent::MouseMove:
	{
		auto *mouse = static_cast<QMouseEvent*>(event);
		if(!(mouse->buttons() & Qt::LeftButton))
			break;
		if((mouse->pos() - obj->property("dragStartPosition").toPoint()).manhattanLength()
			 < QApplication::startDragDistance())
			break;
		auto *fileItem = qobject_cast<FileItem*>(obj);
		if(!documentModel || !fileItem)
			break;
		int i = index(fileItem);
		if(i == -1)
			break;
		QString path = FileDialog::tempPath(fileItem->getFile());
		documentModel->save(i, path);
		documentModel->addTempReference(path);
		auto *mimeData = new QMimeData;
		mimeData->setText(QFileInfo(path).fileName());
		mimeData->setUrls({ QUrl::fromLocalFile(path) });
		auto *drag = new QDrag(this);
		drag->setMimeData(mimeData);
		drag->exec(Qt::CopyAction);
		return true;
	}
	default: break;
	}
	return ItemList::eventFilter(obj, event);
}

void FileList::init(const QString &container, const char *label)
{
	ItemList::init(ItemFile, label);
	this->container = container;
}

void FileList::open(FileItem *item) const
{
	if(int i = index(item); documentModel && i != -1)
		documentModel->open(i);
}

void FileList::removeItem(int row)
{
	if(!documentModel->removeRow(row))
		return;
	ItemList::removeItem(row);
	updateDownload();
}

void FileList::save(FileItem *item)
{
	if(int i = index(item); documentModel && i != -1)
	{
		QString extension = QFileInfo(item->getFile()).suffix();
		QString capitalized = extension[0].toUpper() + extension.mid(1);
		QString dest = FileDialog::getSaveFileName(this, FileDialog::tr("Save file"),
			QFileInfo(container).dir().absolutePath() + QDir::separator() + FileDialog::safeName(item->getFile()),
			QStringLiteral("%1 (*%2)").arg(capitalized, extension));

		if(!dest.endsWith(QStringLiteral(".%1").arg(extension)) && !extension.isEmpty())
				dest.append(QStringLiteral(".%1").arg(extension));

		if(dest.isEmpty())
			return;
		QFile::remove( dest );
		documentModel->save(i, dest);
	}
}

void FileList::saveAll()
{
	QString dir = QDir::toNativeSeparators(FileDialog::getExistingDirectory(this,
		tr("Select folder where files will be stored")));
	if( dir.isEmpty() )
		return;
	int b = QMessageBox::No;	// default
	for( int i = 0; i < documentModel->rowCount(); ++i )
	{
		QString dest = dir + QDir::separator() + FileDialog::safeName(documentModel->data(i));
		if( QFile::exists( dest ) )
		{
			if(b == QMessageBox::YesToAll)
			{
				QFile::remove( dest );
				documentModel->save( i, dest );
				continue;
			}
			b = WarningDialog::create(this)
				->withTitle(FileDialog::tr("Failed to save files"))
				->withText(tr("%1 already exists.<br />Do you want replace it?").arg(dest))
				->setCancelText(WarningDialog::Cancel)
				->addButton(WarningDialog::YES, QMessageBox::Yes)
				->addButton(WarningDialog::NO, QMessageBox::No)
				->addButton(tr("Save with other name"), QMessageBox::Save)
				->addButton(tr("Replace all"), QMessageBox::YesToAll)
				->exec();

			switch(b)
			{
			case QDialog::Rejected:
				return;
			case QMessageBox::No:
				continue;
			case QMessageBox::Save:
				if(dest = FileDialog::getSaveFileName(this, FileDialog::tr("Save file"), dest); dest.isEmpty())
					continue;
				break;
			default:
				QFile::remove(dest);
			}
		}
		documentModel->save( i, dest );
	}
}

void FileList::selectFile()
{
	if(!documentModel)
		return;

	const QFileInfo f(container);
	QString dir;
	if(f.isFile()) dir = f.dir().path();

	QStringList files = FileDialog::getOpenFileNames(this, tr("Add files"), dir);
	if (!files.isEmpty())
		emit addFiles(files);
}

void FileList::setModel(DocumentModel *documentModel)
{
	this->documentModel = documentModel;
	disconnect(documentModel, &DocumentModel::added, nullptr, nullptr);
	connect(documentModel, &DocumentModel::added, this, &FileList::addFile);

	auto count = documentModel->rowCount();
	for(int i = 0; i < count; i++)
		addFile(documentModel->data(i));
}

void FileList::stateChange(ria::qdigidoc4::ContainerState state)
{
	ItemList::stateChange(state);
		updateDownload();
}

void FileList::updateDownload()
{
	auto c = findChildren<FileItem*>().size();
	ui->download->setVisible(state & (UnsignedSavedContainer | SignedContainer | UnencryptedContainer) && c);
	ui->count->setVisible(state & (UnsignedSavedContainer | SignedContainer | UnencryptedContainer) && c);
	ui->count->setText(QString::number(c));
	if(state == EncryptedContainer && c == 0)
		addWidget(new LabelItem(QT_TRANSLATE_NOOP("LabelItem",
			"The container must be decrypted in order to see the contents of an encrypted container.")));
}
