//***********************************************************
//*
//* File:           Group4Player2.java
//* Author:         
//* Contact:        
//* Update:        
//*
//* Description:    
//*
//***********************************************************

package Rectangles;

import ui.*;
import java.util.*;
import java.io.*;
import java.awt.Color;

public final class OldGroup7Player2 implements IFCPlayer {

    Rectangles game;
    int numRobots;
    int boardSize;
    int numPlayers;
    int ourIndex;
    Rect[] botRects;
 
    static final String _CNAME = "What's My Name?!?";
    static final Color  _CCOLOR = new Color(1.0f, 0.8f, 0.3f);

    
    public Robot[] register(Rectangles __rectangles) throws Exception {

        Robot[] RET;
	int loaners = 0;
	int teamBots = 0;
        game       = __rectangles;
	numRobots  = game.numRobots();
	numPlayers = game.numPlayers();
	boardSize  = game.size();
	ourIndex   = game.indexOf(this);
	botRects   = new Rect[numRobots];

        RET = new Robot[numRobots];
	if(numRobots < 4) {
	    int stagger = boardSize / numRobots;
	    for (int i = 0; i < numRobots; i++) {
		RET[i] = new Robot((stagger * i), (stagger * i));
		Vertex startPos = new Vertex((stagger * i), (stagger * i));
		Vertex currPos = new Vertex((stagger * i), (stagger * i));
		botRects[i] = new Rect(startPos, currPos, 
				       (stagger - 1), (stagger - 1) , 'E', 1,
				       boardSize);
	    }
	}
	else {
	    //find what a safe distance is by determining the average area
	    //per bot, square rooting (assume everyone will build a square) to
	    //find the length of one side. 

	    double averageArea = 
		 boardSize * boardSize / (numPlayers * numRobots);
	    int safeLength = (int) Math.sqrt(averageArea);
	    int totalPerimeter = safeLength * numRobots;
	    int botsPerShortSide = 0;
	    int botsPerLongSide = 0;
	    int startX;
	    int startY;
	    //cap the total perimeter at the perimeter needed to 
	    //acheive have the area of the board
	    if(totalPerimeter > Math.sqrt(boardSize * boardSize /2) * 4) {
		botsPerLongSide = (int) boardSize / safeLength;
		botsPerShortSide = (numRobots - (2 * botsPerLongSide));
		if(botsPerShortSide % 2 != 0) {
		    botsPerShortSide -= 1;
		    loaners++;
		}
		botsPerShortSide = botsPerShortSide / 2;
		while(botsPerShortSide >= botsPerLongSide) {
		    botsPerShortSide--;
		    botsPerLongSide++;
		    safeLength = (int)boardSize / botsPerLongSide;
		    //take care of rounding errors
		    if(safeLength < (boardSize / botsPerLongSide)) {
		    	safeLength++;
		    }
		}
		while( (numRobots - botsPerLongSide - botsPerLongSide - botsPerShortSide - botsPerShortSide) / 4 > 1 && botsPerLongSide < boardSize) {
		    botsPerShortSide++;
		    botsPerLongSide++;
		    safeLength = (int)boardSize / botsPerLongSide;
		    if(safeLength < (boardSize / botsPerLongSide)) {
			safeLength++;
		    }
		}
		if(botsPerShortSide > boardSize) {
		    botsPerShortSide = boardSize;
		}

	    Random rand = new Random();
	    startX = 
		rand.nextInt(boardSize - (botsPerShortSide * safeLength));
	    startY = boardSize - 1;
	    teamBots = numRobots - loaners;
	    }
	    else {
		while((numRobots - loaners) % 4 != 0) {
		    loaners++;
		}
		teamBots = numRobots - loaners;
		botsPerLongSide = teamBots / 4;
		botsPerShortSide = teamBots / 4;
		
		Random rand = new Random();
		startX = 
		    rand.nextInt(boardSize - (botsPerShortSide * safeLength));
		startY = 
		    rand.nextInt(boardSize - (botsPerLongSide * safeLength));
		startY += (botsPerLongSide * safeLength);
	    }

	    //place bots to build rect starting from lower left 
	    //in clockwise manner
	    int tempX = startX;
	    int tempY = startY;
	    //left side
	    int botNum = 0;
	    for(int i = 0; i < botsPerLongSide; i++) {
		
		Vertex startPos = new Vertex(tempX, tempY);
		Vertex currentPos = new Vertex(tempX, tempY);
		RET[botNum] = new Robot(tempX, tempY);
		int width;
		if(startX < safeLength) {
		    width = startX;
		}
		else {
		    width = safeLength;
		}
		botRects[botNum] = new Rect(startPos, currentPos, 
					    width, safeLength,
					    'N', 0,
					    boardSize);
		tempY -= safeLength;
		botNum++;
	    }
	    //top side
	    for(int i = 0; i < botsPerShortSide; i++) {
		Vertex startPos = new Vertex(tempX, tempY);
		Vertex currentPos = new Vertex(tempX, tempY);
		RET[botNum] = new Robot(tempX, tempY);
		int height;
		if(tempY > safeLength) {
		    height = safeLength;
		}
		else {
		    height = tempY;
		}
		botRects[botNum] = new Rect(startPos, currentPos, 
					    safeLength, height,
					    'E', 0,
					    boardSize);
		tempX += safeLength;
		botNum++;
	    }
	    //righ side
	    for(int i = 0; i < botsPerLongSide; i++) {
		Vertex startPos = new Vertex(tempX, tempY);
		Vertex currentPos = new Vertex(tempX, tempY);
		RET[botNum] = new Robot(tempX, tempY);
		int width;
		if((boardSize - tempX) < safeLength) {
		    width = boardSize - tempX;
		}
		else {
		    width = safeLength;
		}
		botRects[botNum] = new Rect(startPos, currentPos, 
					    width, safeLength,
					    'S', 0,
					    boardSize);
		tempY += safeLength;
		botNum++;
	    }
	    //bottom side
	    for(int i = 0; i < botsPerShortSide; i++) {
		Vertex startPos = new Vertex(tempX, tempY);
		Vertex currentPos = new Vertex(tempX, tempY);
		RET[botNum] = new Robot(tempX, tempY);
		int height;
		if((boardSize - tempY) > safeLength) {
		    height = safeLength;
		}
		else {
		    height = boardSize - tempY;
		}
		botRects[botNum] = new Rect(startPos, currentPos, 
					    safeLength, height,
					    'W', 0,
					    boardSize);
		tempX -= safeLength;
		botNum++;
	    }
	    //left over kids.  place them along the perimeter of our
	    //big rect
	    if(loaners > 0) {
		tempX = startX;
		tempY = startY;
		char direction;
		if(startX > safeLength) {
		    direction = 'W';
		}
		else if((startY - ((botsPerLongSide + 1) * safeLength))  > 0) {
		    direction = 'N';
		    tempY = startY - (botsPerLongSide * safeLength);
		} 
		else if((startX + ((botsPerShortSide + 1) * safeLength))  < boardSize) {
		    direction = 'E';
		    tempY = startY - (botsPerLongSide * safeLength);
		    tempX = startX + (botsPerShortSide * safeLength);
		}
		else {
		    direction = 'S';
		    tempY = startY;
		    tempX = startX + (botsPerShortSide * safeLength);
		}
		for(int i = 0; i < loaners; i++) {
		    Vertex startPos = new Vertex(tempX, tempY);
		    Vertex currentPos = new Vertex(tempX, tempY);
		    RET[teamBots + i] = new Robot (tempX, tempY);
		    botRects[teamBots + i] = 
			new Rect(startPos, currentPos, 
				 safeLength, safeLength,
				 direction, 1,
				 boardSize);
		    if(direction == 'W') {
			tempY -= safeLength;
		    }
		    if(direction == 'N') {
			tempX += safeLength;
		    }
		    if(direction == 'E') {
			tempY += safeLength;
		    }
		    if(direction == 'S') {
			tempX -= safeLength;
		    }
		}
	    }
	}

        return RET;
    }
    
