#include "main.h"
#include "gamewidget.h"

#include "kpuzzle.h"
#include "kpuzzleapp.h"
#include "kpuzzlewidget.h"

#include <qpaintdevice.h>

KGameWidget::KGameWidget(QWidget *parent,KPuzzleApp* app) : QWidget(parent)
{
	_app = app;
	setMouseTracking(true);
	_piecePos = QPoint(-1,-1);
	_moveTimer = new QTimer(this);
	connect(_moveTimer,SIGNAL(timeout()),this,SLOT(slotMoveTimer()));
	_scrollPos = QPoint(0,0);
	setBackgroundMode(NoBackground);
	connect(this,SIGNAL(sigShowAt(QPoint)),this,SLOT(slotShowAt(QPoint)));
}

KGameWidget::~KGameWidget()
{
       delete _moveTimer;
}

void KGameWidget::initialize(QSize picSize)
{
	// This is necessary to avoid drawing problems
	if (picSize.width() < this->width()) setFixedWidth(picSize.width());
	if (picSize.height() < this->height()) setFixedHeight(picSize.height());
}

QRect KGameWidget::pieceRect()
{ 
	return QRect(_piecePos - QPoint(_app->displace(),_app->displace()),_app->pieceSizeDisp()); 
}

void KGameWidget::paintEvent(QPaintEvent* event)
{
	if (((KPuzzleWidget*) parent())->status() != GS_RUNNING) return;
	QRect logRect(DPtoLP(event->rect()));
	bitBlt(this,event->rect().topLeft(),_app->gamePixmap(),logRect,CopyROP,false);
	if (piecePos().x() == -1) return;
	QPixmap* pieceTurned = _app->currentPieceTurned(); // CAUTION: implicit new
	/*	if (_app->maskedPieces()) */
		bitBlt(this,_piecePos - QPoint(_app->displace(),_app->displace()),
		       pieceTurned,QRect(QPoint(0,0),_app->pieceSizeDisp()),CopyROP,false);
		/*	else
		 *		bitBlt(this,_piecePos, // Does this need to be forked? No
		 *		       pieceTurned,QRect(QPoint(0,0),_app->pieceSizeDisp()),CopyROP,false);
		 */
	delete pieceTurned;
}

void KGameWidget::mouseMoveEvent(QMouseEvent* event)
{
	if (((KPuzzleWidget*) parent())->status() != GS_RUNNING) return;
	// These are all absolute ccordinates
	QPoint prevPos(_piecePos);
	QRect oldRect(pieceRect());
	_piecePos = event->pos();
	QRect newRect(pieceRect());
	if (prevPos.x() != -1) newRect = newRect.unite(oldRect);
	update(newRect);
}

void KGameWidget::mousePressEvent(QMouseEvent* event)
{
	QPoint p; QPoint t;
	switch (event->button()) {
	case LeftButton:
		if (((KPuzzleWidget*) parent())->status() != GS_RUNNING) return;
		p = DPtoLP(event->pos());
		t = calculatePiecePos(p);
		if (!_app->setPiece(t)) return; 
		break;
	case RightButton:
		if (TOPWIDGET->turnPiecesAround())
			_app->turnCW();
		else
			_app->changeLRTurn();
		
		_app->updateAll();
		break;
	case MidButton:
		if (TOPWIDGET->turnPiecesAround())
			_app->turnCCW();
		else
			_app->changeUDTurn();

		_app->updateAll();
		break;
	}
}

void KGameWidget::leaveEvent(QEvent*)
{
	if (((KPuzzleWidget*) parent())->status() != GS_RUNNING) return;
	QRect rect(pieceRect());
	_piecePos = QPoint(-1,-1);
	update(rect);
}

QPoint KGameWidget::calculatePiecePos(QPoint p)
{
	// p is in logical coordinates
	// return value is position of the piece
	QSize ts(_app->pieceSize());
	QPoint szpt(ts.width(),ts.height());
	p += szpt / 2;
	QPoint r(p.x() / szpt.x(),p.y() / szpt.y());
	return r;
}

void KGameWidget::slotLeftPress()
{
	_moveTimer->start(MOVE_TIMER_INTERVAL);
	_moveKeyPressed = 1;
	slotMoveTimer();
}

void KGameWidget::slotLeftRelease()
{
	_moveTimer->stop();
	_moveKeyPressed = 0;
}

void KGameWidget::slotRightPress()
{
	_moveTimer->start(MOVE_TIMER_INTERVAL);
	_moveKeyPressed = 3;
	slotMoveTimer();
}

void KGameWidget::slotRightRelease()
{
	_moveTimer->stop();
	_moveKeyPressed = 0;
}

void KGameWidget::slotUpPress()
{
	_moveTimer->start(MOVE_TIMER_INTERVAL);
	_moveKeyPressed = 2;
	slotMoveTimer();
}

void KGameWidget::slotUpRelease()
{
	_moveTimer->stop();
	_moveKeyPressed = 0;
}

void KGameWidget::slotDownPress()
{
	slotMoveTimer();
	_moveTimer->start(MOVE_TIMER_INTERVAL);
	_moveKeyPressed = 4;
	slotMoveTimer();
}

void KGameWidget::slotDownRelease()
{
	_moveTimer->stop();
	_moveKeyPressed = 0;
}

void KGameWidget::slotMoveTimer()
{
	QPoint newPt;
	switch(_moveKeyPressed) {
	case 1: if (scrollPos().x() > 0) {
		newPt = QPoint(scrollPos().x() - 20,scrollPos().y());
		if (newPt.x() < 0) newPt.setX(0);	        
		emit sigShowAt(newPt);
	}
	//		scrollPos().setX(scrollPos().x() - 20);
		break;
	case 2: if (scrollPos().y() > 0) {
		newPt = QPoint(scrollPos().x(),scrollPos().y() - 20);
		if (newPt.y() < 0) newPt.setY(0);	        
		emit sigShowAt(newPt);
	}
		break;
	case 3: if (scrollPos().x() < _app->pixmapSize().width() - 
		    this->width()) {
		newPt = QPoint(scrollPos().x() + 20,scrollPos().y());
		if (newPt.x() > _app->pixmapSize().width() - this->width())
			newPt.setX(_app->pixmapSize().width() - this->width());
		emit sigShowAt(newPt);
	}
		break;
	case 4: if (scrollPos().y() < _app->pixmapSize().height() - 
		    this->height()) {
		newPt = QPoint(scrollPos().x(),scrollPos().y() + 20);
		if (newPt.y() > _app->pixmapSize().height() -  this->height())
			newPt.setY(_app->pixmapSize().height() - this->height());
		emit sigShowAt(newPt);
	}
		break;
	        
	
	}
}

void KGameWidget::slotShowAt(QPoint pos)
{
	// To avoid rounding problems
	pos.setX(min(pos.x(),_app->pixmapSize().width() - this->width()));
	pos.setY(min(pos.y(),_app->pixmapSize().height() - this->height()));
	scrollPos() = pos;
	((KPuzzleWidget*) parent())->updateButtons(!pos.x() == 0,!pos.y() == 0,
		   pos.x() < _app->pixmapSize().width() - this->width(),
		   pos.y() < _app->pixmapSize().height() - this->height());

	update();
}
