#include <iostream>
#include <string>
#include <GL/glut.h>

#include "CException.h"
#include "CMove.h"
#include "Pieces.h"
#include "CBoard.h"




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

char CPawn::GetChar() const
{
  return ((GetColor() == WHITE) ? 'P' : 'p');
}

CBasePiece* CPawn::GetCopy(CBoard* par) const
{
  CPawn* ret = new CPawn(par, GetX(), GetY(), GetColor());
  ret->EnPassant = EnPassant;
  return ret;
}

type_piece CPawn::GetType() const
{
  return PAWN;
}


bool CPawn::IsCheck(type_color Col) const
{
  if ((Col == EMPTY) || (Col == GetColor()))
    return false;

  char King = ((Col == WHITE) ? 'K' : 'k');

  if (GetY() == 7)
    return false;

  char DirY = ( (GetColor() == WHITE) ? 1 : -1);

  if (GetX() > 0)
    {
      if ((*GetParent())(GetX()-1, GetY()+DirY)->GetChar() == King)
        return true;
    }
  if (GetX() < 7)
    {
      if ((*GetParent())(GetX()+1, GetY()+DirY)->GetChar() == King)
        return true;
    }

  return false;
}

bool CPawn::IsMoveValid(const CMove& move) const
{
  bool Valid = false;
  if ( (move.GetSourceX() != GetX()) || (move.GetSourceY() != GetY()) )
    return false;

  char DirX = move.GetDestinationX() - move.GetSourceX();
  char DirY = move.GetDestinationY() - move.GetSourceY();

  if ((DirX == 0) && (DirY == ( (GetColor() == WHITE) ? 1 : -1 )) &&
      ((*GetParent())(move.GetDestinationX(),
                      move.GetDestinationY())->GetColor() == EMPTY) )
    Valid = true;

  if ((DirX == 0) && (DirY == ( (GetColor() == WHITE) ? 2 : -2 )) &&
      ((*GetParent())(move.GetDestinationX(),
                      move.GetDestinationY())->GetColor() == EMPTY) &&
      ((*GetParent())(move.GetDestinationX(),
                      move.GetDestinationY()-((GetColor() == WHITE) ? 1 : -1 )
                      )->GetColor() == EMPTY) &&
      (GetY() == ((GetColor() == WHITE) ? 1 : 6 )) )
    Valid = true;

  if ( (abs(DirX) == 1) && (DirY == ( (GetColor() == WHITE) ? 1 : -1 )) &&
       ((*GetParent())(move.GetDestinationX(),
                       move.GetDestinationY())->GetColor()
        == ( (GetColor() == WHITE) ? BLACK : WHITE)) )
    Valid = true;

  if ( (abs(DirX) == 1) && (DirY == ( (GetColor() == WHITE) ? 1 : -1 )) &&
       ((*GetParent())(move.GetDestinationX(),
                       move.GetDestinationY())->GetColor() == EMPTY) &&
       ((*GetParent())(move.GetDestinationX(), move.GetSourceY())->GetChar()
        == ( (GetColor() == WHITE) ? 'p' : 'P')))
    {
      CPawn* passant =
        (CPawn *) (*GetParent())(move.GetDestinationX(), move.GetSourceY());
      if (passant->EnPassant)
        Valid = true;
    }

  if (Valid)
    {
      CBoard copy = *GetParent();
      copy.Move(move);

      if (copy.IsCheck(GetColor()))
        return false;
    }
  else
    {
      return false;
    }

  return true;
}

void CPawn::MoveAlert(const CMove& move)
{
  EnPassant = ( ( (move.GetSourceX() == GetX()) &&
                  (move.GetSourceY() == GetY()) ) &&
                (abs(move.GetDestinationY()-move.GetSourceY()) == 2) );

  if ( (move.GetSourceX() == GetX()) && (move.GetSourceY() == GetY()) )
    {
      // Check for en passant

      if ( (move.GetDestinationY() - move.GetSourceY() ==
            ( (GetColor() == WHITE) ? 1 : -1)) &&
           (abs(move.GetSourceX()-move.GetDestinationX()) == 1) &&
           ((*GetParent())(move.GetDestinationX(),
                           move.GetDestinationY())->GetColor() == EMPTY) )
        {
          delete (*GetParent())(move.GetDestinationX(), move.GetSourceY());
          (*GetParent())(move.GetDestinationX(), move.GetSourceY()) =
            new CEmpty(GetParent(), move.GetDestinationX(), move.GetSourceY());
          if ( (*GetParent())(move.GetDestinationX(), move.GetSourceY()) == 0)
            {
              std::cerr << MEMORY_ERROR.GetErrorString();
              exit(1);
            }
        }

      // Check for promotion

      if ( (move.GetSourceX() == GetX()) && (move.GetSourceY() == GetY()) )
        {
          if (GetY() == ( (GetColor() == WHITE) ? 6 : 1))
            {
              GetParent()->SetToDelete(this);
              switch (GetParent()->GetPromotion())
                {
                case (BISHOP):
                  (*GetParent())(GetX(), GetY()) =
                    new CBishop(GetParent(), GetX(), GetY(), GetColor());
                  break;
                case (CASTLE):
                  (*GetParent())(GetX(), GetY()) =
                    new CCastle(GetParent(), GetY(), GetY(), GetColor(), true);
                case (KNIGHT):
                  (*GetParent())(GetX(), GetY()) =
                    new CKnight(GetParent(), GetX(), GetY(), GetColor());
                  break;
                case (QUEEN):
                default:
                  (*GetParent())(GetX(), GetY()) =
                    new CQueen(GetParent(), GetX(), GetY(), GetColor());
                  break;
                }

              if ((*GetParent())(GetX(), GetY()) == 0)
                {
                  std::cerr << MEMORY_ERROR.GetErrorString();
                  exit(1);
                }
            }
        }
    }
}
