import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import java.lang.Math;
import java.util.Random;

public class DiscButtonPanel extends Panel implements ActionListener
{
  private Button tessRepButton;
  private Button faceButton;
  private Button removeButton;
  private Button clearButton;

  private DirectedGraph graph;
  private DirectedGraphCanvas canvas;
  private FirstWindow firwindow;

  private int at;
  private int vat;
  private DirectedVertex v;
  private DirectedVertex vsource;
  private DirectedVertex vsink;
  private DirectedEdge edg;
  private List pos;
  private List orderedEdges;

  DiscButtonPanel(DirectedGraphCanvas canvas)
  {
     super();
     this.canvas = canvas;
     graph = canvas.graph;
     setBackground(Color.gray);
     setLayout(new FlowLayout());

     tessRepButton = new Button("Tessellation Representation");
     faceButton = new Button("Add Face");
     removeButton = new Button("Remove Vertices and Edges");
     //clearButton = new Button("Clear");

     add(faceButton);
     faceButton.addActionListener(this);
     add(tessRepButton);
     tessRepButton.addActionListener(this);
     add(removeButton);
     removeButton.addActionListener(this);
     //add(clearButton);
     //clearButton.addActionListener(this);
     vat = at = 0;
  }


  public static void 
  mergesort(Face [] inArray, int leftPos, int rightPos)
  {
    int i, j, k, center;
    
      int size = inArray.length;          //get the number of elements of the input array
    Face [] tempArray = new Face[size];     //allocate a new array with equivalent number of elements
    
    if(rightPos>leftPos)
      {
	center= (rightPos+leftPos)/2;     //compute the center position

	//merge sort the left and right half of the inArray respectively
	mergesort(inArray, leftPos, center); 
	mergesort(inArray, center+1, rightPos);
	
        // assign the left and right half of inArray to the corresponding position in tempArray
	for (i=center+1; i>leftPos;  i--) tempArray[i-1] = inArray[i-1]; 
 
	for (j=center; j < rightPos; j++)   tempArray[rightPos+center-j] = inArray[j+1];

	//Merge the now-sorted left and right halves
	//by comparing ends of tempArray progressively
	//now i is leftPos, j is rightPos as initial value
	for (k=leftPos; k<=rightPos; k++)
	  {
	    if (tempArray[i].compareTo(tempArray[j]) == -1) 
	      inArray[k] = tempArray[i++];
	    else
	      inArray[k]= tempArray[j--];
	  }
      }
  }