    public char[] move() throws Exception {
	char[] RET = new char[numRobots];
	int length;
	Robot[] ourBots = (game.allRobots())[ourIndex]; 

	for(int i = 0; i < numRobots; i++) {
	    int xpos = ourBots[i].xpos();
	    int ypos = ourBots[i].ypos();
	    botRects[i].setCurrentPosition(new Vertex(xpos, ypos));
	    length = botRects[i].width;
	    if(xpos < ypos) {
		length = botRects[i].height;
	    }

	    char direction = botRects[i].getCurrentDirection();
	    //check to see if there are any broken segments
	    if(botRects[i].atDestCorner() &&
	       continuous(xpos, ypos, direction, length) == 0) {
		botRects[i] = new Rect(new Vertex(xpos, ypos), 
				       new Vertex(xpos, ypos), 
				       length, 
				       length, 
				       direction,
				       botRects[i].rotation,
				       boardSize);
	    }
	    //if we're at an intersection look left and right
	    //before crossing
	    if(botRects[i].atDestCorner()) {
		if(direction == 'N' || direction == 'S') {
		    if(continuous(xpos, ypos, 'E', length) == 0) {
			botRects[i] = new Rect(new Vertex(xpos, ypos), 
					       new Vertex(xpos, ypos), 
					       length, 
					       length, 
					       'E',
					       botRects[i].rotation,
					       boardSize);
		    }
		    if(continuous(xpos, ypos, 'W', length) == 0) {
			botRects[i] = new Rect(new Vertex(xpos, ypos), 
					       new Vertex(xpos, ypos), 
					       length, 
					       length, 
					       'W',
					       botRects[i].rotation,
					       boardSize);
		    }
		}

		if(direction == 'E' || direction == 'W') {
		    if(continuous(xpos, ypos, 'N', length) == 0) {
			botRects[i] = new Rect(new Vertex(xpos, ypos), 
					       new Vertex(xpos, ypos), 
					       length, 
					       length, 
					       'N',
					       botRects[i].rotation,
					       boardSize);
		    }
		    if(continuous(xpos, ypos, 'S', length) == 0) {
			botRects[i] = new Rect(new Vertex(xpos, ypos), 
					       new Vertex(xpos, ypos), 
					       length, 
					       length, 
					       'S',
					       botRects[i].rotation,
					       boardSize);
		    }
		}
	    }
	    RET[i] = botRects[i].generateMove();
	    if(RET[i] == 'z') {
		char newDirection = 'z';
		if(botRects[i].getCurrentDirection() == 'E') {
		    newDirection = 'N';
		}
		if(botRects[i].getCurrentDirection() == 'W') {
		    newDirection = 'S';
		}
		if(botRects[i].getCurrentDirection() == 'N') {
		    newDirection = 'W';
		}
		if(botRects[i].getCurrentDirection() == 'S') {
		    newDirection = 'E';
		}

		botRects[i] = new Rect(botRects[i].corners[0], 
				       botRects[i].currentPosition, 
				       botRects[i].width, 
				       botRects[i].height, newDirection, 1,
				       boardSize);
		RET[i] = botRects[i].generateMove();
	    }
	}
        return RET;
    }

