/**
 * Represents a Col game on a Grid Graph. 
 *
 * @author Kyle Burke <paithanq@gmail.com>
 */

//package packageName

import javax.swing.*;
import java.util.*;

public class GridCol extends Col implements SwingDisplayable {

    /* constants */

    /* fields */
    //height of the grid
    private int height;
    
    //width of the grid
    private int width;
    
    /* constructors */
    
    /**
     * Creates a new instance of GridCol.  Warning: Currently does not check that the graph is laid out as a grid!
     */
    public GridCol(Graph<Integer> graph, int height, int width) {
        super(graph);
        this.height = height;
        this.width = width;
    }
    
    /* public methods */
    
    /**
     * Returns the height.
     * @return  The height of this.
     */
    public int getHeight() {
        return this.height;
    }
    
    /**
     * Returns the width.
     * @return  The width of the grid for this graph.
     */
    public int getWidth() {
        return this.width;
    }
    
    //@override
    public Collection<CombinatorialGame> getOptions(int playerId) {
        Collection<CombinatorialGame> colOptions = super.getOptions(playerId);
        Collection<CombinatorialGame> options = new ArrayList<CombinatorialGame>();
        for (CombinatorialGame game : colOptions) {
            Col col = (Col) game;
            options.add(new GridCol(col.getGraph(), this.getHeight(), this.getWidth()));
        }
        return options;
    }
    
    /**
     * Returns a copy of this.
     *
     * @return  A deepish copy of this.
     */
    public CombinatorialGame clone() {
        return new GridCol(this.getGraph(), this.getHeight(), this.getWidth());
    }
    
    /**
     * Gets a Swing representation of this.
     *
     * @return  A JComponent containing a graphical display of the current position.
     */
    public JComponent toSwingComponent() {
        return new GridColPanel(this);
    }
    
    /**
     * Represents a factory that creates instances of Col.  All instances generated are in a grid.
     */
    public static class PositionBuilder implements PositionFactory<GridCol> {
    
        //fields
        //the minimum width of a board
        private int minWidth;
        
        //the maximum width of a board
        private int maxWidth;
        
        //the minimum height of a board
        private int minHeight;
        
        //the maximum height of a board
        private int maxHeight;
        
        //the probability that each vertex will be colored
        private double colorDensity;
        
        /**
         * Class constructor.
         *
         * @param minWidth  Minimum width of the board.
         * @param maxWidth  Maximum width of the board.
         * @param minHeight  Minimum height of the board.
         * @param maxHeight  Maximum height of the board.
         * @param colorDensity  The probability a vertex will be colored.  (Color chosen uniformly at random.)
         */
        public PositionBuilder(int minWidth, int maxWidth, int minHeight, int maxHeight, double colorDensity) {
            this.minWidth = minWidth;
            this.maxWidth = maxWidth;
            this.minHeight = minHeight;
            this.maxHeight = maxHeight;
            this.colorDensity = colorDensity;
        }
        
        /**
         * Returns a position.
         *
         * @return  A new GridCol position.
         */
        public GridCol getPosition() {
            //randomly choose the height and width
            Random generator = new Random();
            int width = this.minWidth + generator.nextInt(this.maxWidth - this.minWidth + 1);
            int height = this.minHeight + generator.nextInt(this.maxHeight - this.minHeight + 1);
            
            //build the vertices
            Collection<Vertex<Integer>> vertices = new ArrayList<Vertex<Integer>>();
            for (int id = 0; id < width * height; id++) {
                int color = UNCOLORED;
                if (generator.nextDouble() <= colorDensity) {
                    //assign the 
                    color = (generator.nextDouble() < .5 ? BLUE : RED);
                }
                //create the vertex and add it to the collection
                vertices.add(new Vertex<Integer>(color , id));
            }
            
            //create the graph object
            Graph<Integer> graph = new Graph<Integer>(vertices);
            
            //add the edges
            for (int id = 0; id < width * height; id++) {
                //i is the ID of the vertex we're currently looking at, so go get that one.
                Vertex<Integer> vertex = graph.getVertexById(id);
                //if the ID is a multiple of the width, then it's along the left-hand side and doesn't have a vertex to the left
                if (id % width != 0) {
                    //in this case, there is a vertex to the left, so add an edge to that
                    vertex.addEdge(graph.getVertexById(id-1));
                }
                //the second row doesn't start until the IDs are greater than the width
                if (id >= width) {
                    //in this case, there is a vertex above, so add an edge to that
                    vertex.addEdge(graph.getVertexById(id-width));
                }
            }
            //return the position
            return new GridCol(graph, height, width);
        }
    }
    
    /* hidden methods (private/protected) (JavaDoc not necessary) */
    
    /* main method for testing */
    
    /** 
     * Unit test for GridCol
     
     * @param args  Arguments used to test this class.
     */
    public static void main(String[] args) {
        int minWidth = 1;
        int maxWidth = 3;
        int minHeight = 1;
        int maxHeight = 3;
        double colorDensity = .55;
        PositionFactory<GridCol> builder = new GridCol.PositionBuilder(minWidth, maxWidth, minHeight, maxHeight, colorDensity);
        GridCol position = builder.getPosition();
        System.out.println(position);
        System.out.println("***********************************\nOptions for Blue:");
        for (CombinatorialGame option : position.getOptions(CombinatorialGame.LEFT)) {
            System.out.println(option);
            System.out.println("********************************");
        }
    
    }

} //end of GridCol