#include "main.h"

#include <qpushbutton.h>
#include <qfiledialog.h>
#include <qpainter.h>
#include <qpen.h>
#include <qtimer.h>
#include <qmessagebox.h>
#include <qpixmap.h>

#include <kapp.h>

#include "kpuzzle.h"
#include "kpuzzlewidget.h"
#include "gamewidget.h"
#include "kpuzzleapp.h"
#include "piecewidget.h"
#include "picview.h"

#include "gamedialog.h"
#include "highscore.h"

KPuzzleWidget::KPuzzleWidget(QWidget *parent, const char *name)
	: QWidget(parent, name)
{
	setFixedSize(800,600);
	setBackgroundMode(PaletteDark);
	_game = new KPuzzleApp(this);

	_logoPxm = NULL;
	_bigLogoPxm = NULL;
	_winPxm = NULL;
	_losePxm = NULL;
	_pausePxm = NULL;

	_usedGamePixmaps = 0;

	if (TOPWIDGET->imageLoading() == IL_PRELOAD) 
		QTimer::singleShot(0,this,SLOT(slotLoadBackgroundPixmap()));
	useGamePixmap(GP_BIGLOGO);

}

KPuzzleWidget::~KPuzzleWidget()
{
	if (_logoPxm) delete _logoPxm;
	if (_bigLogoPxm) delete _bigLogoPxm;
	if (_winPxm) delete _winPxm;
	if (_losePxm) delete _losePxm;
	if (_pausePxm) delete _pausePxm;
	delete _game;
}

int KPuzzleWidget::status()
{
	return game()->status();
}

void KPuzzleWidget::updateAll()
{ 
	_gameWidget->update(); _pieceWidget->update(); 
}

void KPuzzleWidget::useGamePixmap(int which)
{
	if (which & _usedGamePixmaps) return; // already loaded
	switch(which) {
	case GP_BIGLOGO: _bigLogoPxm = new QPixmap(DATAFILE("biglogo.bmp")); break;
	case GP_PAUSE: _pausePxm = new QPixmap(DATAFILE("pause.bmp")); break;
	case GP_WIN: _winPxm = new QPixmap(DATAFILE("win.bmp")); break;
	case GP_LOSE: _losePxm = new QPixmap(DATAFILE("lose.bmp")); break;
	case GP_LOGO: _logoPxm = new QPixmap(DATAFILE("logo.bmp")); break;
	default: fatal("Terrible error in KPuzzleWidget::useGamePixmap");
	}
	_usedGamePixmaps |= which;				 
}

void KPuzzleWidget::freeGamePixmap(int which)
{
	if (TOPWIDGET->imageLoading() != IL_ON_USE) return;
	if (!(which & _usedGamePixmaps)) return; // not loaded
	switch(which) {
	case GP_BIGLOGO: delete _bigLogoPxm; _bigLogoPxm = NULL; break;
	case GP_PAUSE: delete _pausePxm; _pausePxm = NULL; break;
	case GP_WIN: delete _winPxm; _winPxm = NULL; break;
	case GP_LOSE: delete _losePxm; _losePxm = NULL; break;
	case GP_LOGO: delete _logoPxm; _logoPxm = NULL; break;
	default: fatal("Terrible error in KPuzzleWidget::useGamePixmap");
	}
	_usedGamePixmaps &= ~which;				 
}

