#ifndef GPIECE_H
#define GPIECE_H

#include <qcolor.h>
#include <qcanvas.h>
#include <krandomsequence.h>

//-----------------------------------------------------------------------------
class GPieceInfo
{
 public:
	GPieceInfo();

	virtual uint nbBlocks() const = 0; // nb of blocks in a piece
	virtual uint nbTypes() const  = 0; // nb of combin. of block types in piece
	virtual uint nbForms() const  = 0; // nb of geometrical form of piece
	
	virtual const int *i(uint form) const = 0;
	virtual const int *j(uint form) const = 0;
	virtual uint value(uint type, uint n) const = 0;
	virtual uint form(uint type) const = 0;
	virtual uint nbConfigurations(uint type) const = 0;

	uint maxWidth()  const;
	uint maxHeight() const;

	virtual QPixmap *drawPixmap(uint blockWidth, uint blockHeight,
								uint blockType, uint blockMode,
								bool lighted) const = 0;
	
	virtual uint nbBlockTypes() const = 0; // nb of block types
	virtual uint nbBlockModes() const = 0; // nb of modes per block
	virtual uint garbageType() const = 0;
};

class SequenceArray : public QArray<QCanvasPixmapArray *>
{
 public:
	SequenceArray(uint blockWidth, uint blockHeight);
	~SequenceArray();

	uint blockWidth() const  { return _blockWidth; }
    uint blockHeight() const { return _blockHeight; }

 private:
	uint _blockWidth, _blockHeight;
};

//-----------------------------------------------------------------------------
class BlockInfo : public QCanvas
{
 public:
	BlockInfo(uint width, uint height, const SequenceArray &);
	const SequenceArray &sequences() const { return _sequences; }

 private:
	const SequenceArray &_sequences;
};

//-----------------------------------------------------------------------------
class Block
{
 public:
	Block();
	Block(uint);
	virtual ~Block();

	void setValue(uint, BlockInfo *);
	uint value() const { return _value; }
	bool isGarbage() const;
	void toggleLight();
	void setMode(uint mode);
	void move(int x, int y);
	void show(bool show);

 private:
	uint           _value;
	QCanvasSprite *sprite;

	Block(const Block &);             // disabled
	Block &operator =(const Block &); // disabled
};

//-----------------------------------------------------------------------------
class Piece
{
 public:
    Piece();
	~Piece();
	void copy(const Piece *, bool toNonGraphic);
	void setBlockInfo(BlockInfo *bi);
	static void setPieceInfo(const GPieceInfo *pi) { _info = pi; }
	static const GPieceInfo *info() { return _info; }

    uint nbBlocks() const { return blocks.size(); }
	uint nbConfigurations() const { return _info->nbConfigurations(type); }

	int  value(uint i) const        { return blocks[i].b->value(); }
	uint col(uint i, uint p) const  { return p + blocks[i].i; }
	uint line(uint i, uint l) const { return l - blocks[i].j; }
	int toX(uint col) const;
	int toY(uint line) const;

    int  minX() const;
    int  maxX() const;
	int  width() const { return maxX() - minX() + 1; }
    int  minY() const;
    int  maxY() const;
	int  height() const { return maxY() - minY() + 1; }

	void generateNext(int type = -1);
	void rotate(bool left, int x, int y);
	void move(int x, int y);
	void moveCenter();
	void show(bool show);
	
	void setRandomSequence(KRandomSequence *_random) { random = _random; }

	Block *garbageBlock() const;
	Block *takeBlock(uint i);

 private:
	typedef struct {
		Block *b;
		int i, j;
	} BlockData;
    QArray<BlockData>        blocks;
    uint                     type;
    KRandomSequence         *random;
	static const GPieceInfo *_info;
	BlockInfo               *binfo;

	Piece(const Piece &);             // disabled
	Piece &operator =(const Piece &); // disabled
	void moveBlock(uint i, int x, int y);
	void clean();
};

#endif
