namespace ca.mcgill.ecse223.quoridor.controller;

use QuoridorGame.ump;

class PawnBehavior {
	depend java.util.List;
    0..1 -> 0..1 Game currentGame;
    0..1 -> 0..1 Player player;
	
	boolean isValid;
	
	String side;
	String status;
		
    pawnSM {
    	Placed{
    		initiateDiagonalJump(String side) -> /{
    		}  JumpingDiagonal;
    		initiateStep(String side) -> /{
    		}  Stepping;
    		initiateStraightJump(String side) -> /{
    		}  JumpingStraight;
    	}
		Stepping{
			entry / {isValid = isLegalStep();}
			dropPawn() -> /{
    			updateModel();				//TODO all of these should have isValid as a barrier
    			legalMove(false);
    		}  Placed;
    		cancel() -> /{
    			illegalMove();
    		}Placed;
			
		}
	    JumpingStraight{
	    	entry / {isValid = isLegalJump();}
	    	dropPawn() -> /{
    			updateModel();
    			legalMove(true);
    		}  Placed;
    		cancel() -> /{
    			illegalMove();
    		}Placed;
		}
		JumpingDiagonal{
			entry / {isValid = isLegalJumpDiag();}
			dropPawn() -> /{
    			updateModel();
    			legalMove(true);
    		}  Placed;
    		cancel() -> /{
    			illegalMove();
    		}Placed;
		}
	}
	
	
	void updateModel(){
		status="success";
		//TODO either create new game position and set current or update current one
	}
    // Returns the current row number of the pawn
    int getCurrentPawnRow() { 
    	GamePosition pos = currentGame.getCurrentPosition();
    	if (player.hasGameAsWhite()){
	    	return pos.getWhitePosition().getTile().getRow();
	    }
	    else{
	    	return pos.getBlackPosition().getTile().getRow();
	    }
    }
    
    
    
    // Returns the current column number of the pawn
    int getCurrentPawnColumn() {
    	GamePosition pos=currentGame.getCurrentPosition();
    	if (player.hasGameAsWhite()){
	    	return pos.getWhitePosition().getTile().getColumn();
	    }
	    else{
	    	return pos.getBlackPosition().getTile().getColumn();
	    }
    }
    
    // Returns the current row number of the pawn
    int getOpponentPawnRow() { 
    	GamePosition pos=currentGame.getCurrentPosition();
    	if (player.hasGameAsWhite()){
	    	return pos.getBlackPosition().getTile().getRow();
	    }
	    else{
	    	return pos.getWhitePosition().getTile().getRow();
	    }
    }
    
    
    
    // Returns the current column number of the pawn
    int getOpponentPawnColumn() {
    	GamePosition pos=currentGame.getCurrentPosition();
    	if (player.hasGameAsWhite()){
	    	return pos.getBlackPosition().getTile().getColumn();
	    }
	    else{
	    	return pos.getWhitePosition().getTile().getColumn();
	    }
    }
    
    // Returns if it is legal to step in the given direction
    boolean isLegalStep() { 
    	int opRow = getOpponentPawnRow();
    	int opCol = getOpponentPawnColumn();
    	
    	int curRow = getCurrentPawnRow();
		int curCol = getCurrentPawnColumn();
		
		//String opSide = isOpponentAdjacent(curRow,curCol,opRow,opCol);
    	
    	Boolean walla= isWallBlocking(curRow,curCol,this.side,true);  //if adjacent wall
    	if (walla){
    		return false;
    	}
    	
    	return true; 
    }
    
    // Returns if it is legal to jump in the given direction
    boolean isLegalJump() { 
    	int opRow = getOpponentPawnRow();
    	int opCol = getOpponentPawnColumn();
    	
    	int curRow = getCurrentPawnRow();
		int curCol = getCurrentPawnColumn();
		
		String opSide = isOpponentAdjacent(curRow,curCol,opRow,opCol);
    	Boolean wallb= isWallBlocking(curRow,curCol,opSide,false); 	//wall adjacent to opponent
    	Boolean walla= isWallBlocking(curRow,curCol,this.side,true);  //if adjacent wall
		System.out.print(" opside="+opSide);
		System.out.print(" wallb="+wallb);
    	System.out.print(" walla="+walla);
		if ((wallb)||(walla)){
    		return false;
    	}
		else if(this.side.compareTo(opSide)==0){
			return true;
		} 
		
		else {
			return false;
		}
    }
    
