import com.sun.java.swing.tree.*;
import java.util.Vector;
import java.util.Enumeration;

public class SimGrid  implements TreeNode 
{
    public static java.awt.Graphics g = null;
    public static java.util.Hashtable allSimGrids = null;
	public static com.sun.java.swing.JProgressBar JProgressBar1 = null;
	public static com.sun.java.swing.JLabel JLabel1 = null;
    
    private Edge data[][];
    
    private void fill(int[] inData) {
        int index = 0;
        data = new Edge[6][];
        for (int lcv=0;lcv<6;lcv++) {
            data[lcv] = new Edge[lcv];
            for (int e=0;e<lcv;e++) {
                data[lcv][e] = Edge.getEdge(inData[index]);
                index++;
            }
        }
    }
    
    public SimGrid(int[] inData) {
        super();
        this.fill(inData);
    }
    
    private static final String ZERO = "0";
    private static final String ONE = "1";
    private static final String TWO = "2";
    
    public SimGrid(String stuff) {
        super();
        int[] temp = new int[15];
        int tempPos = 0;
        int stuffPos = 0;
        while (tempPos < 15) {
            char curChar = stuff.charAt(stuffPos);
            if (curChar == ZERO.charAt(0)) {
                temp[tempPos] = 0;
                tempPos++;
                stuffPos++;
            } else if (curChar == ONE.charAt(0)) {
                temp[tempPos] = 1;
                tempPos++;
                stuffPos++;
            } else if (curChar == TWO.charAt(0)) {
                temp[tempPos] = 2;
                tempPos++;
                stuffPos++;
            } else
                stuffPos++;
        }
        this.fill(temp);        
    }
    
    private void swapData(int x1, int y1, int x2, int y2) {
        Edge temp = data[x1][y1];
        data[x1][y1] = data[x2][y2];
        data[x2][y2] = temp;
    }
    
    private void swapDataCheck2(int x1, int y1, int x2, int y2) {
        if (x2 < y2) this.swapData(x1,y1,y2,x2);
        else this.swapData(x1,y1,x2,y2);
    }
    private void swapDataCheck(int x1, int y1, int x2, int y2) {
        if (x1 < y1) this.swapDataCheck2(y1,x1,x2,y2);
        else this.swapDataCheck2(x1,y1,x2,y2);
    }
    
    private void swapIndices(int ind1, int ind2) {
        for (int lcv=0;lcv<6;lcv++) {
            if (lcv == ind1) continue;
            if (lcv == ind2) continue;
            this.swapDataCheck(lcv,ind1,lcv,ind2);
        }
    }
    
    private Edge getData(int x, int y) {
        if (x == y) return(Edge.NONE);
        if (x < y) return(this.data[y][x]);
        else return(this.data[x][y]);
    }
    
    private int indexWeight(int index) {
        int answer = 1;
        for (int lcv=0;lcv<6;lcv++)
/*            if (this.getData(index,lcv).getValue() == 2) 
                answer *= 5;
            else    */
                answer *= 1+this.getData(index,lcv).getValue();
        return(answer);
    }
    
    private int indexSuperWeight(int index, int ignore) {
        int answer = 0;
        int lcv = 0;
        int wt = 1000;
        while (lcv < 6) {
            if (lcv == ignore) lcv++;
            if (lcv == index) lcv++;
            if (lcv == ignore) lcv++;
            if (lcv >= 6) break;
            answer += wt*this.getData(index,lcv).getValue();
            wt /= 10;
            lcv++;
        }
        return(answer);
    }
        
    public void simplify() {
        for (int a=5;a>=0;a--) for (int b=0;b<a;b++)
            if (this.indexWeight(b) < this.indexWeight(b+1))
                this.swapIndices(b,b+1);
        for (int a=5;a>=0;a--) for (int b=0;b<a;b++)
            if ((this.indexWeight(b) == this.indexWeight(b+1))
                && (this.indexSuperWeight(b,b+1) < this.indexSuperWeight(b+1,b)))
                this.swapIndices(b,b+1);
    }
    
    public String toString() {
        String answer = "[" + this.computeWinner() + "]{";
        for (int lcv=1;lcv<6;lcv++) {
            answer += "{";
            for (int e=0;e<lcv;e++) {
                answer += data[lcv][e].toString();
            }
            answer += "}";
        }
        answer += "}";
        return(answer);
    }
    
    public int[] toArray() {
        int[] answer = new int[15];
        int pos = 0;
        for (int lcv=1;lcv<6;lcv++) {
            for (int e=0;e<lcv;e++) {
                answer[pos] = data[lcv][e].getValue();
                pos++;
            }
        }
        return(answer);
    }
    
    public boolean equals(Object obj) {
        if (!obj.getClass().equals(this.getClass())) return(false);
        SimGrid o = (SimGrid) obj;
        boolean answer = true;
        for (int lcv=1;lcv<6;lcv++) {
            for (int e=0;e<lcv;e++) {
                if (this.data[lcv][e] != o.data[lcv][e]) answer = false;
                if (!answer) break;
            }
            if (!answer) break;
        }
        return(answer);
    }
    
    private int myHashCode = -1;
    