void KPuzzleWidget::createPlayground(bool unbearable)
{
	_gameWidget = new KGameWidget(this,_game);
	_gameWidget->setGeometry(50,100,VISIBLE_PIXMAP_SIZE,
				 VISIBLE_PIXMAP_SIZE);
	_bLeft = new QPushButton("<",this);
	_bLeft->setGeometry(20,100,20,VISIBLE_PIXMAP_SIZE);
	_bUp = new QPushButton("Up",this);
	_bUp->setGeometry(50,70,VISIBLE_PIXMAP_SIZE,20);
	_bRight = new QPushButton(">",this);
	_bRight->setGeometry(510,100,20,VISIBLE_PIXMAP_SIZE);
	_bDown = new QPushButton("Down",this);
	_bDown->setGeometry(50,560,VISIBLE_PIXMAP_SIZE,20);

	_gameWidget->show();
	_bLeft->show();
	_bRight->show();
	_bUp->show();
	_bDown->show();

	connect(_bLeft,SIGNAL(pressed()),_gameWidget,SLOT(slotLeftPress()));
	connect(_bLeft,SIGNAL(released()),_gameWidget,SLOT(slotLeftRelease()));
	connect(_bRight,SIGNAL(pressed()),_gameWidget,SLOT(slotRightPress()));
	connect(_bRight,SIGNAL(released()),_gameWidget,
		SLOT(slotRightRelease()));
	connect(_bUp,SIGNAL(pressed()),_gameWidget,SLOT(slotUpPress()));
	connect(_bUp,SIGNAL(released()),_gameWidget,SLOT(slotUpRelease()));
	connect(_bDown,SIGNAL(pressed()),_gameWidget,SLOT(slotDownPress()));
	connect(_bDown,SIGNAL(released()),_gameWidget,SLOT(slotDownRelease()));

	_pieceWidget = new CPieceWidget(this,game());
	_pieceWidget->setGeometry(575,385,200,165);
	_bPrevPiece = new QPushButton("Previous",this);
	_bPrevPiece->setGeometry(575,355,200,20);
	_bNextPiece = new QPushButton("Next",this);
	_bNextPiece->setGeometry(575,561,200,20);
	_bTurn1 = new QPushButton("<",this);
	_bTurn1->setGeometry(545,385,20,80);
	_bTurn2 = new QPushButton(">",this);
	_bTurn2->setGeometry(545,470,20,80);

	_pieceWidget->show();
	_bPrevPiece->show();
	_bNextPiece->show();
	if (unbearable) {
		_bPrevPiece->setEnabled(false);
		_bNextPiece->setEnabled(false);
	}
	_bTurn1->show();
	_bTurn2->show();

	connect(_bNextPiece,SIGNAL(clicked()),_pieceWidget,
		SLOT(slotNextClicked()));
	connect(_bPrevPiece,SIGNAL(clicked()),_pieceWidget,
		SLOT(slotPrevClicked()));
	connect(_bTurn1,SIGNAL(clicked()),_pieceWidget,
		SLOT(slotTurn1Clicked()));
	connect(_bTurn2,SIGNAL(clicked()),_pieceWidget,
		SLOT(slotTurn2Clicked()));

	_picview = new CPicview(this);
	_picview->setGeometry(625,125,150,100);
	_picview->show();

	_fullview = new CPicview(this);
	_fullview->setGeometry(625,240,150,100);
	_fullview->show();

	connect(_picview,SIGNAL(sigChangeViewPos(QPoint)),_gameWidget,
		SLOT(slotShowAt(QPoint)));
	connect(_picview,SIGNAL(sigChangeViewPos(QPoint)),_fullview,
		SLOT(slotChangeViewPos(QPoint)));

	connect(_fullview,SIGNAL(sigChangeViewPos(QPoint)),_gameWidget,
		SLOT(slotShowAt(QPoint)));
	connect(_fullview,SIGNAL(sigChangeViewPos(QPoint)),_picview,
		SLOT(slotChangeViewPos(QPoint)));

	connect(_gameWidget,SIGNAL(sigShowAt(QPoint)),_picview,
		SLOT(slotChangeViewPos(QPoint)));
	connect(_gameWidget,SIGNAL(sigShowAt(QPoint)),_fullview,
		SLOT(slotChangeViewPos(QPoint)));

	_score = new QLCDNumber(4,this);
	_score->setGeometry(650,15,100,40);
	_score->show();
	connect(game(),SIGNAL(sigScore(int)),_score,SLOT(display(int)));

	_time = new QLCDNumber(6,this);
	_time->setGeometry(650,70,100,40);
	_time->show();
	connect(game(),SIGNAL(sigTime(const char*)),_time,
		SLOT(display(const char*)));

	connect(game(),SIGNAL(sigTerm(int)),this,SLOT(slotTerm(int)));
	
	game()->setStatus(GS_RUNNING);

	update();
}

void KPuzzleWidget::destroyPlayground()
{
	delete _gameWidget;
	delete _bLeft;
	delete _bRight;
	delete _bUp;
	delete _bDown;
	delete _pieceWidget;
	delete _bPrevPiece;
	delete _bNextPiece;
	delete _bTurn1;
	delete _bTurn2;
	delete _picview;
	delete _fullview;
	delete _score;
	delete _time;

	if (_largePxm) delete _largePxm;
	_largePxm = NULL;
	useGamePixmap(GP_BIGLOGO);
}

#define SHOWW(w) if (s) w->show(); else w->hide();

void KPuzzleWidget::showAll(bool s)
{
	SHOWW(_gameWidget);
	SHOWW(_bLeft);
	SHOWW(_bUp);
	SHOWW(_bRight);
	SHOWW(_bDown);
	SHOWW(_pieceWidget);
	SHOWW(_bPrevPiece);
	SHOWW(_bNextPiece);
	SHOWW(_bTurn1);
	SHOWW(_bTurn2);
	SHOWW(_picview);
	SHOWW(_fullview);
	SHOWW(_score);
	SHOWW(_time);
}

#undef SHOWW

