/***************************************************************************
 *   Copyright (C) 2004-2005 Artur Wiebe                                   *
 *   wibix@gmx.de                                                          *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <QLayout>
#include <QDebug>
#include <QProgressDialog>
#include <QHeaderView>
#include <QInputDialog>
#include <QLineEdit>

#include "history.h"
#include "common.h"



#define COL_TAG_NR	0	// m_tags, this col is hidden.
#define COL_TAG_NAME	1
#define COL_TAG_VAL	2

#define COL_MOVE_NR	0	// m_movelist
#define COL_MOVE	1
#define COL_MOVE_COMM	2


myHistory::myHistory(QWidget* parent)
	: QFrame(parent)
{
	setFixedWidth(240);

	m_gamelist = new QComboBox(this);
	connect(m_gamelist, SIGNAL(activated(int)),
		this, SLOT(slot_game_selected(int)));

	m_taglist = new QTreeWidget(this);
	m_taglist->setColumnCount(3);
	m_taglist->header()->hide();
	m_taglist->setColumnHidden(COL_TAG_NR, true);
//	m_taglist->header()->setStretchLastSection(true);
//	m_taglist->header()->setResizeMode(QHeaderView::Stretch);
	m_taglist->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
	connect(m_taglist, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
		this, SLOT(slot_modify_tag(QTreeWidgetItem*, int)));

	m_movelist = new QTreeWidget(this);
	m_movelist->setColumnCount(3);
	m_movelist->header()->setStretchLastSection(true);
	m_movelist->header()->setMovable(false);
	m_movelist->setRootIsDecorated(false);
	QStringList header;
	header << "#" << tr("Move") << tr("Comment");
	m_movelist->setHeaderLabels(header);
	//
	connect(m_movelist, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
		this, SLOT(slot_modify_comment(QTreeWidgetItem*, int)));
	connect(m_movelist,
		SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
		this,
		SLOT(slot_move(QTreeWidgetItem*, QTreeWidgetItem*)));

	// history
	/*
	gameUndo = new QAction(QIcon(":/icons/undo.png"), tr("&Undo"), this);
	connect(gameUndo, SIGNAL(triggered()), m_view, SLOT(slotUndo()));

	gameRedo = new QAction(QIcon(":/icons/redo.png"), tr("&Redo"), this);
	connect(gameRedo, SIGNAL(triggered()), m_view, SLOT(slotRedo()));

	gameContinue = new QAction(QIcon(":/icons/continue.png"),
			tr("&Continue"), this);
	connect(gameContinue, SIGNAL(triggered()), m_view, SLOT(slotContinue()));


	 */
	m_mode_icon = new QLabel(this);
	m_mode_icon->setFrameStyle(QFrame::Panel | QFrame::Sunken);

	m_undo = new QToolButton(this);
	m_undo->setIcon(QIcon(":/icons/undo.png"));
	m_undo->setToolTip(tr("Undo"));
	connect(m_undo, SIGNAL(clicked()), this, SLOT(slot_undo()));

	m_redo = new QToolButton(this);
	m_redo->setIcon(QIcon(":/icons/redo.png"));
	m_redo->setToolTip(tr("Redo"));
	connect(m_redo, SIGNAL(clicked()), this, SLOT(slot_redo()));

	m_cont = new QToolButton(this);
	m_cont->setIcon(QIcon(":/icons/continue.png"));
	m_cont->setToolTip(tr("Continue"));
	connect(m_cont, SIGNAL(clicked()), this, SLOT(slot_continue()));

	m_current = new QLabel(this);

	QHBoxLayout* history = new QHBoxLayout();
	history->addWidget(m_mode_icon);
