/***************************************************************************
                           cubedialog.cpp
                           -------------------
    copyright            : (C) 2004 by Jos van den Oever
    email                : jos@vandenoever.info
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#include "cubedialog.h"
#include "questiongenerator.h"
//Added by qt3to4:
#include <QResizeEvent>
#include <QKeyEvent>
#include "sidelib.h"
#include "cube.h"
#include "scorekeeper.h"
#include "qcubelabel.h"
#include <qpushbutton.h>
#include <qlabel.h>
#include <iostream>

CubeDialog::CubeDialog(QWidget* parent, const char* name, Qt::WFlags f)
		: Q3VBox(parent, name, f) {
	// top label for messages
	msg = new QLabel("", this);
	Qt::Alignment alignment = Qt::AlignHCenter | Qt::AlignVCenter;
	msg->setWordWrap(true);
	msg->setAlignment(alignment);
	QSizePolicy qsp(QSizePolicy::Preferred, QSizePolicy::Fixed);
	msg->setSizePolicy(qsp);
	// first row of widgets
	Q3HBox *qhb = new Q3HBox(this);
	score = new ScoreKeeper(qhb);
	cube = new Cube(qhb);
	sides = new QCubeLabel(qhb);
	sides->setVisibleSides(6);
	// second row of widgets
	qhb = new Q3HBox(this);
	for (short i=0; i<4; i++) {
		answers[i] = new Cube(qhb);
	}
	// third row of widgets
	qhb = new Q3HBox(this);
	qhb->setSizePolicy(qsp);
	for (short i=0; i<4; i++) {
		answerButtons[i] = new QPushButton(QChar('A'+i), qhb);
		answerButtons[i]->setCheckable(true);
	}
	connect(answerButtons[0], SIGNAL(clicked()), this, SLOT(answerA()));
	connect(answerButtons[1], SIGNAL(clicked()), this, SLOT(answerB()));
	connect(answerButtons[2], SIGNAL(clicked()), this, SLOT(answerC()));
	connect(answerButtons[3], SIGNAL(clicked()), this, SLOT(answerD()));
	connect(cube, SIGNAL(animationFinished()), this, SLOT(answerA()));
	connect(answers[0], SIGNAL(animationFinished()), this, SLOT(answerB()));
	connect(answers[1], SIGNAL(animationFinished()), this, SLOT(answerC()));
	connect(answers[2], SIGNAL(animationFinished()), this, SLOT(answerD()));
	connect(answers[3], SIGNAL(animationFinished()),
			this, SLOT(afterAnimation()));
	connect(cube, SIGNAL(rotated()), this, SLOT(handleRotation()));
	connect(answers[0], SIGNAL(rotated()), this, SLOT(handleRotation()));
	connect(answers[1], SIGNAL(rotated()), this, SLOT(handleRotation()));
	connect(answers[2], SIGNAL(rotated()), this, SLOT(handleRotation()));
	connect(answers[3], SIGNAL(rotated()), this, SLOT(handleRotation()));
	// fourth row of widgets
	qhb = new Q3HBox(this);
	qhb->setSizePolicy(qsp);
	reset = new QPushButton(tr("restore question"), qhb);
	reset->setEnabled(false);
	connect(reset, SIGNAL(clicked()), this, SLOT(resetQuestion()));
	ok = new QPushButton(tr("Ok"),qhb);
	ok->setEnabled(false);
	connect(ok, SIGNAL(clicked()), this, SLOT(answer()));

	// initialze intern variables
	autoq = true;
	blanks = 0;
}
void
CubeDialog::resizeEvent(QResizeEvent *re) {
	msg->setFixedHeight(height()/10);
	Q3VBox::resizeEvent(re);
}
void
CubeDialog::setSideStyle(const SideStyle *ss) {
	style = ss;
}
void
CubeDialog::startQuestions() {
	// generate question if none are set by hand
	if (autoq) {
		readQuestions();
	}
	score->reset();
	score->setNumQuestions(questions.size());
	q = questions.begin();
	nextQuestion();
}
void
CubeDialog::nextQuestion() {
	msg->setText(tr("Choose the cube that is identical to the top cube."));
	if (q == questions.end()) {
		emit finished();
		return;
	}
	score->nextQuestion();
	cube->reset();
	cube->clear();
	for (short i=0; i<6; i++) {
		Side *s = &cube->getSide(i);
		switch (q->cube.sym[i]) {
		case C1:
			s->setPicture(style->getC1Picture(q->cube.type[i]));
			break;
		case C2:
			s->setPicture(style->getC2Picture(q->cube.type[i]));
			break;
		case C4:
		case none:
			s->setPicture(style->getC4Picture(q->cube.type[i]));
		}
		s->setRotation(q->cube.siderot[i]);
	}
	cube->setOrientation(0);
	cube->saveOrientation();
	sides->setCube(*cube);
	for (short i=0; i<4; i++) {
		CubeDecoration *a = &q->answers[i];
		answers[i]->clear();
		answers[i]->reset();
		for (short j=0; j<6; j++) {
			Side *s = &answers[i]->getSide(j);
			switch (a->sym[j]) {
			case C1:
				s->setPicture(style->getC1Picture(a->type[j]));
			break;
			case C2:
				s->setPicture(style->getC2Picture(a->type[j]));
				break;
			case C4:
			case none:
				s->setPicture(style->getC4Picture(a->type[j]));
			}
			s->setRotation(a->siderot[j]);
		}
		// rotate so three sides are visible
		// save target orientation
		answers[i]->setOrientation(0);
		answers[i]->saveOrientation();
		answers[i]->setOrientation(q->answers[i].orientation);
	}
	ok->setText(tr("Ok"));
	ok->setEnabled(false);
	reset->setEnabled(false);
	reset->setText(tr("restore question"));
	answered = false;
	restoreanswer = false;
	for (short i=0; i<4; i++) {
		answers[i]->setEnabled(true);
		answerButtons[i]->setChecked(false);
		answerButtons[i]->setEnabled(true);
	}
	answerButtons[0]->setFocus();
	beforeAnimation = true;
}
void
CubeDialog::resetQuestion() {
	cube->setOrientation(0);
	if (restoreanswer) {
		for (short i=0; i<4; i++) {
			answers[i]->setOrientation(0);
		}
	} else {
		for (short i=0; i<4; i++) {
			answers[i]->setOrientation(q->answers[i].orientation);
		}
	}
	if (answered) {
		stopAnim();
		if (restoreanswer) {
			reset->setText(tr("restore question"));
		} else {
			reset->setText(tr("restore answer"));
		}
		restoreanswer = !restoreanswer;
	} else {
		reset->setEnabled(false);
	}
}
void
CubeDialog::setQuestion(Question &que) {
/*	for (short i=0; i<6; ++i) {
		cerr << que.shownTypes[i] << " " << que.shownSyms[i] << " ";
	}
	cerr << endl;*/
	questions.clear();
	QuestionGenerator qg;
	qg.setBlanks(blanks);
	if (blanks > 1) {
		qg.setUniqueSides(true);
	}
	qg.setStyleRestrictions(style->amount(C1), style->amount(C2),
		style->amount(C4));
	qg.makeQuestion(que);
	if (!que.valid) {
		close();
		exit(0);
		return;
	}
	for (short i=0; i<6; ++i) {
		cout << que.shownTypes[i] << " " << que.shownSyms[i] << " ";
	}
	cout << endl;
	questions.push_back(que);
	q = questions.begin();
	autoq = false;
	startQuestions();
}
void
CubeDialog::readQuestions() {
	QuestionGenerator qg;
	qg.setBlanks(blanks);
	if (blanks > 1) {
		qg.setUniqueSides(true);
	}
	qg.setStyleRestrictions(style->amount(C1), style->amount(C2),
		style->amount(C4));
	questions.clear();

	for (short i=0; i<10; ++i) {
		Question que = qg.makeQuestion();
		if (que.valid) {
			questions.push_back(que);
		}
	}
}
void
CubeDialog::keyPressEvent ( QKeyEvent * e ) {
	int key = e->key();
	switch (key) {
	case 'A':
	case 'a':
		setAnswer(0);
		break;
	case 'B':
	case 'b':
		setAnswer(1);
		break;
	case 'C':
	case 'c':
		setAnswer(2);
		break;
	case 'd':
	case 'D':
		setAnswer(3);
		break;
	case Qt::Key_F5:
		update();
		break;
	}
}
void
CubeDialog::answerA() {
	setAnswer(0);
}
void
CubeDialog::answerB() {
	setAnswer(1);
}
void
CubeDialog::answerC() {
	setAnswer(2);
}
void
CubeDialog::answerD() {
	setAnswer(3);
}
void
CubeDialog::setAnswer(short j) {
	if (beforeAnimation) {
		// this handles signals from answers before the animation starts
		for (short i=0; i<4; i++) {
			if (j != i) {
				answerButtons[i]->setChecked(false);
			} else {
				answerButtons[i]->setChecked(true);
			}
		}
		ok->setEnabled(true);
		ok->setFocus();
	} else {
		// this handles signals from answers during the animation
		if (!stopAnimation) {
			answers[j]->animateToSavedOrientation();
		} else {
			afterAnimation();
		}
	}
}
void
CubeDialog::afterAnimation() {
	if (next) { // the animations must be finished and the ok button clicked
		++q;
		nextQuestion();
	}
	for (short i=0; i<4; i++) {
		answers[i]->setEnabled(true);
	}
	next = true;
}
void
CubeDialog::handleRotation() {
	reset->setEnabled(true);
}
const ScoreKeeper &
CubeDialog::getScore() const {
	return *score;
}
/* this function can be called to answer a question and also to advance to
   the next question */
