package chess4j.io;

import java.text.ParseException;

import chess4j.Color;
import chess4j.board.Board;
import chess4j.board.CastlingRights;
import chess4j.board.File;
import chess4j.board.Rank;
import chess4j.board.Square;
import chess4j.pieces.Bishop;
import chess4j.pieces.King;
import chess4j.pieces.Knight;
import chess4j.pieces.Pawn;
import chess4j.pieces.Queen;
import chess4j.pieces.Rook;
import chess4j.utils.BlankRemover;


public class FenParser {
	private static boolean debug=true;
	
	public static String setPos(Board b,String fen) throws ParseException {
		if (fen==null)
			throw new ParseException("FEN is null",0);

		fen = fen.trim();
		b.clearBoard();

		fen = BlankRemover.trim(fen);
		// split on spaces
		String[] fen_pieces = fen.split(" ");
		if (fen_pieces.length < 4) 
			throw new ParseException("not enough parts to FEN.",0);
		
		setPieces(b,fen_pieces[0]);
		setPlayer(b,fen_pieces[1]);
		setCastlingRights(b,fen_pieces[2]);
		setEP(b,fen_pieces[3]);
		
		String remaining="";
		for (int i=4;i<fen_pieces.length;i++) {
			remaining += fen_pieces[i] + " ";
		}
		return remaining;
	}

	private static void setCastlingRights(Board b,String s) throws ParseException {
		if (debug)
			System.out.println("setCastlingRights: " + s);
		
		if (s.equals("-"))
			return;
		
		
		char[] arr = s.toCharArray();
		for (int i=0;i<arr.length;i++) {
			switch (arr[i]) {
			case 'K':
				b.addCastlingRight(CastlingRights.WHITE_KINGSIDE);
				break;
			case 'k':
				b.addCastlingRight(CastlingRights.BLACK_KINGSIDE);
				break;
			case 'Q':
				b.addCastlingRight(CastlingRights.WHITE_QUEENSIDE);
				break;
			case 'q':
				b.addCastlingRight(CastlingRights.BLACK_QUEENSIDE);
				break;
			default:
				throw new ParseException("invalid character in setCastlingRights: " + s,i);
			}
		}
	}

	private static void setEP(Board b,String s) throws ParseException {
		if (debug)
			System.out.println("setEP: " + s);

		if (s.equals("-"))
			return;
		
		char[] arr = s.toCharArray();
		if (arr.length != 2)
			throw new ParseException("invalid string in setEP: " + s,0);
		
		int epsq=0;
		if (arr[0]>='a' && arr[0]<='h')
			epsq=arr[0]-'a';
		else
			throw new ParseException("invalid string in setEP: " + s,0);
		
		if (arr[1]>='1' && arr[1]<='8')
			epsq+= 8 * (8-(arr[1]-'0'));
		else
			throw new ParseException("invalid string in setEP: " + s,0);
		
		b.setEP(Square.allSquares().get(epsq));
	}

	private static void setPieces(Board b,String s) {
		if (debug)
			System.out.println("setPieces: " + s);
		
		char[] arr = s.toCharArray();
		int sq=0;
		for (int i=0;i<arr.length;i++) {
			// map sq to a rank and file
			File f = File.file(sq&7);
			Rank r = Rank.rank(sq/8);
			Square square = Square.valueOf(f, r);
			switch (arr[i]) {
			case 'K':
				b.addPiece(King.WHITE_KING,square);
				sq++;
				break;
			case 'k':
				b.addPiece(King.BLACK_KING,square);
				sq++;
				break;
			case 'Q':
				b.addPiece(Queen.WHITE_QUEEN,square);
				sq++;
				break;
			case 'q':
				b.addPiece(Queen.BLACK_QUEEN,square);
				sq++;
				break;
			case 'R':
				b.addPiece(Rook.WHITE_ROOK,square);
				sq++;
				break;
			case 'r':
				b.addPiece(Rook.BLACK_ROOK,square);
				sq++;
				break;
			case 'N':
				b.addPiece(Knight.WHITE_KNIGHT,square);
				sq++;
				break;
			case 'n':
				b.addPiece(Knight.BLACK_KNIGHT,square);
				sq++;
				break;
			case 'B':
				b.addPiece(Bishop.WHITE_BISHOP,square);
				sq++;
				break;
			case 'b':
				b.addPiece(Bishop.BLACK_BISHOP,square);
				sq++;
				break;
			case 'P':
				b.addPiece(Pawn.WHITE_PAWN,square);
				sq++;
				break;
			case 'p':
				b.addPiece(Pawn.BLACK_PAWN,square);
				sq++;
				break;
			case '8': sq+=8; break;
			case '7': sq+=7; break;
			case '6': sq+=6; break;
			case '5': sq+=5; break;
			case '4': sq+=4; break;
			case '3': sq+=3; break;
			case '2': sq+=2; break;
			case '1': sq++;  break;
			}
		}
		assert(sq==64);
	}

	private static void setPlayer(Board b,String s) throws ParseException {
		if (debug)
			System.out.println("setPlayer: " + s);
		
		Color ptm;
		if (s.equalsIgnoreCase("b"))
			ptm = Color.BLACK;
		else if (s.equalsIgnoreCase("w"))
			ptm = Color.WHITE;
		else
			throw new ParseException("could not parse player: " + s,0);
		
		if (!ptm.equals(b.getPlayerToMove()))
			b.swapPlayer();
	}

}
