/*
 * puzzle.h -- Copyright (C) 1998 by M. G"otze
 */

#ifndef PUZZLE_H
#define PUZZLE_H

#include <qwidget.h>
#include <qcolor.h>
#include <qstring.h>
#include <qtimer.h>
#include <qevent.h>
#include <qdatetime.h>
#include <kstatusbar.h>


typedef unsigned int tInd;                             // type for tile indices
typedef unsigned char tOpt;        // type for option/state variables/constants
typedef struct {
  char *frameFileName, *tilesFileName;       // respective file name w/o suffix
  int frameSize;                    // width/height of outer frame/image inside
  int puzOffset, imgOffset;     // offset of frame/image relative to the widget
  QColor borderColor;                       // border color of unmoveable tiles
  float fixCoeffs[3];    // RGB coefficients to colorize monochrome fixed Tiles
} tScn;                               // type for a puzzle layout (frames etc.)

const tOpt stMoving = 0x01;
const tOpt stOrdering = 0x02;
const tOpt stCompleting = 0x04;
const tOpt stUncompleting = 0x08;
const tOpt stLoadingUncompleting = 0xaf;
const tOpt stGivingHint = 0x20;
const tOpt stLoading = 0xff;
const tOpt stInAction = 0x0f;
const tOpt stInitialized = 0x40;
const tOpt stComplete = 0x80;

const tOpt opSoundOn = 0x01;
const tOpt opRandomMissingTile = 0x02;
const tOpt opDefault = 0x03;

const tOpt fnFrame = 0;
const tOpt fnFrameMask = 1;
const tOpt fnTiles = 2;
const tOpt fnTilesMask = 3;

const tOpt moClassical3 = 0;
const tOpt moClassical4 = 1;
const tOpt moClassical5 = 2;
const tOpt moClassical6 = 3;
const tOpt moCorners = 4;
const tOpt moCross = 5;
const tOpt moDiamond = 6;
const tOpt moIsles = 7;
const tOpt moTriangle = 8;
const tOpt moLoadDefImage = 0x10;
const tOpt moKeepMode = 0x20;

const tInd maxTiles = 6;
const tInd noTile = maxTiles * maxTiles;
const tInd fixTile = noTile+1;

const int imageSize = 480;                      // width/height of puzzle image
 
/*const tScn scn =
  { "frame0", "tiles0", 565, 5, 47, QColor(80, 32, 16), { 1, .625, 0 } };*/

class KSlidePuzzle : public QWidget
{
  Q_OBJECT

  public:
    KSlidePuzzle(QWidget *parent = 0, const char *name = 0, const tOpt opt = opDefault);
    ~KSlidePuzzle();

    bool toggleSound();
    bool toggleRandomMissingTile();

    bool isIdle()
      { return !(getState(stInAction) || puz.scrambling); };
    bool isComplete()
      { return getState(stComplete); };
    bool randomMissingTile()
      { return getOption(opRandomMissingTile); };
    bool soundOn()
      { return getOption(opSoundOn); };

    bool loadImage(tOpt mode = moKeepMode, QString fileName = NULL);
    void scramble(const tInd moves);
    bool solveCheck(const bool honor = TRUE);
  /** Change the border's image */
  void setMask(int mask);
  /** Check if the player has reached the max move number */
  bool checkMaxMoves();
  /** set the max moves number to moves */
  void setMaxMoves( int moves );
  /*Set a pointer to the statusbar so as to change its displayed text*/
  void setStatusBar(KStatusBar*);
  /** Set the max allowed time to solve game to mins (in minutes) */
  void setMaxGameTime( int mins );
	/** set the max moves number to moves */
	void setMaxHints( int hints );
  /** change the game level */
  void setGameLevel(int level);
  /* Set Player's name */
  void setPlayername(QString name);
  /** Set the global border skin */
  void setFrameImage(QString);
  /** Set the tiles skin */
  void setTiledImage(QString);

  public slots:
    void scramble();
    void order();
  /** Save current game state */
  void slotSaveGame();
  /** Load a game... */
  void slotLoadGame();
  /** Start to order, giving a hint to the gamer */
  void slotGiveHint();
	void changeLevel();
	void slotChangeLevel();
  /** No descriptions */
  void slotStopHint();
  /** Displays the Hall Of Fame (hiscores) */
  void slotViewHallOfFame();

  signals:
    void sigStartedScrambling();
    void sigStoppedScrambling();
    void sigStartedOrdering();
    void sigStoppedOrdering();
    void sigPuzzleSolved();
    void sigChangeLevel();
    void toggleHint(bool);
    void enableMenus(bool);