void KPuzzleWidget::updateButtons(bool b1,bool b2,bool b3,bool b4)
{
	_bLeft->setEnabled(b1);
	if (!b1 && gameWidget()->moveKeyPressed() == 1) gameWidget()->slotLeftRelease();
	_bUp->setEnabled(b2);
	if (!b2 && gameWidget()->moveKeyPressed() == 2) gameWidget()->slotUpRelease();
	_bRight->setEnabled(b3);
	if (!b3 && gameWidget()->moveKeyPressed() == 3) gameWidget()->slotRightRelease();
	_bDown->setEnabled(b4);
	if (!b4 && gameWidget()->moveKeyPressed() == 4) gameWidget()->slotDownRelease();
}

void KPuzzleWidget::paintEvent(QPaintEvent* e)
{
	switch (game()->status()) {
	case GS_NOT_STARTED:
		if (_bigLogoPxm != NULL)
			bitBlt(this,QPoint(0,0),_bigLogoPxm,
			       _bigLogoPxm->rect(),CopyROP,false);
		return;
	case GS_SHOW_LARGE:
	case GS_SHOW_LARGE_WINNING:
	case GS_SHOW_LARGE_LOSING:
		bitBlt(this,QPoint(0,0),_largePxm,
		       _largePxm->rect(),CopyROP,false);
		return;
	case GS_WINNING:
		ASSERT(_winPxm);
		bitBlt(this,QPoint(0,0),_winPxm,_winPxm->rect(),CopyROP,false);
		return;
	case GS_LOSING:
		ASSERT(_losePxm);
		bitBlt(this,QPoint(0,0),_losePxm,_losePxm->rect(),CopyROP,false);
		return;
	case GS_PAUSED:
		ASSERT(_pausePxm != NULL);
		bitBlt(this,QPoint(0,0),_pausePxm,_pausePxm->rect(),CopyROP,false);
		return;
	case GS_SHOW_HIGHSCORES: 
		ASSERT(_largePxm);
		bitBlt(this,QPoint(0,0),_largePxm,
		       _largePxm->rect(),CopyROP,false);
		return;
	}

	if (game()->status() == GS_NOT_STARTED) return;

	QPainter pt(this);

	QPen redPen(red,2,SolidLine);
	pt.setPen(redPen);
	pt.moveTo(45,555);
	pt.lineTo(45,95);
	pt.lineTo(505,95);
	pt.moveTo(47,553);
	pt.lineTo(503,553);
	pt.lineTo(503,97);

	QPen dRedPen(darkRed,2,SolidLine);
	pt.setPen(dRedPen);
	pt.moveTo(47,553);
	pt.lineTo(47,97);
	pt.lineTo(503,97);
	pt.moveTo(45,555);
	pt.lineTo(505,555);
	pt.lineTo(505,95);

	QPen yellowPen(yellow,2,SolidLine);
	pt.setPen(yellowPen);
	pt.drawLine(537,0,537,599);

	QPen dYellowPen(darkYellow,2,SolidLine);
	pt.setPen(dYellowPen);
	pt.drawLine(540,0,540,599);
}

void KPuzzleWidget::mousePressEvent(QMouseEvent* e)
{
	switch (game()->status()) {
	case GS_PAUSED:
		game()->pause(false);
		update();
		break;
	case GS_SHOW_LARGE:
		game()->pause(false);
		delete _largePxm;
		_largePxm = NULL;
		update();
		break;
	case GS_SHOW_LARGE_WINNING:
		game()->setStatus(GS_SHOW_HIGHSCORES);
		update();
		break;
	case GS_SHOW_LARGE_LOSING:
		game()->setStatus(GS_SHOW_HIGHSCORES);
		update();
		break;
	case GS_LOSING:
		game()->setStatus(GS_SHOW_LARGE_LOSING);
		update();
		break;
	case GS_WINNING:
		game()->setStatus(GS_SHOW_LARGE_WINNING);
		update();
		break;
// 	case GS_SHOW_HIGHSCORES:
// 		delete _largePxm;
// 		_largePxm = NULL;
// 		game()->setStatus(GS_NOT_STARTED);
// 		destroyPlayground();
// 		useGamePixmap(GP_BIGLOGO);
// 		update();
// 		break;
	default:
		QWidget::mousePressEvent(e);	
		break;
	}
}

void KPuzzleWidget::slotTerm(int reason)
{

}

void KPuzzleWidget::slotLoadBackgroundPixmap()
{
	useGamePixmap(GP_BIGLOGO);
	repaint(false);
	useGamePixmap(GP_LOGO);
	useGamePixmap(GP_WIN);
	useGamePixmap(GP_LOSE);
	useGamePixmap(GP_PAUSE);
}

