package com.editev.chess;

import com.editev.util.Filter;
import com.editev.util.Function;
import com.editev.util.Enum;
import com.editev.chess.piece.Piece;
import java.util.Enumeration;

/** A Game that can enumerate its legal Moves.
 *
 *  @see See the source here.
 */
public class EnumeratedGame extends Game {

    /** Enumeration of every legal move for this Game.  
     *  Don't change the game in the middle of getting the enumeration or this might not work.
     *  @return a new Enumeration of all legal moves for this game.
     */
    public Enumeration enumerateAllLegalMoves() {
        return
            new Enum.Filtered(            
                acceptLegalMoves,                           // filter accepts only legal moves..
                
                new Enum.Compound(                          // for each legal move for the piece.
                
                    new Enum.Mapped(    
                        constructMovesFromPieces,           // map Pieces to a list of moves for that Piece.

                        new Enum.Filtered(
                            acceptSquaresOnTheMove,         // filter accepts only pieces that are on-the move
                            move.source.getEnumeration()    // for each square on the board,
                        )
                    )
                )
            );
    }

    /** A Function that converts a Square to the Piece on that Square. */
    public class SquareToPiece implements Function {
        /** @param square a Square on the chessboard. 
         *  @return the Piece on that Square. */
        public Object eval( Object square ) { return getPiece( (Square) square ); }
    }
    
    /** An enumeration of all Moves for the piece in the Move. */
    public class AllMovesForPieceMoving extends Enum.Lookahead {
        /** the Piece that's doing the moving. */
        public final Piece piece;

        /** create the iterator starting with a Move. */
        public AllMovesForPieceMoving() { 
            this.piece = getPiece( move );   // get the Piece for this move.
            next = move;
            piece.firstMoveIndex( move );
        }

        /** Retrieve the next move (legal or not!)
         *  @see com.editev.util.Enum.Lookahead. */
        protected void next() { next = piece.incrementMoveIndex( move ) ? move : null; }
    }
    
    /** Constructs a list of Piece moves from a Square. */
    class ConstructMovesFromPieces implements Function {
        /** Create a new emumeration of the Pieces 
         *  @return an enumeration of moves for the piece moving. 
         *  @param discard ignore this:  we look at the central iterator Move.
         */
        public Object eval( Object discard ) { return new AllMovesForPieceMoving(); }
    };

    /** A class only accept legal moves. */
    class AcceptLegalMoves implements Filter {
        /** @param move a move to check for legality. 
         *  @return true if the Move is legal.*/
        public boolean accept( Object move ) { return !isIllegal( (Move) move ); }
    };

    /** Only accepts Squares containing pieces that are on-the-move. */
    class AcceptSquaresOnTheMove implements Filter {
        /** @param square a square which might have a Piece.
         *  
         *  @return true if the Square contains a Piece and that Piece is on-the-move.
         */
        public boolean accept( Object square ) {
            byte piece = getPieceIndex( (Square) square );
            return piece != NO_PIECE && isWhiteMove() == White.is( piece );
        }
    }    

    /** A Function that constructs a list of Piece moves from a Square in this Game. */
    Function constructMovesFromPieces   = new ConstructMovesFromPieces();
    
    /** A Filter that only accepts legal moves for this Game. */
    Filter   acceptLegalMoves           = new AcceptLegalMoves();
    
    /** A filter that only accepts Locations with pieces that are on-the-move for this game. */
    Filter   acceptSquaresOnTheMove     = new AcceptSquaresOnTheMove();

}