    boolean isLegalJumpDiag() { 
    	int opRow = getOpponentPawnRow();
    	int opCol = getOpponentPawnColumn();
    	
    	int curRow = getCurrentPawnRow();
    	int curCol = getCurrentPawnColumn();
    	
    	String opSide = isOpponentAdjacent(curRow,curCol,opRow,opCol);
    	Boolean wallb= isWallBlocking(curRow,curCol,opSide,false); 
    	Boolean walla= isWallBlocking(curRow,curCol,opSide,true);  //if adjacent wall
    	Boolean border= isBorderBlocking(opRow,opCol,opSide);
    	System.out.print(" opside="+opSide);
    	System.out.print(" border="+border);
    	System.out.print(" wallb="+wallb);
    	System.out.print(" walla="+walla);
    	if ((!border)&&(!wallb)){
    		return false;
    	}
    	else if (walla){
    		return false;
    	}
		else if(this.side.compareTo("upleft")==0){
			if((opSide.compareTo("up")==0) || opSide.compareTo("left")==0){
				return true;
			}
		} 
		
		else if(this.side.compareTo("upright")==0){
			if((opSide.compareTo("up")==0) || opSide.compareTo("right")==0){
				return true;
			}
		} 
		else if(this.side.compareTo("downleft")==0){
			if((opSide.compareTo("down")==0) || opSide.compareTo("left")==0){
				return true;
			}
		} 
		else if(this.side.compareTo("downright")==0){
			if((opSide.compareTo("down")==0) || opSide.compareTo("right")==0){
				return true;
			}
		}
		
    	return false;
    }
	
	boolean isWallBlocking(int curRow, int curCol,String cside,boolean isStep){
    	int distance;
    	if(isStep){
    		distance=1;
    	}
    	else {
    		distance = 2;
    	}
    	GamePosition curr= currentGame.getCurrentPosition();
		
		List<Wall> wWall = curr.getWhiteWallsOnBoard();
		List<Wall> bWall = curr.getBlackWallsOnBoard();
		
    	if(cside.equals("up")){
			for(Wall w: wWall){
				if (w.getMove().getWallDirection().toString().compareTo("Horizontal")==0){
					if (w.getMove().getTargetTile().getRow()==curRow-distance){
						if ((w.getMove().getTargetTile().getColumn()==curCol)||(w.getMove().getTargetTile().getColumn()==curCol-1)){
							return true;
						}
					}
				}
			}
			for(Wall w: bWall){
				if (w.getMove().getWallDirection().toString().compareTo("Horizontal")==0){
					if (w.getMove().getTargetTile().getRow()==curRow-distance){
						if ((w.getMove().getTargetTile().getColumn()==curCol)||(w.getMove().getTargetTile().getColumn()==curCol-1)){
							return true;
						}
					}
				}
			}
		}
		else if(cside.equals("right")){
			for(Wall w: wWall){
				if (w.getMove().getWallDirection().toString().compareTo("Vertical")==0){
					if (w.getMove().getTargetTile().getColumn()==curCol-1+distance){
						if ((w.getMove().getTargetTile().getRow()==curRow)||(w.getMove().getTargetTile().getRow()==curRow-1)){
							return true;
						}
					}
				}
			}
			for(Wall w: bWall){
				if (w.getMove().getWallDirection().toString().compareTo("Vertical")==0){
					if (w.getMove().getTargetTile().getColumn()==curCol-1+distance){
						if ((w.getMove().getTargetTile().getRow()==curRow)||(w.getMove().getTargetTile().getRow()==curRow-1)){
							return true;
						}
					}
				}
			}
		} 
		else if(cside.equals("left")){
			for(Wall w: wWall){
				if (w.getMove().getWallDirection().toString().compareTo("Vertical")==0){
					if (w.getMove().getTargetTile().getColumn()==curCol-distance){
						if ((w.getMove().getTargetTile().getRow()==curRow)||(w.getMove().getTargetTile().getRow()==curRow-1)){
							return true;
						}
					}
				}
			}
			for(Wall w: bWall){
				if (w.getMove().getWallDirection().toString().compareTo("Vertical")==0){
					if (w.getMove().getTargetTile().getColumn()==curCol-distance){
						if ((w.getMove().getTargetTile().getRow()==curRow)||(w.getMove().getTargetTile().getRow()==curRow-1)){
							return true;
						}
					}
				}
			}
		} 
		else if(cside.equals("down")){
			for(Wall w: wWall){
				if (w.getMove().getWallDirection().toString().compareTo("Horizontal")==0){
					if (w.getMove().getTargetTile().getRow()==curRow-1+distance){
						if ((w.getMove().getTargetTile().getColumn()==curCol)||(w.getMove().getTargetTile().getColumn()==curCol-1)){
							return true;
						}
					}
				}
			}
			for(Wall w: bWall){
				if (w.getMove().getWallDirection().toString().compareTo("Horizontal")==0){
					if (w.getMove().getTargetTile().getRow()==curRow-1+distance){
						if ((w.getMove().getTargetTile().getColumn()==curCol)||(w.getMove().getTargetTile().getColumn()==curCol-1)){
							return true;
						}
					}
				}
			}
		}
		
		return false;
    }
    
