package a7;

import java.util.Observable;

public abstract class ChessPiece extends Observable {

	private ChessPlayer owner;
	private ChessGame game;
	private ChessPosition position;
	protected char mark;

	protected ChessPiece(ChessPlayer owner, ChessGame game,
			ChessPosition init_position) {
		
		this.owner = owner;
		this.game = game;
		this.position = null;
		this.addObserver(this.getGame());
		
		game.getBoard().placePieceAt(this, init_position);
	}

	public ChessPlayer getOwner() {
		return owner;
	}

	public ChessGame getGame() {
		return game;
	}

	public ChessPosition getPosition() {
		return position;
	}

	public void setPosition(ChessPosition new_position) {
		position = new_position;
	}

	public void moveTo(ChessPosition destination) throws IllegalMove {
		// exception if destination holds piece by same player

		if (game.getBoard().getPieceAt(destination) != null) {
			if (game.getBoard().getPieceAt(destination).getOwner().getName()
					.equals(this.getOwner().getName())) {
				throw new IllegalMove(this, position, destination);
			}
		}

		// exception if the piece is at the desired location
		if (game.getBoard().getPieceAt(destination) == this) {
			throw new IllegalMove(this, position, destination);
		}

	}

	public char getMark() {
		return mark;
	}

	public boolean checkLineOfSight(ChessPosition start, ChessPosition end) {

		int deltay = 0;
		int deltax = 0;
		// this sets the stage for iteration

		if (start.getX() > end.getX()) {
			deltax = -1;
		}
		if (start.getX() < end.getX()) {
			deltax = 1;
		}
		if (start.getY() > end.getY()) {
			deltay = -1;
		}

		if (start.getY() < end.getY()) {
			deltay = 1;
		}

		if (deltax == 0 && deltay == 0) {
			return false;
		} else {

			ChessPosition intermediate = new ChessPosition(start.getX()
					+ deltax, start.getY() + deltay);

			while (((intermediate.getX() != end.getX()) || (intermediate.getY() != end
					.getY()))) {
				
				if (this.getGame().getBoard().getPieceAt(intermediate) != null) {
					return false;

				} else {
					intermediate = new ChessPosition(
							(intermediate.getX() + deltax), intermediate.getY()
									+ deltay);
				}

			}
			return true;

		}

	}
}

class Rook extends ChessPiece {
	public Rook(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'r';
		} else {
			mark = 'R';
		}
	}
	public String toString(){
		return "rook";
	}
	public void moveTo(ChessPosition destination) throws IllegalMove {

		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		
		
		super.moveTo(destination);
		if (super.checkLineOfSight(this.getPosition(), destination)) {
			if ((destination.getX() == this.getPosition().getX())
					|| (destination.getY() == this.getPosition().getY())) {

				if (this.getGame().getBoard().getPieceAt(destination) != null) {
					captured = this.getGame().getBoard().getPieceAt(destination);
					this.getGame().getBoard().removePieceFrom(destination);
					
				}
				this.getGame().getBoard().removePieceFrom(this.getPosition());
				this.getGame().getBoard().placePieceAt(this, destination);
			} else {
				throw new IllegalMove(this, this.getPosition(), destination);
			}

		} else {
			throw new IllegalMove(this, this.getPosition(), destination);
		}

		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
		
	}

}

class Bishop extends ChessPiece {
	public Bishop(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'b';
		} else {
			mark = 'B';
		}
	}
	public String toString(){
		return "bishop";
	}
	public void moveTo(ChessPosition destination) throws IllegalMove {
		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		super.moveTo(destination);
		if (super.checkLineOfSight(this.getPosition(), destination)) {
			if ((Math.abs(destination.getX() - this.getPosition().getX())) == Math
					.abs((destination.getY() - this.getPosition().getY()))) {

				if (this.getGame().getBoard().getPieceAt(destination) != null) {
					captured = this.getGame().getBoard().getPieceAt(destination);
					this.getGame().getBoard().removePieceFrom(destination);
					
				}
				this.getGame().getBoard().removePieceFrom(this.getPosition());
				this.getGame().getBoard().placePieceAt(this, destination);
			} else {
				throw new IllegalMove(this, this.getPosition(), destination);
			}

		} else {
			throw new IllegalMove(this, this.getPosition(), destination);
		}

		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
	}

}

class Knight extends ChessPiece {
	public Knight(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'n';
		} else {
			mark = 'N';
		}
	}
	public String toString(){
		return "knight";
	}
	
	public void moveTo(ChessPosition destination) throws IllegalMove {
		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		super.moveTo(destination);

		if ((Math.abs(this.getPosition().getY() - destination.getY()) + Math
				.abs((this.getPosition().getX() - destination.getX()))) == 3) {
			if ((this.getPosition().getY() != destination.getY())
					&& (this.getPosition().getX() != destination.getX())) {

				if (this.getGame().getBoard().getPieceAt(destination) != null) {
					captured = this.getGame().getBoard().getPieceAt(destination);
					this.getGame().getBoard().removePieceFrom(destination);
				}
				this.getGame().getBoard().removePieceFrom(this.getPosition());
				this.getGame().getBoard().placePieceAt(this, destination);

			} else {
				throw new IllegalMove(this, this.getPosition(), destination);
			}
		} else {
			throw new IllegalMove(this, this.getPosition(), destination);
		}
		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
		
	}

}

