package li.seiji.minichess.figure;

import li.seiji.minichess.*;

import java.util.List;
import java.util.function.Function;

import li.seiji.minichess.Board;
import li.seiji.minichess.Move;
import li.seiji.minichess.State;

public interface IFigure {

    /* INTERFACE */
    static boolean isMoveValid(State state, Move move) {
        if(!IFigure.isMoveWithinBounds(state, move)) return false;
        if(IFigure.getFieldPlayer(state, move.to) == state.turn) return false;
        return true;
    }



    /* HELPERS */
    static boolean isMoveWithinBounds(State state, Move move) {
        return (move.to.x >= 0 && move.to.x < Board.COLUMNS && move.to.y >= 0 && move.to.y < Board.ROWS);
    }
    static Player getFieldPlayer(State state, Square dst) {
        return Player.parseIdentifier(dst.getIdentifier(state));
    }

    //delta
    static int getMoveDeltaX(Move move) {
        return (move.to.x - move.from.x);
    }
    static int getMoveDeltaY(Move move) {
        return (move.to.y - move.from.y);
    }
    static int getAbsMoveDeltaX(Move move) {
        return Math.abs(getMoveDeltaX(move));
    }
    static int getAbsMoveDeltaY(Move move) {
        return Math.abs(getMoveDeltaY(move));
    }


    /* STRAIGHT */
    static boolean isStraightMove(Move move) {
        return (move.from.x == move.to.x && move.from.y != move.to.y) ||
                (move.from.x != move.to.x && move.from.y == move.to.y);
    }
    static int getStraightMoveLen(Move move) {
        if(move.from.x == move.to.x) //y changed
            return getAbsMoveDeltaY(move);
        else //x changed
            return getAbsMoveDeltaX(move);
    }
    static boolean checkStraightIsBlocked(State state, Move move, Function<Player, Boolean> isBlockade) {
        for(int x = move.from.x; x < move.to.x; ++x) {
            Square square = new Square(x, move.to.y);
            if(isBlockade.apply(getFieldPlayer(state, square))) return true;
        }
        for(int y = move.from.y; y < move.to.y; ++y) {
            Square square = new Square(move.to.x, y);
            if(isBlockade.apply(getFieldPlayer(state, square))) return true;
        }
    }

    /* DIAGONAL */
    static boolean isDiagonalMove(Move move) {
        return getAbsMoveDeltaX(move) == getAbsMoveDeltaY(move);
    }
    static int getDiagonalMoveLen(Move move) {
        return getAbsMoveDeltaX(move);
    }

    static boolean isDestinationFieldAnEnemy(State state, Move move, Player currentPlayer) {
        Player fieldPlayer = getFieldPlayer(state, move.to);
        if(currentPlayer == Player.BLACK)
            return (fieldPlayer == Player.WHITE);
        else
            return (fieldPlayer == Player.BLACK);
    }





    static void scan(State state, List<Move> result, Square from, int dx, int dy, boolean stopShort, Capture capture) {
        int x = from.x, y = from.y;
        Player player = Player.parseIdentifier(state.board[x][y]);

        do {
            x += dx; y +=dy;

            if((x < 0 || x > Board.COLUMNS) || (y < 0 || y > Board.ROWS))
                break;

            if(state.board[x][y] != '.') {
                if(Player.parseIdentifier(state.board[x][y]) == player)
                    break;
                if(capture == Capture.FALSE)
                    break;
                stopShort = true;
            }
            else if(capture == Capture.ONLY)
                break;
            result.add(new Move(from, new Square(x, y)));
        } while(stopShort);
    }

    static void symmScan(State state, List<Move> result, Square from, int dx, int dy, boolean stopShort, Capture capture) {
        for(int i = 0; i < 4; i++) {
            scan(state, result, from, dx, dy, stopShort, capture);
            dx = dy;
            dy *= -1;
        }
    }

    static void symmScan(State state, List<Move> result, Square from, int dx, int dy, boolean stopShort) {
        symmScan(state, result, from, dx, dy, stopShort, Capture.TRUE);
    }

    static void moveList(State state, List<Move> result, Square from) {
        char identifier = state.board[from.y][from.x];
        boolean stopShort;

        switch (identifier) {
            case Queen.identifier:
            case King.identifier:
                stopShort = identifier == King.identifier;
                symmScan(state, result, from, 0, 1, stopShort);
                symmScan(state, result, from, 1, 1, stopShort);
                break;
            case Bishop.identifier:
            case Rook.identifier:
                stopShort = identifier == Bishop.identifier;
                Capture capture = identifier == Rook.identifier ? Capture.TRUE : Capture.FALSE;
                symmScan(state, result, from, 0, 1, stopShort, capture);
                if(identifier == Bishop.identifier) {
                    stopShort = false;
                    capture = Capture.TRUE;
                    symmScan(state, result, from, 1, 1, stopShort, capture);
                }
                break;
            case Knight.identifier:
                symmScan(state, result, from, 1, 2, true);
                symmScan(state, result, from, -1, 2, true);
                break;
            case Pawn.identifier:
                int dir = Player.parseIdentifier(identifier) == Player.BLACK ? -1 : 1;

                scan(state, result, from, -1, dir, true, Capture.ONLY);
                scan(state, result, from, 1, dir, true, Capture.ONLY);
                scan(state, result, from, 0, dir, true, Capture.FALSE);
        }

    }
}

@@ -837,16 +837,230 @@
 //delta%0A
+    static int getMoveDirX(Move move) %7B%0A        return getMoveDeltaX(move) / getAbsMoveDeltaX(move);%0A    %7D%0A    static int getMoveDirY(Move move) %7B%0A        return getMoveDeltaY(move) / getAbsMoveDeltaY(move);%0A    %7D%0A
     stat
@@ -1959,24 +1959,101 @@
 Blockade) %7B%0A
+        int xDir = getMoveDirX(move);%0A        int yDir = getMoveDirY(move);%0A%0A
         for(
@@ -2075,17 +2075,18 @@
 om.x; x 
-%3C
+!=
  move.to
@@ -2093,11 +2093,17 @@
 .x; 
-++x
+x += xDir
 ) %7B%0A
@@ -2278,17 +2278,18 @@
 om.y; y 
-%3C
+!=
  move.to
@@ -2296,11 +2296,17 @@
 .y; 
-++y
+y += yDir
 ) %7B%0A
@@ -2428,32 +2428,32 @@
 )) return true;%0A
-
         %7D%0A    %7D%0A
@@ -2438,32 +2438,54 @@
 true;%0A        %7D%0A
+        return false;%0A
     %7D%0A%0A    /* DI

Fix checkStraightIsBlocked()