  protected:
//    KAudio *audio;

    void paintEvent(QPaintEvent*);
    void drawPuzzle();
    void timerEvent(QTimerEvent*);
    void mousePressEvent(QMouseEvent*);
    void mouseMoveEvent(QMouseEvent*);

  private:
    tOpt state, options;
	int level;
	int maxmoves;
	int currentmoves;
	int timerid; //ID of the timer used to move blocks
	int gametimerid; //ID of the timer used for the game's time limit
	int displaytimerid; //ID of the timer used to display the remaining game time
	int usetimer; //-1 if one won't use a game limit, otherwise set to n msecs
	int timerlevelid; //
	int timerhintid;
	int maxlevel; //The number of puzzles;
	int maxhints; //Max nimber of hints
	int currenthints;
	int counterGivingHint_i, counterGivingHint_j; //Ordering step when giving a hint
	int gamelevel; //the difficulty level
	QString imagepath;
	QTime gametime; //The duration of current game
	KStatusBar* statusbar;
	int score;
	int nbmoves;
	QString playername;
	struct {
		int x;
		int y;
	} tilepos;
	QValueList<QPoint> tilelist;

struct {
  const char *frameFileName, *tilesFileName;       // respective file name w/o suffix
  int frameSize;                    // width/height of outer frame/image inside
  int puzOffset, imgOffset;     // offset of frame/image relative to the widget
  QColor borderColor;                       // border color of unmoveable tiles
  float fixCoeffs[3];    // RGB coefficients to colorize monochrome fixed Tiles
} scn;                               // type for a puzzle layout (frames etc.)

    struct {
      const char *path;
      QString prevImage;
      QCursor *cursors[7];
      unsigned char curCur;
      tOpt mode;
      QPixmap *frame;
      QPixmap *tiles[maxTiles * maxTiles];
      tInd pos[maxTiles * maxTiles];
      tInd movesTo[maxTiles * maxTiles];
      tInd size;
      tInd missingTile;
      tInd scrambling, prevScramble;
      QPoint prevMousePos;
    } puz;
    struct {
      tInd x, y;
      int delta;
      int step;
      int tVal;
      bool hor;
      QPixmap *buf;
    } ani;
    QString tempFileName;

    bool isMoving()
      { return getState(stMoving); };
    bool isLoading()
      { return getState(stLoading); };
    bool isLoadingUncompleting()
      { return getState(stLoadingUncompleting); };
    bool isOrdering()
      { return getState(stOrdering); };
    bool isCompleting()
      { return getState(stCompleting); };
    bool isUncompleting()
      { return getState(stUncompleting); };
    bool isGivingHint()
      { return getState(stGivingHint); };
    bool getState(const tOpt st)
      { return state & st; };
    void setState(const tOpt st, const bool enable)
      { if (enable) state |= st; else state -= state & st; };

    bool getOption(const tOpt op)
      { return options & op; };
    void setOption(const tOpt op, const bool enable)
      { if (enable) options |= op; else options -= options & op; };

    bool isFixTile(const unsigned int mode, const tInd index);
    bool isCorner(const tInd index);

    tInd coords2Index(const tInd size, const tInd x, const tInd y)
      { return y * size + x; };
    void index2Coords(const tInd size, const tInd index, tInd &x,
      tInd &y) { y = index / size; x = index % size; };
    tInd coords2Index(const tInd x, const tInd y)
      { return coords2Index(puz.size, x, y); };
    void index2Coords(const tInd index, tInd &x, tInd &y)
      { index2Coords(puz.size, index, x, y); };
    tInd tileSize(const tInd size)
      { return imageSize / size; };
    tInd tileSize()
      { return tileSize(puz.size); };
    tInd maxTile()
      { return puz.size * puz.size; };
    tInd lastTile()
      { return maxTile() - 1; };
    tInd movesTo(const tInd index);
    void updateMovesTos();
    void spiral(const tInd index, tInd &x, tInd &y);
    void chooseMissingTile();
    void drawTile(const tInd index);
    /*static*/ void swap(tInd &a, tInd &b)
      { tInd c = a; a = b; b = c;
      	if(!isGivingHint())tilelist.append(QPoint(a,b));};
    void moveTile(const tInd index);
    QString getFullPicPath(const char *dataFile);
    const char* getFullSoundPath(const char *dataFile);
    const char* getDataFileName(const tOpt file);
    void setCursor(unsigned char cur)
      { QWidget::setCursor(*puz.cursors[puz.curCur = cur]); };

};

#endif