    String isOpponentAdjacent(int curR, int curC, int oR, int oC){
    	if ((curR==oR)&&(curC==oC+1)){
    		return "left";
    	}
    	else if ((curR==oR)&&(curC==oC-1)){
    		return "right";
    	}
    	
    	else if ((curC==oC)&&(curR==oR+1)){
    		return "up";
    	}
    	else if ( (curC==oC)&&(curR==oR-1)){
    		return "down";
    	}
    	else {
    		return "no";
    	}
    }
    
    Boolean isBorderBlocking(int opRow, int opCol, String opSide){
    	if ((opSide.compareTo("up")==0)&&(opRow==1)){
    		return true;
    	}
    	
    	else if ((opSide.compareTo("down")==0)&&(opRow==9)){
    		return true;
    	}
    	
    	else if ((opSide.compareTo("left")==0)&&(opCol==0)){
    		return true;
    	}
    	
    	else if ((opSide.compareTo("right")==0)&&(opCol==9)){
    		return true;
    	}
    	else {
    		return false;
    	}
    }
	
    // Action to be called when an illegal move is attempted
    void illegalMove() { 
		status="illegal";
    }
    
    void legalMove(boolean isJump) { 
		status="success";
    	GamePosition curr= currentGame.getCurrentPosition();
    	int curRow = getCurrentPawnRow()-1;
    	int curCol = getCurrentPawnColumn()-1;
		int r=curRow,j=curCol;
		int distance=2;
		if (!isJump){
			distance=1;
		}
		
		if(this.side.compareTo("up")==0){
			r=curRow-distance;
		} 
		
		else if(this.side.compareTo("right")==0){
			j=curCol+distance;
		} 
		else if(this.side.compareTo("left")==0){
			j=curCol-distance;
		} 
		else if(this.side.compareTo("down")==0){
			r=curRow+distance;
		}
		
		else if(this.side.compareTo("upleft")==0){
			r=curRow-1;
			j=curCol-1;
		} 
		
		else if(this.side.compareTo("upright")==0){
			r=curRow-1;
			j=curCol+1;
		} 
		else if(this.side.compareTo("downleft")==0){
			r=curRow+1;
			j=curCol-1;
		} 
		else if(this.side.compareTo("downright")==0){
			r=curRow+1;
			j=curCol+1;
		}
		
		if (player.hasGameAsWhite()) {
			curr.setWhitePosition(new PlayerPosition(player, currentGame.getQuoridor().getBoard().getTile(r*9+j)));
		}
		else {
			curr.setBlackPosition(new PlayerPosition(player, currentGame.getQuoridor().getBoard().getTile(r*9+j)));
		}
    }
    
    
    // Enumeration for the possible moving directions
    // (directions are from the viewpoint of white player)
    enum MoveDirection { East, South, West, North; }
}