  // ActionListener
  public void actionPerformed(ActionEvent e)
  {

    if (e.getActionCommand().equals("Tessellation Representation") && (canvas.FacesAdded())) {
        
 //       System.out.println("Tessellation Representation");
        double checkpos; 
        double checkpos2;      
	checkpos = 10000;
	checkpos2 = 0;
        // Display Vertices
 //       System.out.println("Vertices: ");
        for (int j=0; j<graph.vertices.length; j++) {
          v = (DirectedVertex)(graph.vertices.elements[j]);
          if (v.position.y < checkpos) {
          	checkpos = v.position.y;
          	vsink = v;
          }
          if (v.position.y > checkpos2) {
          	checkpos2 = v.position.y;
          	vsource = v;
          }
    //      System.out.println(v.toString());
        }

//	System.out.println("Sink: ");
//        System.out.println(vsink.toString());
//	System.out.println("Source: ");
//        System.out.println(vsource.toString());

  //      System.out.println("Vertices: ");
        for (int j=0; j<graph.vertices.length; j++) {
          v = (DirectedVertex)(graph.vertices.elements[j]);
          canvas.thelongestpath = 0;
          canvas.longestpath(v,vsource,0);
  //        System.out.println(canvas.thelongestpath + " " + v.toString());
          ((DirectedVertex)graph.vertices.elements[j]).vertexnum = canvas.thelongestpath;
        }


        
        // Display Edges
  /*      int length = graph.edges.length;
        System.out.println("Edges:");
      for (int i=0; i<length; i++) {
        edg = (DirectedEdge)(graph.edges.elements[i]);
        System.out.println(edg.toString());
      }*/
/*
      for (int j = 1; j <= canvas.numberoffaces; j++) {
	System.out.println("-Face " + j + " Information");
	System.out.println(" Number of Vertices : " + canvas.Faces[j].numofvertices);

	System.out.println(" Vertices List: ");

	int numofverticesinface = canvas.Faces[j].vertices.length;
	for (int k=0; k<canvas.Faces[j].vertices.length; k++) {
        			v = (DirectedVertex)(canvas.Faces[j].vertices.elements[k]);
    				System.out.println(v.toString());
    			}
      
      }      
  */    
  
      //Arrays.sort(canvas.Faces, 1, canvas.numberoffaces + 1); 
      mergesort(canvas.Faces,1,canvas.numberoffaces);
            
      for (int j = 1; j <= canvas.numberoffaces; j++) {
//	System.out.println("-Face " + j + " Information");
//	System.out.println(" Number of Vertices : " + canvas.Faces[j].numofvertices);

//	System.out.println(" Vertices List: ");

	int numofverticesinface = canvas.Faces[j].vertices.length;
	for (int k=0; k<canvas.Faces[j].vertices.length; k++) {
        			v = (DirectedVertex)(canvas.Faces[j].vertices.elements[k]);
   // 				System.out.println(v.toString());
    			}
    			
    //	System.out.println(" Edges List: ");

	for (int k=0; k<canvas.Faces[j].numofedges; k++) {
        			DirectedEdge tempedge = (DirectedEdge)(canvas.Faces[j].edges.elements[k]);

			        for (int i=0; i<graph.edges.length; i++) {
        				edg = (DirectedEdge)(graph.edges.elements[i]);
					if (edg == tempedge) {
					
						if (((DirectedEdge)(graph.edges.elements[i])).leftface == 255) {
							((DirectedEdge)(graph.edges.elements[i])).leftface = j;
						} else if (((DirectedEdge)(graph.edges.elements[i])).rightface == 255){
							((DirectedEdge)(graph.edges.elements[i])).rightface = j;						
						}
						
					}
      				}
				        			
        			
  //  				System.out.println(tempedge.toString());
    			}



      
      }      
      
      // Determining left and right face #'s for vertices

        for (int j=0; j<graph.vertices.length; j++) {
          v = (DirectedVertex)(graph.vertices.elements[j]);
	  if (v == vsink) {
	  
	  	((DirectedVertex)(graph.vertices.elements[j])).leftface = 0;
	  	((DirectedVertex)(graph.vertices.elements[j])).rightface = canvas.numberoffaces + 1;
	  
	  }
	
	  if (v == vsource) {
	  
	  	((DirectedVertex)(graph.vertices.elements[j])).leftface = 0;
	  	((DirectedVertex)(graph.vertices.elements[j])).rightface = canvas.numberoffaces + 1;
	  
	  }
	
	}

	// Traverse through left side from source to sink, marking left face 0 to left vertice and edges 
	
	boolean leftsidedone = false;
	DirectedVertex leftsidevertex = vsource;
	
	while (!leftsidedone) {
	
		if (leftsidevertex.tohash().equals(vsink.tohash())) {
			leftsidedone = true;
		} else {
		
		        for (int j=0; j<graph.vertices.length; j++) {
          			v = (DirectedVertex)(graph.vertices.elements[j]);
				if (v.tohash().equals(leftsidevertex.tohash())) {
				
					((DirectedVertex)(graph.vertices.elements[j])).leftface = 0;
				
					double lowestxposoutedge = 1000;
					double angleout;
					DirectedVertex vertextofollow = new DirectedVertex();
					DirectedEdge edgetofollow = (DirectedEdge)graph.edges.elements[0];
				
					for (int k=0; k<((DirectedVertex)(graph.vertices.elements[j])).outedges.length; k++) {
					
					double newx = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.position.x;
					double newy = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.position.y;
					double oldx = v.position.x;
					double oldy = v.position.y;

//					System.out.println (newx + " " + oldx + " " + newy + " " + oldy);
					if ((newx == oldx) && (newy == oldy)) {angleout = 1001; } else {
					angleout =  ((Math.atan((oldy-newy)/(oldx-newx)) * 180) / Math.PI);
					//if (angleout < 0) angleout = (angleout * -1) + 90;
					if (angleout < 0) angleout = (90 - (angleout * -1)) + 90;
					}
//					System.out.println(angleout);
					
						if ((angleout < lowestxposoutedge) &&
						(!(((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.tohash().equals(leftsidevertex.tohash()))))
						 {
						
							lowestxposoutedge = angleout;
							vertextofollow = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end;
							edgetofollow = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k]));
												
						}
						
					}
					
				for (int i=0; i<graph.edges.length; i++) {
        				edg = (DirectedEdge)(graph.edges.elements[i]);
					if (edg == edgetofollow) {
					
						if (((DirectedEdge)(graph.edges.elements[i])).leftface == 255) {
							((DirectedEdge)(graph.edges.elements[i])).leftface = 0;
						} else {
							((DirectedEdge)(graph.edges.elements[i])).rightface = 0;						
						}
						
					}
      				}
					

					
					leftsidevertex = vertextofollow;
					break;
				
				}			
			}
			
		}
		
	}
	
	// Traverse through right side from source to sink, marking the far right face on the far right vertices and edges.

//	System.out.println("Right Side");

	leftsidedone = false;
	leftsidevertex = vsource;
	
	while (!leftsidedone) {
	
		if (leftsidevertex.tohash().equals(vsink.tohash())) {
			leftsidedone = true;
		} else {
		
		        for (int j=0; j<graph.vertices.length; j++) {
          			v = (DirectedVertex)(graph.vertices.elements[j]);
				if (v.tohash().equals(leftsidevertex.tohash())) {
				
					((DirectedVertex)(graph.vertices.elements[j])).rightface = canvas.numberoffaces + 1;
				
					double lowestxposoutedge = 0;
					double angleout;
					
					DirectedVertex vertextofollow = new DirectedVertex();
					DirectedEdge edgetofollow = (DirectedEdge)graph.edges.elements[0];
				
					for (int k=0; k<((DirectedVertex)(graph.vertices.elements[j])).outedges.length; k++) {
					
					double newx = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.position.x;
					double newy = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.position.y;
					double oldx = v.position.x;
					double oldy = v.position.y;
 
		//			System.out.println (newx + " " + oldx + " " + newy + " " + oldy);
					if ((newx == oldx) && (newy == oldy)) {angleout = 0; } else {
					angleout =  ((Math.atan((oldy-newy)/(oldx-newx)) * 180) / Math.PI);
					 if (angleout < 0) angleout = (90 - (angleout * -1)) + 90;
					}
		//			System.out.println(angleout);
										
						if ((angleout > lowestxposoutedge) &&
						(!(((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end.tohash().equals(leftsidevertex.tohash()))))
						 {
		//					System.out.println("Changing...");
							lowestxposoutedge = angleout;
							vertextofollow = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k])).end;
							edgetofollow = ((DirectedEdge)(((DirectedVertex)(graph.vertices.elements[j])).outedges.elements[k]));
												
						}
						
					}

				for (int i=0; i<graph.edges.length; i++) {
        				edg = (DirectedEdge)(graph.edges.elements[i]);
					if (edg == edgetofollow) {
		//				System.out.println("Modifying edge..");
						if (((DirectedEdge)(graph.edges.elements[i])).leftface == 255) {
							((DirectedEdge)(graph.edges.elements[i])).leftface = canvas.numberoffaces + 1;
						} else {
							((DirectedEdge)(graph.edges.elements[i])).rightface = canvas.numberoffaces + 1;						
						}
						
					}
      				}

					leftsidevertex = vertextofollow;
					break;
				
				}			
			}
			
		}
		
	}

