#ifndef COMMON_AI_H
#define COMMON_AI_H

#include <qtimer.h>
#include <qptrvector.h>

#include <kdialogbase.h>
#include <knuminput.h>
#include <krandomsequence.h>

#include "generic/gsettings.h"


class Board;
class Piece;

//-----------------------------------------------------------------------------
class AIElement
{
 public:
    struct Data {
        const char *name;
        bool triggered;
        int (*function)(const Board &, const Board &);
    };

    AIElement(const Data &data);
    ~AIElement();

    QString triggerName() const { return _triggerName; }
    QString coeffName() const { return _coeffName; }
    bool triggered() const { return _trigger; }
    double points(const Board &main, const Board &current) const;

 private:
    QString            _triggerName, _coeffName;
    const KConfigItem *_coeff, *_trigger;
    int (*_function)(const Board &, const Board &);
};

//-----------------------------------------------------------------------------
class AIPiece
{
 public:
	AIPiece();
    ~AIPiece();

    void init(const Piece *p, Board *b);
	bool place();
	bool increment();

    int dec() const  { return curDec; }
    uint rot() const { return curRot; }

 private:
	uint    nbPos, nbRot, curPos, curRot;
	int     curDec;
	const Piece *_piece;
    Piece       *_p;
    Board       *_board;

    void reset();
};

//-----------------------------------------------------------------------------
class AI : public QObject
{
 Q_OBJECT
 public:
    AI(uint thinkTime, uint orderTime);
	virtual ~AI();

    KConfigWidget *createConfigWidget();

	void launch(Board *main);
	void stop();
	void start();

 private slots:
	void timeout();
    void settingsChanged();

 protected:
    void addElement(const AIElement::Data &data);

	virtual void initThink();

	static int nbOccupiedLines(const Board &, const Board &);
	static int nbHoles(const Board &, const Board &);
	static int nbSpaces(const Board &, const Board &);
	static int peakToPeak(const Board &, const Board &);
	static int mean(const Board &, const Board &);
	static int nbRemoved(const Board &, const Board &);

    enum ElementType {
        Occupied = 0, Holes, Spaces, PeakToPeak, MeanHeight,
        NB_ELEMENT_TYPES };
    static const AIElement::Data ELEMENT_DATA[NB_ELEMENT_TYPES];

 private:
	bool think();
	void startTimer();
	bool emitOrder();
	double points() const;
    void resizePieces(uint size);

	QTimer                   timer;
	enum ThinkState { Thinking, GivingOrders };
	ThinkState               state;
	uint                     thinkTime, orderTime;
	bool                     stopped;
	QMemArray<AIPiece *>     pieces;
    QPtrVector<AIElement>    elements;
	Board                   *main, *board;
    KRandomSequence          random;

    bool   hasBestPoints;
    double bestPoints;
    int    bestDec;
    uint   bestRot;
};

//-----------------------------------------------------------------------------
class AIConfig : public KConfigWidget
{
 Q_OBJECT
 public:
    AIConfig(const QPtrVector<AIElement> &);

 private:
    void addElement(const AIElement *element, QGrid *grid);
};

#endif