    public String name() throws Exception {
        return _CNAME;
    }

    public Color color() throws Exception {
        return _CCOLOR;
    }

    public boolean interactive() throws Exception {
        return false;
    }        
  private static final String arrayToString(Robot[] arr) throws Exception {
        StringBuffer buf = new StringBuffer();
        buf.append("[");
        for (int i = 0; i < arr.length; i++) {
            buf.append(String.valueOf(arr[i].xpos())).append(",");
        }
        buf.append("]");

        return buf.toString();
    }
    private int continuous (int xpos, int ypos, char direction, int length) throws Exception {
	int[][] boardColors = game.colors();
	int testLength = length;
	int colorCount = 0;
	int emptyCount = 0;
	int filledCount = 0;
	if(direction == 'N') {
	    if(ypos < length) {
		testLength = ypos;
	    }
	    for(int i = 0; i< testLength; i++) {
		if (boardColors[xpos][ypos - i] == _CEMPTY) {
		    emptyCount++;
		}
		else if(boardColors[xpos][ypos - i] == _CFILLED) {
		    filledCount++;
		}
		else if(boardColors[xpos][ypos - i] == ourIndex) {
		    colorCount++;
		}

		
	    }
	}

	if(direction == 'S') {
	    if(boardSize < ypos + length) {
		testLength = boardSize - ypos;
	    }
	    for(int i = 0; i< testLength; i++) {
		if (boardColors[xpos][ypos + i] == _CEMPTY) {
		    emptyCount++;
		}
		else if(boardColors[xpos][ypos + i] == _CFILLED) {
		    filledCount++;
		}
		else if(boardColors[xpos][ypos + i] == ourIndex) {
		    colorCount++;
		}

		
	    }
	}


	if(direction == 'W') {
	    if(xpos < length) {
		testLength = xpos;
	    }
	    for(int i = 0; i< testLength; i++) {
		if (boardColors[xpos - i][ypos] == _CEMPTY) {
		    emptyCount++;
		}
		else if(boardColors[xpos - i][ypos] == _CFILLED) {
		    filledCount++;
		}
		else if(boardColors[xpos - i][ypos] == ourIndex) {
		    colorCount++;
		}

		
	    }
	}

	if(direction == 'E') {
	    if(boardSize < xpos + length) {
		testLength = boardSize - xpos;
	    }
	    for(int i = 0; i< testLength; i++) {
		if (boardColors[xpos + i][ypos] == _CEMPTY) {
		    emptyCount++;
		}
		else if(boardColors[xpos + i][ypos] == _CFILLED) {
		    filledCount++;
		}
		else if(boardColors[xpos + i][ypos] == ourIndex) {
		    colorCount++;
		}

		
	    }
	}
	if(filledCount + 1 == testLength) {
	    return _CFILLED;
	}
	if(emptyCount + 1 == testLength) {
	    return _CEMPTY;
	}
	if(colorCount > 0 && colorCount < testLength) {
	    return 0;
	}
      
	return 1;
    }
    
}