	// Switch left and right faces of edges if they are backwards
	  //      System.out.println("Edges:");
      int tempfacenum;
      for (int i=0; i<graph.edges.length; i++) {
      	if (((DirectedEdge)(graph.edges.elements[i])).leftface > ((DirectedEdge)(graph.edges.elements[i])).rightface) {
      	
      		tempfacenum = ((DirectedEdge)(graph.edges.elements[i])).leftface;
      		((DirectedEdge)(graph.edges.elements[i])).leftface = ((DirectedEdge)(graph.edges.elements[i])).rightface;
      		((DirectedEdge)(graph.edges.elements[i])).rightface = tempfacenum;
      		
      	}
        edg = (DirectedEdge)(graph.edges.elements[i]);
        //System.out.println(edg.toString());
      }

	// Finishing assigning left and right faces to vertices		
        //System.out.println("Vertices: ");
        for (int j=0; j<graph.vertices.length; j++) {
          v = (DirectedVertex)(graph.vertices.elements[j]);
         
	double furleftfacepos = 1000;
	double furrightfacepos = 0;
	int furleftface = 255;
	int furrightface = 255; 

          
          for (int k=0; k<v.outedges.length; k++) {
          	if (((DirectedEdge)(v.outedges.elements[k])).end.position.x < furleftfacepos) {
          		furleftfacepos = ((DirectedEdge)(v.outedges.elements[k])).end.position.x;
          		furleftface = ((DirectedEdge)(v.outedges.elements[k])).leftface;

          	}
          	if (((DirectedEdge)(v.outedges.elements[k])).end.position.x > furrightfacepos) {
          		furrightfacepos = ((DirectedEdge)(v.outedges.elements[k])).end.position.x;
          		furrightface = ((DirectedEdge)(v.outedges.elements[k])).rightface;

          	}
          
          }
          if (((DirectedVertex)(graph.vertices.elements[j])).leftface == 255) 
	          ((DirectedVertex)(graph.vertices.elements[j])).leftface = furleftface;
          if (((DirectedVertex)(graph.vertices.elements[j])).rightface == 255) 
	          ((DirectedVertex)(graph.vertices.elements[j])).rightface = furrightface;
          
          v = (DirectedVertex)(graph.vertices.elements[j]);

          //System.out.println(v.toString());
        }

// Display Tessellation Representation

