#ifndef PIECES_H
#define PIECES_H

enum type_color { WHITE, BLACK, EMPTY };
enum type_piece { PAWN, KNIGHT, BISHOP, CASTLE, QUEEN, KING, EMPTY_T };

class CBoard;

class CBasePiece
{
  char PosX;
  char PosY;
  type_color Color;

  CBoard* parent;

 public:
  CBasePiece(CBoard* par = 0, char x = -1, char y = -1,
             type_color color = WHITE)
    { parent = par, PosX = x; PosY = y; Color = color; }

  char GetX() const { return PosX; }
  char GetY() const { return PosY; }
  type_color GetColor() const { return Color; }
  CBoard* GetParent() const { return parent; }
  void SetX(char x) { PosX = x; }
  void SetY(char y) { PosY = y; }
  void SetColor(type_color TheColor) { Color = TheColor; }

  // Draw the piece 
  void Draw() const
    {
      if (GetType() != EMPTY_T)
        {
          float BaseX = GetType() / 6.0f, BaseY = GetColor() / 2.0f;

          glColor3f(1,1,1);
          glBegin(GL_QUADS);
          glTexCoord2f(BaseX,        BaseY+1/2.0f); glVertex2i(PosX,   PosY);
          glTexCoord2f(BaseX,        BaseY);        glVertex2i(PosX,   PosY+1);
          glTexCoord2f(BaseX+1/6.0f, BaseY);        glVertex2i(PosX+1, PosY+1);
          glTexCoord2f(BaseX+1/6.0f, BaseY+1/2.0f); glVertex2i(PosX+1, PosY);
          glEnd();
        }
    }
  void DragDraw(float x, float y) const
    {
      if (GetType() != EMPTY_T)
        {
          float BaseX = GetType() / 6.0f, BaseY = GetColor() / 2.0f;

          glColor3f(0.5,0.0,0.0);
          glBegin(GL_QUADS);			
          glTexCoord2f(BaseX,        0.5f); glVertex2i(PosX,   PosY);
          glTexCoord2f(BaseX,        0);    glVertex2i(PosX,   PosY+1);
          glTexCoord2f(BaseX+1/6.0f, 0);    glVertex2i(PosX+1, PosY+1);
          glTexCoord2f(BaseX+1/6.0f, 0.5f); glVertex2i(PosX+1, PosY);
          glEnd();

          glMatrixMode(GL_MODELVIEW);
          glLoadIdentity();
          glPushMatrix();
          glTranslatef(x,y,0);

          glColor3f(1,1,1);
          glBegin(GL_QUADS);
          glTexCoord2f(BaseX,        BaseY+0.5f); glVertex2i(0, 0);
          glTexCoord2f(BaseX,        BaseY);      glVertex2i(0, 1);
          glTexCoord2f(BaseX+1/6.0f, BaseY);      glVertex2i(1, 1);
          glTexCoord2f(BaseX+1/6.0f, BaseY+0.5f); glVertex2i(1, 0);
          glEnd();

          glPopMatrix();
        }
    }


  // Pure virtual functions

  // Returns the character corresponding to the piece,
  // lowercase for black and uppercase for white
  virtual char GetChar() const = 0;

  // Returns the type of the piece (and its index in the texture)
  virtual type_piece GetType() const = 0;

  // Returns a pointer to a copy of the object
  virtual CBasePiece* GetCopy(CBoard* par) const = 0;

  // Returns true if the piece is threatening the king
  // of the specified color
  virtual bool IsCheck(type_color Col) const = 0;

  // Returns true if the move is valid
  virtual bool IsMoveValid(const CMove& move) const = 0;

  // Dol the after-move stuff, such as setting move flags for
  // pawns, castles and king.
  virtual void MoveAlert(const CMove& move) = 0;
};




//////////////
//          //
//  BISHOP  //
//          //
//////////////

class CBishop : public CBasePiece
{
 public:
  CBishop(CBoard* par, char x = -1, char y = -1, type_color color = WHITE)
    : CBasePiece(par, x, y, color) {}

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



//////////////
//          //
//  CASTLE  //
//          //
//////////////

class CCastle : public CBasePiece
{
  bool HasMoved;

 public:
  CCastle(CBoard* par, char x = -1, char y = -1,
          type_color color = WHITE, bool hasmoved = false)
    : CBasePiece(par, x, y, color) { HasMoved = hasmoved; }

  bool GetHasMoved() const { return HasMoved; }
  void SetHasMoved(bool hm) { HasMoved = hm; }

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



/////////////
//         //
//  EMPTY  //
//         //
/////////////

class CEmpty : public CBasePiece
{
 public:
  CEmpty(CBoard* par, char x = -1, char y = -1)
    : CBasePiece(par, x, y, EMPTY) {}

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



//////////////
//          //
//   KING   //
//          //
//////////////

class CKing : public CBasePiece
{
  bool HasMoved;

 public:
  CKing(CBoard* par, char x = -1, char y = -1,
        type_color color = WHITE, bool hasmoved = false)
    : CBasePiece(par, x, y, color) { HasMoved = hasmoved; }

  bool GetHasMoved() const { return HasMoved; }
  void SetHasMoved(bool hm) { HasMoved = hm; }

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



//////////////
//          //
//  KNIGHT  //
//          //
//////////////

class CKnight : public CBasePiece
{
 public:
  CKnight(CBoard* par, char x = -1, char y = -1, type_color color = WHITE)
    : CBasePiece(par, x, y, color) {}

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



//////////////
//          //
//   PAWN   //
//          //
//////////////

class CPawn : public CBasePiece
{
  bool EnPassant;

 public:
  CPawn(CBoard* par, char x = -1, char y = -1, type_color color = WHITE)
    : CBasePiece(par, x, y, color) { EnPassant = false; }

  bool GetEnPassant() const { return EnPassant; }
  void SetEnPassant(bool ep) { EnPassant = ep; }

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};



/////////////
//         //
//  QUEEN  //
//         //
/////////////

class CQueen : public CBasePiece
{
 public:
  CQueen(CBoard* par, char x = -1, char y = -1, type_color color = WHITE)
    : CBasePiece(par, x, y, color) {}

  virtual char GetChar() const;
  virtual type_piece GetType() const;
  virtual CBasePiece* GetCopy(CBoard* par) const;
  virtual bool IsCheck(type_color Col) const;
  virtual bool IsMoveValid(const CMove& move) const;
  virtual void MoveAlert(const CMove& move);
};


#endif