/*
class Rect {
    Vertex startPosition;
    Vertex currentPosition;
    int width;
    int height;
    int directionIndex;
    char[] MOVES;
    int counter;
    int side;
    int rotation;
    static final char[] clockwiseMoves = {'E', 'S', 'W', 'N', 'Y'};
    static final char[] counterClockwiseMoves = {'S', 'E', 'N', 'W', 'Y'};

    public Rect (Vertex start, Vertex current, int w, int h, 
		 char currentDirection, int clockwise) throws Exception {
	startPosition    = start;
	currentPosition  = current;
	width            = w;
	height           = h;
	side             = 0;
	counter          = 1; 
	rotation         = clockwise;
	if(clockwise == 1) {
	    MOVES = clockwiseMoves;
	}
	else {
	    MOVES = counterClockwiseMoves;
	}
	for(int i = 0; i < MOVES.length; i++) {
	    if(MOVES[i] == currentDirection) {
		directionIndex = i;
	    }
	}
    }
    public char getCurrentDirection() {
	if(directionIndex == -1) {
	    return 'Z';
	}
	return MOVES[directionIndex];
    }
    public void updateRect() {
	if((MOVES[directionIndex] == 'E' || MOVES[directionIndex] == 'W') &&
	   counter <= width) {
	    directionIndex = directionIndex;
	}
	else if((MOVES[directionIndex] == 'N' || MOVES[directionIndex] == 'S') &&
	   counter <= height) {
	    directionIndex = directionIndex;
	}
	else {
	    if(side < MOVES.length - 2) {
		side++;
		directionIndex = (directionIndex + 1) % 4;
		counter = 0;
	    }
	    else {
		side++;
		directionIndex = -1;
	    }
	}
	counter++;
    }
    public char generateMove() {
	char RET;
	if(side < 4) {
	    RET = MOVES[directionIndex];
	    updateRect();
	}
	else {
	    RET = 'z';
	}
	return RET;
    }

    public Vertex checkRect (boolean[][] board) {
	return null;
    }
}

*/
class Rect {
    Vertex currentPosition;
    Vertex[] corners;
    int direction;
    int width;
    int height;
    char[] MOVES;
    int counter;
    int side;
    int rotation;
    int destCorner;

    static final char[] clockwiseMoves = {'E', 'S', 'W', 'N', 'Y'};
    static final char[] counterClockwiseMoves = {'S', 'E', 'N', 'W', 'Y'};

    public Rect (Vertex start, Vertex current, int w, int h, 
		 char currentDirection, int clockwise, int boardSize) throws Exception {
	currentPosition  = current;
	width            = w;
	height           = h;
	side             = 0;
	counter          = 1; 
	rotation         = clockwise;
	destCorner       = 1;
	corners = new Vertex[4];
	if(clockwise == 1) {
	    MOVES = clockwiseMoves;
	}
	else {
	    MOVES = counterClockwiseMoves;
	}
	corners[0] = start;
	//calculate the other three corners
	for(int i = 0; i < MOVES.length; i++) {
	    if(MOVES[i] == currentDirection) {
		direction = i;
		break;
	    }
	}
	for(int i = 0; i < 3; i++) {
	    int nextDirection = (i + direction) % 4;
	    if(MOVES[nextDirection] == 'N') {
		corners[i + 1] = new Vertex(corners[i].xpos(), 
				     Math.max(0, corners[i].ypos() - (height))) ;
	    }

	    if(MOVES[nextDirection] == 'S') {
		corners[i + 1] = new Vertex(corners[i].xpos(), 
				     Math.min(boardSize - 1, corners[i].ypos() + (height))) ;
	    }
	    if(MOVES[nextDirection] == 'E') {
		corners[i + 1] = new Vertex(Math.min(boardSize - 1, corners[i].xpos() + (width)), 
				     corners[i].ypos()) ;
	    }

	    if(MOVES[nextDirection] == 'W') {
		corners[i + 1] = new Vertex(Math.max(0, corners[i].xpos() - (width)), 
				     corners[i].ypos());
	    }
	}

    }
    public char getCurrentDirection() {
	if(direction > -1) {
	    return MOVES[direction];
	}
	return 'z';
    }
    public void setCurrentPosition(Vertex currentPos) {
	currentPosition = currentPos;
    }
    public char generateMove() throws Exception {
	char RET = 'z';
	if(currentPosition.xpos() == corners[destCorner].xpos()) {
	    if(currentPosition.ypos() == corners[destCorner].ypos()) {
		direction = (direction + 1) % 4;
		destCorner = (destCorner + 1) % 4;
		side++;
	    }
	}
	if(side != 4) {
	    RET = MOVES[direction];
	}
	return RET;
    }	    
	    
    public boolean atDestCorner() throws Exception {
	if(currentPosition.xpos() == corners[destCorner].xpos() &&
	   currentPosition.ypos() == corners[destCorner].ypos()) {
	    return true;
	}
	return false;
    }

    public Vertex checkRect (boolean[][] board) {
	return null;
    }
}