     	FirstWindow.init();
        int totalnumofhor = 1;
        int totalnumofhorcolors = 0;
        
//        System.out.println("Vertices: ");
        for (int j=0; j<graph.vertices.length; j++) {
          v = (DirectedVertex)(graph.vertices.elements[j]);
      FirstWindow.horlines[totalnumofhor]=(v.leftface);
      FirstWindow.horlines[totalnumofhor+1]=(v.vertexnum);
      FirstWindow.horlines[totalnumofhor+2]=(v.rightface);
      FirstWindow.horlines[totalnumofhor+3]=(v.vertexnum);
	totalnumofhor = totalnumofhor + 4;
	totalnumofhorcolors++;
	FirstWindow.horlinescolors[totalnumofhorcolors] = v.vertexcolor;
  //    	  System.out.print("(" + v.leftface + "," + v.vertexnum + ") ");
//	  System.out.println("(" + v.rightface + "," + v.vertexnum + ")");
	}
	totalnumofhor--;
	FirstWindow.horlines[0] = totalnumofhor;


//      System.out.println("Faces: ");
//      System.out.println("-Face 0 (0," + vsink.vertexnum + ") (0,0)");
	FirstWindow.verlines[1] = 0;
	FirstWindow.verlines[2] = vsink.vertexnum;
	FirstWindow.verlines[3] = 0;
	FirstWindow.verlines[4] = 0;

				Random rand = new Random();
		        int tempred = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
		        int tempblue = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
		        int tempgreen = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
		        Color tempcolor = new Color(tempred,tempblue,tempgreen);
	
	FirstWindow.verlinescolors[1] = tempcolor;
	
	int totalnumofver = 5;
	int totalnumofvercolors = 1;