//TODO	history->addStretch();
	history->addWidget(m_undo);
	history->addWidget(m_redo);
	history->addWidget(m_cont);
	history->addStretch();
	history->addWidget(m_current);

	// layout
	QVBoxLayout* vb = new QVBoxLayout(this);
	vb->setMargin(0);
	vb->addWidget(m_gamelist, 0);
	vb->addWidget(m_taglist, 2);
	vb->addWidget(m_movelist, 4);
	vb->addLayout(history);

	/*
	 * other stuff
	 */
	m_pdn = new Pdn();
	m_disable_moves = false;
	//
	m_paused = true;	// little hack ensures a mode change.
	m_freeplace = false;
	set_mode(false);
}


myHistory::~myHistory()
{
	delete m_pdn;
}


void myHistory::clear()
{
	m_gamelist->clear();
	m_pdn->clear();
	m_taglist->clear();
	m_movelist->clear();
}


void myHistory::setTag(PdnGame::Tag tag, const QString& val)
{
	QTreeWidgetItem* item = 0;
	QList<QTreeWidgetItem*> item_list = m_taglist->findItems(
			tag_to_string(tag), Qt::MatchExactly, COL_TAG_NAME);
	if(item_list.count()) {
		if(item_list.count() == 1)
			item = item_list[0];
		else
			qDebug() << __PRETTY_FUNCTION__ << "ERR";
	}

	if(item) {
		item->setText(COL_TAG_VAL, val);
	} else {
		item = new QTreeWidgetItem(m_taglist);
		item->setText(COL_TAG_NR, QString::number(tag));
		item->setText(COL_TAG_NAME, tag_to_string(tag));
		item->setText(COL_TAG_VAL, val);
	}

	if(tag==PdnGame::Type) {
		item->setText(COL_TAG_VAL, val + " ("
				+ typeToString(QString("%1").arg(val).toInt())
				+ ")");
	}

	m_game->set(tag, val);
//TODO	m_taglist->resizeColumnToContents(COL_TAG_NAME);
}


QString myHistory::getTag(PdnGame::Tag tag)
{
	QList<QTreeWidgetItem*> item_list = m_taglist->findItems(
			tag_to_string(tag), Qt::MatchExactly, COL_TAG_NAME);
	if(item_list.count() == 1)
		return item_list[0]->text(COL_TAG_VAL);
	return "";
}


QString myHistory::tag_to_string(PdnGame::Tag tag)
{
	switch(tag) {
	case PdnGame::Date:	return /*tr(*/"Date";//);
	case PdnGame::Site:	return /*tr(*/"Site";//);
	case PdnGame::Type:	return /*tr(*/"Type";//);
	case PdnGame::Event:	return /*tr(*/"Event";//);
	case PdnGame::Round:	return /*tr(*/"Round";//);
	case PdnGame::White:	return /*tr(*/"White";//);
	case PdnGame::Black:	return /*tr(*/"Black";//);
	case PdnGame::Result:	return /*tr(*/"Result";//);
	}

	return "Site";	// FIXME
}


void myHistory::appendMove(const QString& text, const QString& comm)
{
	m_disable_moves = true;

	QTreeWidgetItem* new_item = new QTreeWidgetItem(m_movelist);
	new_item->setText(COL_MOVE, text);
	new_item->setText(COL_MOVE_COMM, comm);

	int move_nr = (m_movelist->topLevelItemCount() - 2) / 2;
	PdnMove* m = m_game->getMove(move_nr);

	if(m_movelist->topLevelItemCount()%2) {
		m->m_second = text;
		m->m_comsecond = comm;
	} else {
		new_item->setText(COL_MOVE_NR, QString("%1.").arg(move_nr+1));
		m->m_first = text;
		m->m_comfirst = comm;
	}

	m_movelist->setCurrentItem(new_item);
	m_movelist->scrollToItem(new_item);

	// TODO
	m_movelist->resizeColumnToContents(COL_MOVE_NR);

	m_disable_moves = false;
}