class Queen extends ChessPiece {
	public Queen(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'q';
		} else {
			mark = 'Q';
		}
	}
	public String toString(){
		return "queen";
	}
	public void moveTo(ChessPosition destination) throws IllegalMove {
		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		super.moveTo(destination);

		if (super.checkLineOfSight(this.getPosition(), destination)) {
			if (((Math.abs(destination.getX() - this.getPosition().getX())) == Math
					.abs((destination.getY() - this.getPosition().getY()))
					|| (destination.getX() == this.getPosition().getX()) || (destination
						.getY() == this.getPosition().getY()))) {

				if (this.getGame().getBoard().getPieceAt(destination) != null) {
					captured = this.getGame().getBoard().getPieceAt(destination);
					this.getGame().getBoard().removePieceFrom(destination);
				}
				this.getGame().getBoard().removePieceFrom(this.getPosition());
				this.getGame().getBoard().placePieceAt(this, destination);
			} else {
				throw new IllegalMove(this, this.getPosition(), destination);
			}

		} else {
			throw new IllegalMove(this, this.getPosition(), destination);
		}
		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
	}

}

class King extends ChessPiece {
	public King(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'k';
		} else {
			mark = 'K';
		}
	}
	public String toString(){
		return "king";
	}
	public void moveTo(ChessPosition destination) throws IllegalMove {
		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		super.moveTo(destination);
		if (Math.abs(this.getPosition().getY() - destination.getY()
				+ (this.getPosition().getX() - destination.getX())) <= 2) {
			if (this.getGame().getBoard().getPieceAt(destination) != null) {
				captured = this.getGame().getBoard().getPieceAt(destination);
				this.getGame().getBoard().removePieceFrom(destination);
			}
			this.getGame().getBoard().removePieceFrom(this.getPosition());
			this.getGame().getBoard().placePieceAt(this, destination);

		} else {
			throw new IllegalMove(this, this.getPosition(), destination);
		}
		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
	}

}

class Pawn extends ChessPiece {
	public Pawn(ChessPlayer owner, ChessGame game, ChessPosition init_position) {
		super(owner, game, init_position);
		if (owner == game.getPlayer1()) {
			mark = 'p';
		} else {
			mark = 'P';
		}

	}
	public String toString(){
		return "pawn";
	}
	public void moveTo(ChessPosition destination) throws IllegalMove {
		ChessPosition from = this.getPosition();
		ChessPosition to = destination;
		ChessPiece captured = null; 
		super.moveTo(destination);
		if (this.getOwner().getName() == "P1") {

			// if it's one row up and at most 1 to the right or left
			if ((destination.getY() == this.getPosition().getY() + 1)
					&& (Math.abs(destination.getX() - this.getPosition().getX()) <= 1)) {
				// if it's trying to kill forward right or forward left
				if (Math.abs(destination.getX() - this.getPosition().getX()) == 1) {
					// if there's a piece there (should already be checked
					// if the piece is the own players
					if (this.getGame().getBoard().getPieceAt(destination) != null) {
						captured = this.getGame().getBoard().getPieceAt(destination);
						this.getGame().getBoard().removePieceFrom(destination);
						
						this.getGame().getBoard()
								.removePieceFrom(this.getPosition());
						this.getGame().getBoard()
								.placePieceAt(this, destination);
					} else {
						throw new IllegalMove(this, this.getPosition(),
								destination);
					}
				} else {
					// if the forward position doesn't contain a piece
					if (this.getGame().getBoard().getPieceAt(destination) == null) {
						this.getGame().getBoard()
								.removePieceFrom(this.getPosition());
						this.getGame().getBoard()
								.placePieceAt(this, destination);
					} else {
						throw new IllegalMove(this, this.getPosition(),
								destination);
					}
				}

			} else {
				// if it's two directly ahead and it's in the starting
				// position then it's okay to move.
				if ((destination.getY() == this.getPosition().getY() + 2)
						&& (this.getPosition().getY() == 1)
						&& (Math.abs(destination.getX()
								- this.getPosition().getX()) == 0)) {
					this.getGame().getBoard()
							.removePieceFrom(this.getPosition());
					this.getGame().getBoard().placePieceAt(this, destination);
				} else {
					throw new IllegalMove(this, this.getPosition(), destination);
				}
			}

		}

		else {

			// if it's one row up and at most 1 to the right or left
			if ((destination.getY() == this.getPosition().getY() - 1)
					&& (Math.abs(destination.getX() - this.getPosition().getX()) <= 1)) {
				// if it's trying to kill forward right or forward left
				if (Math.abs(destination.getX() - this.getPosition().getX()) == 1) {
					// if there's a piece there (should already be checked
					// if the piece is the own players
					if (this.getGame().getBoard().getPieceAt(destination) != null) {
						captured = this.getGame().getBoard().getPieceAt(destination);
						this.getGame().getBoard().removePieceFrom(destination);
						this.getGame().getBoard()
								.removePieceFrom(this.getPosition());
						this.getGame().getBoard()
								.placePieceAt(this, destination);
					} else {
						throw new IllegalMove(this, this.getPosition(),
								destination);
					}
				} else {
					// if the forward position doesn't contain a piece
					if (this.getGame().getBoard().getPieceAt(destination) == null) {
						this.getGame().getBoard()
								.removePieceFrom(this.getPosition());
						this.getGame().getBoard()
								.placePieceAt(this, destination);
					} else {
						throw new IllegalMove(this, this.getPosition(),
								destination);
					}
				}

			} else {
				// if it's two directly ahead and it's in the starting
				// position then it's okay to move.
				if ((destination.getY() == this.getPosition().getY() - 2)
						&& (this.getPosition().getY() == 6)
						&& (Math.abs(destination.getX()
								- this.getPosition().getX()) == 0)) {
					this.getGame().getBoard()
							.removePieceFrom(this.getPosition());
					this.getGame().getBoard().placePieceAt(this, destination);
				} else {
					throw new IllegalMove(this, this.getPosition(), destination);
				}
			}

		}
		ChessMove moved = new ChessMove(this, from, to, captured);
		setChanged();
		notifyObservers(moved);
	}

}