      for (int j = 1; j <= canvas.numberoffaces; j++) {

	double toppos = 1000;
	double bottompos = 0;
	int topvernum = 255;
	int bottomvernum = 255;

	int numofverticesinface = canvas.Faces[j].vertices.length;
	for (int k=0; k<canvas.Faces[j].vertices.length; k++) {
        			v = (DirectedVertex)(canvas.Faces[j].vertices.elements[k]);
				if (v.position.y < toppos) {
				
					toppos = v.position.y;
					topvernum = v.vertexnum;	
				
				}
				if (v.position.y > bottompos) {
				
					bottompos = v.position.y;
					bottomvernum = v.vertexnum;	
				
				}
			
    		}
//	System.out.println("-Face " + j + " (" + j + "," + topvernum + ") (" + j + "," + bottomvernum + ")");
	FirstWindow.verlines[totalnumofver] = j;
	FirstWindow.verlines[totalnumofver+1] = topvernum;
	FirstWindow.verlines[totalnumofver+2] = j;
	FirstWindow.verlines[totalnumofver+3] = bottomvernum;
	totalnumofver = totalnumofver + 4; 
	totalnumofvercolors++;
	FirstWindow.verlinescolors[totalnumofvercolors] = canvas.Faces[j].facecolor;
      
}      
	FirstWindow.verlines[totalnumofver] = canvas.numberoffaces + 1;
	FirstWindow.verlines[totalnumofver+1] = vsink.vertexnum;
	FirstWindow.verlines[totalnumofver+2] = canvas.numberoffaces + 1;
	FirstWindow.verlines[totalnumofver+3] = 0;
	totalnumofver = totalnumofver + 3;
	totalnumofvercolors++;
			tempred = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
			tempblue = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
			tempgreen = (int)((long)(Math.random () * (long)(Math.pow (10, 3)))) % 255;
			tempcolor = new Color(tempred,tempblue,tempgreen);
	
	FirstWindow.verlinescolors[totalnumofvercolors] = tempcolor;
	FirstWindow.verlines[0] = totalnumofver;

      // System.out.println("-Face " + (canvas.numberoffaces + 1) + " (" + (canvas.numberoffaces + 1) + "," + vsink.vertexnum + ") (" + (canvas.numberoffaces + 1) + ",0)");
      
	

        // Display Edges
        // System.out.println("Edges:");
      int totalnumofrec = 1;
      int totalnumofreccolors = 0;
      for (int i=0; i<graph.edges.length; i++) {
        edg = (DirectedEdge)(graph.edges.elements[i]);
        totalnumofreccolors++;
        FirstWindow.rectang[totalnumofrec] = edg.leftface;
        FirstWindow.rectang[totalnumofrec+1] = edg.end.vertexnum;
        FirstWindow.rectang[totalnumofrec+2] = edg.rightface;
        FirstWindow.rectang[totalnumofrec+3] = edg.start.vertexnum;
	totalnumofrec = totalnumofrec + 4;
	FirstWindow.rectangcolors[totalnumofreccolors] = edg.edgecolor;        
      //  System.out.println("Edge (" + edg.leftface + "," + edg.end.vertexnum + ") (" + edg.rightface + "," + edg.start.vertexnum + ")");
        
      }
      totalnumofrec--;
      FirstWindow.rectang[0] = totalnumofrec;
      
	FirstWindow.start();
      
      
      
      
      
    }
    else if (e.getActionCommand().equals("Remove Vertices and Edges")) {
      int length = graph.vertices.length;
      // remove the verticies and edges
      for (int i=0; i<length; i++)
        graph.vertices.delete((DirectedVertex)(graph.vertices.elements[0]));
      length = graph.edges.length;
      for (int i=0; i<length; i++)
        graph.edges.delete((DirectedEdge)(graph.edges.elements[0]));
      canvas.repaint();
    }
    else if (e.getActionCommand().equals("Clear")) {
      int length = graph.vertices.length;
      // remove the verticies and edges
      for (int i=0; i<length; i++)
        graph.vertices.delete((DirectedVertex)(graph.vertices.elements[0]));
      length = graph.edges.length;
      for (int i=0; i<length; i++)
        graph.edges.delete((DirectedEdge)(graph.edges.elements[0]));
      canvas.repaint();
      vat = at = 0;
    }
    else if (e.getActionCommand().equals("Add Face")) {
    	canvas.setFaceMode();
    }

  }
}