void myHistory::slot_modify_comment(QTreeWidgetItem* item, int)
{
	if(!item || item==m_movelist->topLevelItem(0) || m_paused)
		return;

	bool ok;
	QString new_text = QInputDialog::getText(this, tr("Set Comment"),//FIXME
		tr("Comment")+":", QLineEdit::Normal, item->text(COL_MOVE_COMM),
		&ok);
	if(!ok)
		return;

	new_text.remove('{');
	new_text.remove('}');
	if(new_text != item->text(COL_MOVE_COMM)) {
		// gui
		item->setText(COL_MOVE_COMM, new_text);

		// pdn
		int index = m_movelist->indexOfTopLevelItem(item);
		PdnMove* move = m_game->getMove((index - 1) / 2);
		if(index%2==1)
			move->m_comfirst = new_text;
		else
			move->m_comsecond = new_text;
	}
}


void myHistory::slot_modify_tag(QTreeWidgetItem* item, int/* col*/)
{
	if(!item || m_paused)
		return;

	PdnGame::Tag tag =(PdnGame::Tag)item->text(COL_TAG_NR).toUInt();
	if(tag==PdnGame::Type) {
		return;
	}

	bool ok;
	QString new_text = QInputDialog::getText(this, tr("Set Tag"),//FIXME
		tr("Tag")+":", QLineEdit::Normal, item->text(COL_TAG_VAL), &ok);
	if(!ok)
		return;

	new_text.remove('"');
	new_text.remove('[');
	new_text.remove(']');

	if(new_text != item->text(COL_TAG_VAL)) {
		item->setText(COL_TAG_VAL, new_text);
		m_game->set(tag, new_text);
		if(tag==PdnGame::Event)
			m_gamelist->setItemText(m_gamelist->currentIndex(),
					new_text);
	}
}


bool myHistory::openPdn(const QString& filename, QString& log_text)
{
	if(!m_pdn->open(filename, this, tr("Reading file..."), log_text)) {
		set_mode(false);
		return false;
	}

	set_mode(true);

	m_gamelist->clear();
	m_movelist->clear();
	m_taglist->clear();

	QProgressDialog progress(this);
	progress.setModal(true);
	progress.setLabelText(tr("Importing games..."));
	progress.setRange(0, m_pdn->count());
	progress.setMinimumDuration(0);

	for(int i=0; i<m_pdn->count(); ++i) {
		if((i%10)==0)
			progress.setValue(i);
		m_gamelist->insertItem(i, m_pdn->game(i)->get(PdnGame::Event));
	}

	slot_game_selected(0);

	return true;
}


bool myHistory::savePdn(const QString& fn)
{
	return m_pdn->save(fn);
}


void myHistory::slot_game_selected(int index)
{
	if(index>=m_pdn->count()) {
		qDebug() << __PRETTY_FUNCTION__ << "Index" << index
			<< "out of range >=" << m_pdn->count();
		return;
	}

	m_game = m_pdn->game(index);
	m_movelist->clear();

	QTreeWidgetItem* root = new QTreeWidgetItem(m_movelist);
	for(int i=0; i<m_game->movesCount(); ++i) {
		PdnMove* m = m_game->getMove(i);

		appendMove(m->m_first, m->m_comfirst);
		if(m->m_second.length())
			appendMove(m->m_second, m->m_comsecond);
	}

	setTag(PdnGame::Site,	m_game->get(PdnGame::Site));
	setTag(PdnGame::Black,	m_game->get(PdnGame::Black));
	setTag(PdnGame::White,	m_game->get(PdnGame::White));
	setTag(PdnGame::Result,	m_game->get(PdnGame::Result));
	setTag(PdnGame::Date,	m_game->get(PdnGame::Date));
	setTag(PdnGame::Site,	m_game->get(PdnGame::Site));
	setTag(PdnGame::Type,	m_game->get(PdnGame::Type));
	setTag(PdnGame::Round,	m_game->get(PdnGame::Round));
	setTag(PdnGame::Event,	m_game->get(PdnGame::Event));

	// signal to view
	if(m_paused && !m_freeplace) {
		emit previewGame(m_game->get(PdnGame::Type).toInt());
	}

	m_movelist->setCurrentItem(root);
	slot_move(root, 0);
}


