/*
    Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu>
    Copyright 2010 Stefan Majewsky <majewsky@gmx.net>

    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 "newgame.h"
#include "game.h"

#include <QFileDialog>
#include <QLabel>
#include <QListWidget>
#include <QPushButton>
#include <QStandardPaths>
#include <QVBoxLayout>

#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <KSharedConfig>

#include <KGameHighScoreDialog>

NewGameDialog::NewGameDialog(bool enableCourses)
	: KPageDialog()
{
	setWindowTitle(i18nc("@title:window", "New Game"));
	buttonBox()->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
	setMinimumSize(640,310);
	connect(buttonBox(), &QDialogButtonBox::accepted, this, &NewGameDialog::slotOk);

	setFaceType(KPageDialog::Tree);
	this->enableCourses = enableCourses;

	KSharedConfig::Ptr config = KSharedConfig::openConfig();
        // following use this group
        KConfigGroup configGroup(config->group(QStringLiteral("New Game Dialog Mode")));

	// lots o' colors :)
	startColors << Qt::blue << Qt::red << Qt::yellow << Qt::lightGray << Qt::cyan << Qt::darkBlue << Qt::magenta << Qt::darkGray << Qt::darkMagenta << Qt::darkYellow;

	playerPage = new QFrame();
	addPage(playerPage, i18nc("@title:tab", "Players"));

	QVBoxLayout *bigLayout = new QVBoxLayout(playerPage);

	addButton = new QPushButton(i18nc("@action:button", "&New Player"), playerPage);
	bigLayout->addWidget(addButton);

	connect(addButton, &QPushButton::clicked, this, &NewGameDialog::addPlayer);

	scroller = new QScrollArea(playerPage);
	bigLayout->addWidget(scroller);
	playersWidget = new QWidget(playerPage);
	scroller->setWidget(playersWidget);
	new QVBoxLayout(playersWidget);

	QMap<QString, QString> entries = config->entryMap(QStringLiteral("New Game Dialog"));
	int i = 0;
	for (QMap<QString, QString>::Iterator it = entries.begin(); it != entries.end(); ++it)
	{
		if (i > startColors.count())
			return;

		addPlayer();
		editors.last()->setName(it.key().right(it.key().length() - 1));
		editors.last()->setColor(QColor(it.value()));
		++i;
	}

	if (editors.isEmpty())
	{
		addPlayer();
		addPlayer();
	}

	enableButtons();
	KPageWidgetItem *pageItem =nullptr;
	if (enableCourses)
	{
		coursePage = new QFrame();
		pageItem = new KPageWidgetItem( coursePage, i18nc("@title:tab", "Course") );
		pageItem->setHeader(i18nc("@title", "Choose Course to Play"));
		addPage(pageItem);
		QVBoxLayout *coursePageLayout = new QVBoxLayout(coursePage);

		QHBoxLayout *hlayout = new QHBoxLayout;
                coursePageLayout->addLayout( hlayout );


		// find other courses
		externCourses = configGroup.readEntry("extra",QStringList());

		/// course loading
		QStringList files;
		const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("courses"), QStandardPaths::LocateDirectory);
		for (const QString& dir : dirs) {
			const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*"), QDir::Files);
			for (const QString& file : fileNames) {
				files.append(dir + QLatin1Char('/') + file);
			}
		}
		const QStringList items = externCourses + files;

		QStringList nameList;
		const QString lastCourse(configGroup.readEntry("course", ""));
		int curItem = 0;
		i = 0;
		for (QStringList::const_iterator it = items.begin(); it != items.end(); ++it, ++i)
		{
			QString file = *it;
			CourseInfo curinfo;
			KolfGame::courseInfo(curinfo, file);
			info[file] = curinfo;
			names.append(file);
			nameList.append(curinfo.name);

			if (lastCourse == file)
				curItem = i;
		}

		const QString newName(i18nc("@item", "<Create New>"));
		info[QString()] = CourseInfo(newName, newName, i18n("You"), 0, 0);
		names.append(QString());
		nameList.append(newName);

		courseList = new QListWidget(coursePage);
		hlayout->addWidget(courseList);
		courseList->addItems(nameList);
		courseList->setCurrentRow(curItem);
		connect(courseList, &QListWidget::currentRowChanged, this, &NewGameDialog::courseSelected);
		connect(courseList, &QListWidget::itemSelectionChanged, this, &NewGameDialog::selectionChanged);

		QVBoxLayout *detailLayout = new QVBoxLayout;
                hlayout->addLayout( detailLayout );
		name = new QLabel(coursePage);
		detailLayout->addWidget(name);
		author = new QLabel(coursePage);
		detailLayout->addWidget(author);

		QHBoxLayout *minorLayout = new QHBoxLayout;
                detailLayout->addLayout( minorLayout );
		par = new QLabel(coursePage);
		minorLayout->addWidget(par);
		holes = new QLabel(coursePage);
		minorLayout->addWidget(holes);

		detailLayout->addStretch();
		auto *scores = new QPushButton(i18nc("@action:button", "Highscores"), coursePage);
		connect(scores, &QPushButton::clicked, this, &NewGameDialog::showHighscores);
		detailLayout->addWidget(scores);

		detailLayout->addStretch();
		detailLayout->addWidget(new KSeparator(coursePage));

		minorLayout = new QHBoxLayout;
                detailLayout->addLayout( minorLayout );

		auto *addCourseButton = new QPushButton(i18nc("@action:button", "Add…"), coursePage);
		minorLayout->addWidget(addCourseButton);
		connect(addCourseButton, &QPushButton::clicked, this, &NewGameDialog::addCourse);

		remove = new QPushButton(i18nc("@action:button", "Remove"), coursePage);
		minorLayout->addWidget(remove);
		connect(remove, &QPushButton::clicked, this, &NewGameDialog::removeCourse);

		courseSelected(curItem);
		selectionChanged();
	}

	// options page
    optionsPage = new QFrame();
    pageItem = new KPageWidgetItem( optionsPage, i18nc("@title:tab", "Options") );
    pageItem->setHeader(i18nc("@title", "Game Options"));
    addPage(pageItem);

	QVBoxLayout *vlayout = new QVBoxLayout(optionsPage);

	mode = new QCheckBox(i18nc("@option:check", "&Strict mode"), optionsPage);
	vlayout->addWidget(mode);
	mode->setChecked(configGroup.readEntry("competition", false));

	QLabel *desc = new QLabel(i18n("In strict mode, undo, editing, and switching holes is not allowed. This is generally for competition. Only in strict mode are highscores kept."), optionsPage);
	desc->setTextFormat(Qt::RichText);
	desc->setWordWrap(true);
	vlayout->addWidget(desc);
}

NewGameDialog::~NewGameDialog()
{
	qDeleteAll(editors);
}

void NewGameDialog::slotOk()
{
	KSharedConfig::Ptr config = KSharedConfig::openConfig();
	KConfigGroup configGroup(config->group(QStringLiteral("New Game Dialog Mode")));

	configGroup.writeEntry("competition", mode->isChecked());
	if (enableCourses)
	{
		configGroup.writeEntry("course", currentCourse);
		configGroup.writeEntry("extra", externCourses);
	}

	config->deleteGroup(QStringLiteral("New Game Dialog"));

	PlayerEditor *curEditor = nullptr;
	int i = 0;
	for (; i < editors.count(); ++i) {
		curEditor = editors.at(i);
		configGroup.writeEntry(QString::number(i) + curEditor->name(), curEditor->color().name());
	}

	config->sync();
}

void NewGameDialog::courseSelected(int index)
{
	//BUG 274418: select first course if nothing selected (should not happen, but meh)
	if (index < 0)
		index = 0;
	currentCourse = names.at(index);

	CourseInfo &curinfo = info[currentCourse];

	name->setText(QStringLiteral("<strong>%1</strong>").arg(curinfo.name));

	author->setText(i18nc("@info author attribution", "By %1", curinfo.author));
	par->setText(i18nc("@info", "Par %1", curinfo.par));
	holes->setText(i18ncp("@info", "1 Hole", "%1 Holes", curinfo.holes));
}

void NewGameDialog::showHighscores()
{
	KGameHighScoreDialog *scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Custom1 | KGameHighScoreDialog::Score, this);
	scoreDialog->addField(KGameHighScoreDialog::Custom1, i18n("Par"), QStringLiteral("Par"));
	scoreDialog->setConfigGroup(qMakePair(QByteArray(info[currentCourse].untranslatedName.toUtf8() + " Highscores"), i18n("High Scores for %1", info[currentCourse].name)));
	scoreDialog->setComment(i18n("High Scores for %1", info[currentCourse].name));
	scoreDialog->show();
}

void NewGameDialog::removeCourse()
{
	QListWidgetItem* curItem = courseList->currentItem();
	if (!curItem)
		return;

	QString file = curItem->text();
	if (!externCourses.contains(file))
		return;

	names.removeAll(file);
	externCourses.removeAll(file);
	delete courseList->takeItem(courseList->currentRow());

	selectionChanged();
}

void NewGameDialog::selectionChanged()
{
	QListWidgetItem* curItem = courseList->currentItem();
	remove->setEnabled(curItem && externCourses.contains(curItem->text()));
}

void NewGameDialog::addCourse()
{
	QPointer<QFileDialog> fileLoadDialog = new QFileDialog(this);
	fileLoadDialog->setWindowTitle(i18nc("@title:window", "Pick Kolf Course"));
	fileLoadDialog->setMimeTypeFilters(QStringList(QStringLiteral("application/x-kourse")));
	fileLoadDialog->setAcceptMode(QFileDialog::AcceptOpen);
	fileLoadDialog->setFileMode(QFileDialog::ExistingFile);
	fileLoadDialog->exec();
        const QStringList files = fileLoadDialog->selectedFiles();
	delete fileLoadDialog;

	bool hasDuplicates = false;

	for (QStringList::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt)
	{
		if (names.contains(*fileIt) > 0)
		{
			hasDuplicates = true;
			continue;
		}

		CourseInfo curinfo;
		KolfGame::courseInfo(curinfo, *fileIt);
		info[*fileIt] = curinfo;
		names.prepend(*fileIt);
		externCourses.prepend(*fileIt);

		courseList->insertItem(0, new QListWidgetItem(curinfo.name));
	}

	if (hasDuplicates)
		KMessageBox::information(this, i18n("Chosen course is already on course list."));

	courseList->setCurrentItem(nullptr);
	courseSelected(0);
	selectionChanged();
}

void NewGameDialog::addPlayer()
{
	if (editors.count() >= startColors.count())
		return;


	PlayerEditor *pe = new PlayerEditor(i18n("Player %1", editors.count() + 1), startColors.at(editors.count()), playersWidget);
	editors.append(pe);
	pe->show();
	playersWidget->layout()->addWidget(pe);
	connect(pe, &PlayerEditor::deleteEditor, this, &NewGameDialog::deleteEditor);

	enableButtons();
	playersWidget->setMinimumSize(playersWidget->sizeHint());
}

void NewGameDialog::deleteEditor(PlayerEditor *editor)
{
	if (editors.count() < 2)
		return;

	editors.removeAll(editor);
	delete editor;

	enableButtons();
	playersWidget->setMinimumSize(playersWidget->sizeHint());
	playersWidget->resize(playersWidget->sizeHint());
}

void NewGameDialog::enableButtons()
{
	addButton->setEnabled(!(editors.count() >= startColors.count()));
}

/////////////////////////

PlayerEditor::PlayerEditor(const QString &startName, QColor startColor, QWidget *parent)
	: QWidget(parent)
{
	QHBoxLayout *layout = new QHBoxLayout(this);

	editor = new KLineEdit(this);
	layout->addWidget(editor);
	editor->setFrame(false);
	editor->setText(startName);
	layout->addStretch();
	layout->addWidget(colorButton = new KColorButton(startColor, this));
	colorButton->hide();
	auto *remove = new QPushButton(i18nc("@action:button", "Remove"), this);
	layout->addWidget(remove);
	connect(remove, &QPushButton::clicked, this, &PlayerEditor::removeMe);
}

void PlayerEditor::removeMe()
{
	Q_EMIT deleteEditor(this);
}

#include "moc_newgame.cpp"
