package org.amc.game.chess;

import static org.amc.game.chess.NoChessPiece.NO_CHESSPIECE;

import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;

/**
 * Contains the Rules of Chess
 * 
 * @author Adrian Mclaughlin
 *
 */
@Entity
@Table(name = "chessGames")
public class ChessGame extends AbstractChessGame {
    private static final long serialVersionUID = 5323277982974698086L;

    @Transient
    private final PlayerKingInCheckCondition kingInCheck = PlayerKingInCheckCondition.getInstance();

    protected ChessGame() {
        super();
    }

    public ChessGame(ChessBoard board, ChessGamePlayer playerWhite, ChessGamePlayer playerBlack) {
        super(board, playerWhite, playerBlack);
    }

    public ChessGame(AbstractChessGame chessGame) {
        super(chessGame);
    }

    @Override
    public void move(ChessGamePlayer player, Move move) throws IllegalMoveException {
        isPlayersTurn(player);
        isNeedToDoAPromotion();
        ChessPiece piece = getChessBoard().get(move.getStart());
        //checkChessPieceExistsOnSquare(piece, move);
        checkItsthePlayersPiece(player, piece);
        moveThePlayersChessPiece(player, getChessBoard(), piece, move);
        if (isOpponentsKingInCheck(player, getChessBoard())) {
            isOpponentKingInCheckMate(player);
        } else {
            PlayerInStalemate stalemate = new PlayerInStalemate(getOpposingPlayer(player), player,
                            getChessBoard());
            if (stalemate.isStalemate()) {
                setGameState(GameState.STALEMATE);
            }
        }
    }

    private void isPlayersTurn(Player player) throws IllegalMoveException {
        if (!ComparePlayers.isSamePlayer(getCurrentPlayer(), player)) {
            throw new IllegalMoveException("Not Player's turn");
        }
    }

    private void isNeedToDoAPromotion() throws IllegalMoveException {
        if (getGameState() == GameState.PAWN_PROMOTION) {
            throw new IllegalMoveException("Pawn Promotion need to be completed");
        }
    }

    private void checkChessPieceExistsOnSquare(ChessPiece piece, Move move)
                    throws IllegalMoveException {
        if (piece == NO_CHESSPIECE) {
            throw new IllegalMoveException("No piece at " + move.getStart());
        }
    }

    private void checkItsthePlayersPiece(ChessGamePlayer player, ChessPiece piece)
                    throws IllegalMoveException {
        if (notPlayersChessPiece(player, piece)) {
            throw new IllegalMoveException("Player can only move their own pieces");
        }
    }

    private boolean notPlayersChessPiece(ChessGamePlayer player, ChessPiece piece) {
        return player.getColour() != piece.getColour();
    }

    private void moveThePlayersChessPiece(ChessGamePlayer player, ChessBoard board,
                    ChessPiece piece, Move move) throws IllegalMoveException {
        if (isPlayersKingInCheck(player, board)) {
            doNormalMove(player, piece, move);
        } else if (doesAGameRuleApply(this, move)) {
            thenApplyGameRule(player, move);
        } else {
            doNormalMove(player, piece, move);
        }
    }

    boolean isPlayersKingInCheck(ChessGamePlayer player, ChessBoard board) {
        return kingInCheck.isPlayersKingInCheck(player, getOpposingPlayer(player), board);

    }

    boolean isOpponentsKingInCheck(ChessGamePlayer player, ChessBoard board) {
        ChessGamePlayer opponent = getOpposingPlayer(player);
        boolean inCheck = kingInCheck.isPlayersKingInCheck(opponent, player, board);
        if (inCheck) {
            setGameState(Colour.WHITE.equals(opponent.getColour()) ? GameState.WHITE_IN_CHECK
                            : GameState.BLACK_IN_CHECK);
        }
        return inCheck;
    }

    boolean isOpponentKingInCheckMate(ChessGamePlayer player) {
        ChessGamePlayer opponent = getOpposingPlayer(player);
        PlayersKingCheckmateCondition okcc = new PlayersKingCheckmateCondition(opponent, player,
                        getChessBoard());
        if (okcc.isCheckMate()) {
            setGameState(Colour.WHITE.equals(opponent.getColour()) ? GameState.WHITE_CHECKMATE
                            : GameState.BLACK_CHECKMATE);
            return true;
        } else {
            return false;
        }
    }

    private void doNormalMove(ChessGamePlayer player, ChessPiece piece, Move move)
                    throws IllegalMoveException {
        if (piece.isValidMove(getChessBoard(), move)) {
            thenMoveChessPiece(player, move);
        } else {
            throw new IllegalMoveException("Not a valid move");
        }
    }

    private void thenMoveChessPiece(ChessGamePlayer player, Move move) throws IllegalMoveException {
        ChessBoard testBoard = new ChessBoard(getChessBoard());
        testBoard.move(move);
        if (isPlayersKingInCheck(player, testBoard)) {
            throw new IllegalMoveException("King is checked");
        } else {
            setGameState(GameState.RUNNING);
            getChessBoard().move(move);
            this.allGameMoves.add(move);
        }
    }

    private void thenApplyGameRule(ChessGamePlayer player, Move move) throws IllegalMoveException {
        for (ChessMoveRule rule : getChessMoveRules()) {
            ChessGame testGame = new ChessGame(this);
            rule.applyRule(testGame, move);
            if (isPlayersKingInCheck(player, testGame.getChessBoard())) {
                throw new IllegalMoveException("King is checked");
            } else {
                rule.applyRule(this, move);
            }
        }
    }
}

@@ -26,70 +26,8 @@
 s;%0A%0A
-import static org.amc.game.chess.NoChessPiece.NO_CHESSPIECE;%0A%0A
 impo
@@ -55,16 +55,16 @@
 Entity;%0A
+
 import j
@@ -998,62 +998,8 @@
 ));%0A
-        //checkChessPieceExistsOnSquare(piece, move);%0A
     
@@ -1973,267 +1973,8 @@
  %7D%0A%0A
-    private void checkChessPieceExistsOnSquare(ChessPiece piece, Move move)%0A                    throws IllegalMoveException %7B%0A        if (piece == NO_CHESSPIECE) %7B%0A            throw new IllegalMoveException(%22No piece at %22 + move.getStart());%0A        %7D%0A    %7D%0A%0A
     
@@ -2118,42 +2118,46 @@
 if (
-notP
+p
 layer
-sChessPiece(player, piece
+.getColour() != piece.getColour(
 )) %7B
@@ -2238,24 +2238,24 @@
 n pieces%22);%0A
+
         %7D%0A  
@@ -2263,156 +2263,8 @@
  %7D%0A%0A
-    private boolean notPlayersChessPiece(ChessGamePlayer player, ChessPiece piece) %7B%0A        return player.getColour() != piece.getColour();%0A    %7D%0A%0A
     

remove check for piece on a square