void myHistory::newPdn(const QString& event, bool freeplace)
{
	m_freeplace = freeplace;
	m_paused = !m_freeplace;	// FIXME - needed to force view update.
	set_mode(m_freeplace);

	PdnGame* game = m_pdn->newGame();
	game->set(PdnGame::Event, event);

	int index = m_gamelist->count();
	m_gamelist->insertItem(index, event);
	m_gamelist->setCurrentIndex(index);

	slot_game_selected(index);
}


QString myHistory::typeToString(int type)
{
	switch(type) {
		case ENGLISH:	   return tr("English draughts");
		case RUSSIAN:	   return tr("Russian draughts");
	};
	return tr("Unknown game type");
}


void myHistory::set_mode(bool paused)
{
	if(m_paused != paused) {
		m_paused = paused;

		if(m_paused) {
			if(m_freeplace) {
				m_mode_icon->setPixmap(QPixmap(":/icons/freeplace.png"));
				m_mode_icon->setToolTip(tr("Free Placement Mode"));
			 } else {
				m_mode_icon->setPixmap(QPixmap(":/icons/paused.png"));
				m_mode_icon->setToolTip(tr("Paused Mode"));
			 }
		} else {
			m_mode_icon->setPixmap(QPixmap(":/icons/logo.png"));
			m_mode_icon->setToolTip(tr("Play Mode"));
		}

		m_gamelist->setEnabled(m_paused);
		//FIXME	m_movelist->setEnabled(yes);

		emit newMode(m_paused, m_freeplace);
	}
}


void myHistory::slot_move(QTreeWidgetItem* item, QTreeWidgetItem*)
{
	// update history buttons.
	bool curr_is_first =
		(m_movelist->topLevelItem(0) == m_movelist->currentItem());
	bool curr_is_last = 
		(m_movelist->indexOfTopLevelItem(m_movelist->currentItem())
			== m_movelist->topLevelItemCount()-1);

	m_undo->setEnabled(!curr_is_first);
	m_redo->setEnabled(!curr_is_last);
	m_cont->setEnabled(m_paused);


	// process
	if(!item || !m_paused || m_disable_moves)
		return;

	do_moves();
}


void myHistory::history_undo(bool move_backwards)
{
	int next = m_movelist->indexOfTopLevelItem(m_movelist->currentItem())
		+ (move_backwards ? -1 : +1);

	if(next>=0 && next<m_movelist->topLevelItemCount())
		m_movelist->setCurrentItem(m_movelist->topLevelItem(next));
}


void myHistory::do_moves()
{
	QString moves;
	QTreeWidgetItem* item = m_movelist->currentItem();
	for(int i=0; i<m_movelist->topLevelItemCount(); ++i) {
		QTreeWidgetItem* cur = m_movelist->topLevelItem(i);
		moves += cur->text(COL_MOVE) + MOVE_SPLIT;
		if(m_movelist->topLevelItem(i)==item)
			break;
	}
	emit applyMoves(moves);
}


void myHistory::delete_moves()
{
	int curr = m_movelist->indexOfTopLevelItem(m_movelist->currentItem());
	while(m_movelist->topLevelItemCount() > curr+1) {
		delete m_movelist->topLevelItem(
				m_movelist->topLevelItemCount()-1);
	}
}


void myHistory::slot_undo()
{
	set_mode(true);
	history_undo(true);
	do_moves();
}

void myHistory::slot_redo()
{
	set_mode(true);
	history_undo(false);
	do_moves();
}


void myHistory::slot_continue()
{
	delete_moves();
	set_mode(false);
}


void myHistory::slotWorking(bool b)
{
	setEnabled(!b);
}