#include "misc_ui.h"
#include "misc_ui.moc"

#include <qtimer.h>
#include "gpiece.h"
#include "board.h"
#include "defines.h"

/*****************************************************************************/
ShowNextPiece::ShowNextPiece(BlockInfo *bi, QWidget *parent,
							 const char *name)
: QFrame(parent, name)
{
	setFrameStyle( QFrame::Panel | QFrame::Sunken );
	view = new QCanvasView(bi, this);
	view->setGeometry(frameWidth(), frameWidth(),
					  bi->width()+5, bi->height()+5);
}

QSize ShowNextPiece::sizeHint() const
{
	return QSize(2*frameWidth() + view->width(),
				 2*frameWidth() + view->height());
}

QSizePolicy ShowNextPiece::sizePolicy() const
{
	return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

/*****************************************************************************/
Shadow::Shadow(const Board *board, int xOffset,
			   QWidget *parent, const char *name)
: QWidget(parent, name), _shown(FALSE), _p(this),
  _xOffset(xOffset), _board(board)
{
	_state.resize(_board->matrix().width());
	_state.fill(FALSE);
}

QSize Shadow::sizeHint() const
{
	return QSize(_xOffset + _board->matrix().width() * _board->blockWidth(),
				 SHADOW_HEIGHT);
}

QSizePolicy Shadow::sizePolicy() const
{
	return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

void Shadow::reveal(bool reveal)
{
	if ( _shown==reveal ) return;
	_shown = reveal;
	draw(!_shown, FALSE);
}

void Shadow::redraw(bool clear)
{
	if (clear) return; // the state is saved so no clearing needed
	if (_shown) draw(FALSE, TRUE);
}

void Shadow::paintEvent(QPaintEvent *)
{
	if (_shown) draw(FALSE, FALSE);
}

void Shadow::draw(bool erase, bool smart)
{
	const Piece *piece = _board->currentPiece();
	uint pf = piece->minX() + _board->currentCol();
	uint pl = pf + piece->width() - 1;

	for (uint i=0; i<_board->matrix().width(); i++) {
		if ( (i<pf || i>pl) || erase ) {
			if (_state[i]) {   // need deletion
			_state[i] = FALSE;
			drawBlock(i, TRUE);
			}
		} else if ( !_state[i] || !smart ) { // need drawing
				_state[i] = TRUE;
				drawBlock(i, FALSE);
		}
	}
}

void Shadow::drawBlock(uint i, bool erase)
{
	QRect r(_xOffset + i * _board->blockWidth() + 1 , 0,
			_board->blockWidth() - 2, SHADOW_HEIGHT);
	QColor col = (erase ? backgroundColor() : black);
	_p.setBrush(col);
	_p.setPen(col);
	_p.drawRect(r);
}

/*****************************************************************************/
GiftShower::GiftShower(uint timeout, QWidget *parent, const char *name)
: QWidget(parent, name), _timeout(timeout), _state(FALSE)
{}

QSize GiftShower::sizeHint() const
{
	return QSize(GI_WIDTH, GI_HEIGHT);
}

QSizePolicy GiftShower::sizePolicy() const
{
	return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

void GiftShower::set()
{
	if (_state) return;
	_state = TRUE;
	repaint();
	QTimer::singleShot(_timeout, this, SLOT(timeout()));
}

void GiftShower::timeout()
{
	_state = FALSE;
	repaint();
}

void GiftShower::paintEvent(QPaintEvent *)
{
	QPainter p(this);
	p.setBrush((_state ? yellow : black));
	p.setPen(black);
	p.drawRect(0, (height()-ARROW_HEIGHT)/2, ARROW_WIDTH, ARROW_HEIGHT);
	QPointArray a(3);
	a.setPoint(0, ARROW_WIDTH, 0);
	a.setPoint(1, width()-1, height()/2);
	a.setPoint(2, ARROW_WIDTH, height()-1);
	p.drawPolygon(a);
}
	
/*****************************************************************************/
// #### FIXME after KLed fixes commit
class Led : public QWidget // KLed
{
 public:
	Led(const QColor &c, QWidget *parent, const char *name=0)
		: QWidget(parent, name), col(c), _on(FALSE) {}
//		: KLed(c, Off, flat, Rectangular, parent, name) {}

	QSizePolicy sizePolicy() const
		{ return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); }
	QSize sizeHint() const { return QSize(LED_WIDTH, LED_HEIGHT); }

	void on()  { if (!_on) { _on = TRUE; repaint(); } }
	void off() { if (_on)  {_on = FALSE; repaint(); } }
	void setColor(const QColor &c) { if (c!=col) { col = c; repaint(); } }

 protected:
	void paintEvent(QPaintEvent *) {
		QPainter p(this);
		p.setBrush((_on ? col.light() : col.dark()));
		p.setPen(black);
		p.drawEllipse(0, 0, width(), height());
	}

 private:
	QColor col;
	bool   _on;
};

GiftPool::GiftPool(uint nbLeds, uint m,
				   QWidget *parent, const char *name)
: QHBox(parent, name), _timeout(GIFT_POOL_TIMEOUT), nb(0), max(m), ready(false)
{
	setSpacing(LED_SPACING);
	leds.resize(nbLeds);
	for (uint i=0; i<nbLeds; i++) leds[i] = new Led(yellow, this);
}

QSize GiftPool::sizeHint() const
{
	QSize s = (leds.size() ? leds[0]->sizeHint() : QSize());
	return QSize((s.width()+LED_SPACING)*leds.size()-LED_SPACING, s.height());
}

QSizePolicy GiftPool::sizePolicy() const
{
	return QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

void GiftPool::put(uint n)
{
	if ( n==0 ) return;
	if ( nb==0 && !ready ) QTimer::singleShot(_timeout, this, SLOT(timeout()));
	uint e = QMIN(nb+n, leds.size());
	for (uint i=nb; i<e; i++) leds[i]->on();
	uint f = QMIN(nb+n-e, leds.size());
	for (uint i=0; i<f; i++) leds[i]->setColor(red);
	nb += n;
}

uint GiftPool::take()
{
	ASSERT(ready);
	for (uint i=0; i<leds.size(); i++) {
		leds[i]->setColor(yellow);
		leds[i]->off();
	}
	if ( nb>max ) {
		uint p = nb - max;
		nb = 0;
		put(p);
		return max;
	} else {
		ready = FALSE;
		uint t = nb;
		nb = 0;
		return t;
	}
}