    public int hashCode() {
        if (myHashCode == -1) {
            int answer = 0;
            int base = 1;
            for (int lcv=1;lcv<6;lcv++) for (int e=0;e<lcv;e++) {
                answer += base*this.data[lcv][e].getValue();
                base *= 3;
            }
            myHashCode = 14349000 - answer;
            return(answer);     
        } else {
            return(myHashCode);
        }
    }
    
    private int myTriCount = -1;
    public int triangleCount() {
        if (myTriCount == -1) {
            int answer = 0;
            for (int i=0;i<6;i++)
            for (int j=i+1;j<6;j++)
            for (int k=j+1;k<6;k++)
            if ((this.data[j][i].getValue() != 0) &&
                (this.data[j][i] == this.data[k][i]) &&
                (this.data[j][i] == this.data[k][j])) answer++;
            myTriCount = answer;
            return(answer);
        } else {
            return(myTriCount);
        }
    }
    
    private int myLoser = -1;
    public int getLoser() {
        if (myLoser == -1) {
            int answer = 0;
            if (triangleCount() != 1) answer = -1;
            else {
                for (int i=0;i<6;i++)
                for (int j=i+1;j<6;j++)
                for (int k=j+1;k<6;k++)
                if ((this.data[j][i].getValue() != 0) &&
                    (this.data[j][i] == this.data[k][i]) &&
                    (this.data[j][i] == this.data[k][j])) 
                answer = this.data[j][i].getValue();
            }
            myLoser = answer;
            return(answer);
        } else
            return(myLoser);
    }
    
    private int myPlayer = -1;
    public int getPlayer() {
        if (myPlayer == -1) {
            int answer = 0;
            for (int lcv=1;lcv<6;lcv++) for (int e=0;e<lcv;e++)
                if (this.data[lcv][e].getValue() != 0) answer ++;
            answer %= 2;
            if (answer == 0) answer = 2;
            myPlayer = answer;
            return(answer);     
        } else
            return(myPlayer);
    }
    
    private boolean computed = false;
    private int myWinner = -1;
    private Vector myChildren;
    
    public Enumeration children() {
        this.computeWinner();
        return(myChildren.elements());
    }
    
    public boolean getAllowsChildren() {
        return(true);
    }
    
    public TreeNode getChildAt(int childIndex) {
        this.computeWinner();
        return((TreeNode)myChildren.elementAt(childIndex));
    }
    
    public int getChildCount() {
        this.computeWinner();
        return(myChildren.size());
    }
    
    public int getIndex(TreeNode node) {
        this.computeWinner();
        return(myChildren.indexOf(node));
    }
    
    public TreeNode getParent() {
        return(null);
    }
    
    public boolean isLeaf() {
        this.computeWinner();
        return(myChildren.size() == 0);
    }
    
    public int computeWinner() {
        if (!computed) {
            if (this.triangleCount() == 1) {
                myWinner = 3 - this.getLoser();
                myChildren = new Vector(0);
            } else {
                myChildren = new Vector(15);
                // Who are my children?
                int[] myArray = this.toArray();
                SimGrid temp;
                Integer code;
                for (int lcv=0;lcv<15;lcv++) if (myArray[lcv] == 0) {
                    myArray[lcv] = this.getPlayer();
                    temp = new SimGrid(myArray);
                    temp.simplify();
                    code = new Integer(temp.hashCode());
                    if (SimGrid.allSimGrids.containsKey(code)) {
                        temp = (SimGrid)SimGrid.allSimGrids.get(code);
                        if (!myChildren.contains(temp))
                            myChildren.addElement(temp);
                    }
                    myArray[lcv] = 0;
                }
                
                // if any of my children have "myPlayer" as their Winner, then
                // myWinner is myPlayer.
                myWinner = 3 - this.getPlayer();
                for (int lcv=0;lcv<myChildren.size();lcv++) {
                    SimGrid kid = (SimGrid)myChildren.elementAt(lcv);
                    if (kid.computeWinner() == this.getPlayer())
                        myWinner = this.getPlayer();
                }
            }
            computed = true;
    	    JProgressBar1.setValue(JProgressBar1.getValue()+1);
    	    JLabel1.setText("" + JProgressBar1.getValue());
        }
        return(myWinner);
    }
    
    public static final int[] xpp = new int[] { 60, 140, 160, 140, 60, 40 };
    public static final int[] ypp = new int[] { 20, 20, 100, 180, 180, 100 };
    
    public void draw() {
        g.clearRect(0, 0, 400, 400);
        for (int lcv=1;lcv<6;lcv++) for (int e=0;e<lcv;e++)
           if (this.data[lcv][e].getValue() != 0) {
            
            java.awt.Color c;
            if (this.data[lcv][e].getValue() == 1)
                c = java.awt.Color.red;
            else
                c = java.awt.Color.blue;
            
            g.setColor(c);
            g.drawLine(xpp[lcv], ypp[lcv], xpp[e], ypp[e]);
        }
        for (int lcv=0;lcv<6;lcv++) {
            g.setColor(java.awt.Color.black);
            g.fillOval(xpp[lcv]-5, ypp[lcv]-5, 10, 10);
        }
    }
}