void
CubeDialog::answer() {
	if (beforeAnimation) {
		// check answer
		answered = true;
		reset->setEnabled(true);
		short j=0;
		for (short i=0; i<4; i++) {
			if (answerButtons[i]->isChecked()) {
				j = i;
			}
			answers[i]->setEnabled(false);
			answerButtons[i]->setEnabled(false);
		}
		QString m;
		if (q->answer == j) {
			score->addPoints(1);
			m = tr("Well done! The correct answer is %1.");
		} else {
			m = tr("Wrong! The correct answer is %1.");
		}
		m = m.arg(QString(QChar('A'+q->answer)));
		msg->setText(m);
		// start animation to clarify answer
		beforeAnimation = false;
		next = false;
		list<Question>::iterator nq = q;
		if (++nq != questions.end()) {
			ok->setText(tr("Next question"));
		} else {
			ok->setText(tr("Continue"));
		}
		ok->setFocus();
		stopAnimation = false;
		cube->animateToSavedOrientation();
	} else {
		if (next) {
			++q;
			nextQuestion();
		} else {
			stopAnim();
			next = true;
		}
	}
}
void
CubeDialog::stopAnim() {
	stopAnimation = true;
	cube->stopAnimation();
	for (short i=0; i<4; i++) {
		answers[i]->stopAnimation();
	}
}
