//Need to ask Todd about sizes (font, window).

/**
 * CRStateDisplay.java
 *
 * Created: July 10, 2002
 *
 * @author David Hettlinger
 * MyMancalaFrame.java was used as a template.
 */

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
import java.util.Vector;

public class CRStateDisplay extends JFrame{

    /**
     * variable <code>northPane</code> - JPanel containing the top row of pins
     */
    private JPanel northPanel = new JPanel();  

    /*
     * variable <code>southPanel</code> - JPanel containing the bottom row of pins
     */
    private JPanel southPanel = new JPanel(); 

    /**
     * variable <code>wiringPanel</code> - CRWiringPanel object for the wiring
     */
    private CRWiringPanel wiringPanel = new CRWiringPanel(); 
    
    /**
     * variable <code>pinLabel</code> - the pin JLabels
     */
    private JLabel[][] pinLabel;

    /**
     * variable <code>crState</code> - the CRState object
     */
    private CRState4 crState;

    char[] nums = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    char[] uc = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
		 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 
		 'W', 'X', 'Y', 'Z'};
    char[] lc = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
		 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
		 'w', 'x', 'y', 'z'};
    char[] etc = {'@', '#', '$', '%', '&', '\u00B6', '?', '\u00A3', '\u00A9', '\u00A2', '\u00BF'};

    /**Creates a new <code>CRStateDisplay</code> instance.
       Sets up the initial state of the GUI.
      *@param state the crState object to work with. 
    */
    public CRStateDisplay (CRState4 state){

	crState = state;
		
	//I found info on getScreenSize from Frameworks.java of the Java
	//tutorial.
	Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
	int screenWidth = screenSize.width;
	int screenHeight = screenSize.height;

	//final int DEFAULT_FRAME_WIDTH = (int) (screenSize.width * 0.7);
	//final int DEFAULT_FRAME_HEIGHT = (int) (screenSize.height * 0.4);
	int frameWidth;
	if (crState.columns * 50 < screenWidth) frameWidth = crState.columns * 50;
	else frameWidth = screenWidth;
	int frameHeight;
	if (crState.v * 40 < screenHeight) frameHeight = crState.v * 40;
	else frameHeight = screenHeight;
	
	setSize(frameWidth, frameHeight);
		
	
	pinLabel = new JLabel[2][crState.columns];
	//int fontSize = frameWidth / crState.columns;
	//Font pinFont = new Font("SansSerif", Font.PLAIN, fontSize);
	
	Container contentPane = getContentPane();  
	//All components of the GUI will be added to contentPane
	//directly or indirectly.
    	 
	//Making northPanel and southPanel
	//This grid layout is messing me up.  When there's too many columns,
	
	/*GridBagLayout gridbag = new GridBagLayout();
	GridBagLayout gridbag2 = new GridBagLayout();
	GridBagConstraints c = new GridBagConstraints();
	GridBagConstraints c2 = new GridBagConstraints();
	northPanel.setLayout(gridbag);
	southPanel.setLayout(gridbag2);
	c.fill = GridBagConstraints.HORIZONTAL;
	c.weightx = 1;
	c2.fill = GridBagConstraints.HORIZONTAL;
	c2.weightx = 1;
	*/
		
	GridLayout pinLayout = new GridLayout(1, crState.columns, 1, 1);
	northPanel.setLayout(pinLayout); 
        southPanel.setLayout(pinLayout);
	//northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.X_AXIS));
	//southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.X_AXIS));
	
	//northPanel and southPanel each contain JLabels that contain
	//the pin numbers
	char symbol;
	int netNum;
	int fontSize = 12;
	if (crState.columns > 90) fontSize = 9;
	Font pinFont = new Font("pinFont", Font.PLAIN, fontSize);

	for (int count = 0; count < crState.columns; count++) {

	    netNum = crState.topRow[count];
	    if (netNum <= 9) symbol = nums[netNum];
	    else if(netNum <= 9 + 26) symbol = uc[netNum - 10];
	    else if(netNum <= 9 + 26 + 26) symbol = lc[netNum - 10 - 26];
	    else symbol = etc[netNum - 10 - 26 - 26];
	    pinLabel[0][count] = 
		new JLabel("" + symbol, SwingConstants.CENTER);
	    pinLabel[0][count].setFont(pinFont);

	    netNum = crState.bottomRow[count];
	    if (netNum <= 9) symbol = nums[netNum];
	    else if(netNum <= 9 + 26) symbol = uc[netNum - 10];
	    else if(netNum <= 9 + 26 + 26) symbol = lc[netNum - 10 - 26];
	    else symbol = etc[netNum - 10 - 26 - 26];
	    pinLabel[1][count] = 
		new JLabel("" + symbol, SwingConstants.CENTER);
	    pinLabel[1][count].setFont(pinFont);
	    
	    //c.gridx = count;
	    //c2.gridx = count;
	    //gridbag.setConstraints(pinLabel[0][count], c);
	    //gridbag2.setConstraints(pinLabel[1][count], c2);
	    northPanel.add(pinLabel[0][count]);
	    southPanel.add(pinLabel[1][count]);
	}
		
	//Now wiringPanel, northPanel, and southPanel are added to
	//contentPane
	
	contentPane.add(wiringPanel, "Center");
	contentPane.add(northPanel, "North");
	contentPane.add(southPanel, "South");
				
	//Adds a window listener so that the program will exit when
	//the window is closed.
	addWindowListener(new WindowCloser()); 

	//updateCRFrame is called to update the GUI.
	updateCRFrame();
      
    }
  
    /**
     * Updates this display object.
    */
     public void updateCRFrame() {
   
	 for (int i = 0; i < crState.columns; i++) {
	     char symbol;
	     int netNum = crState.topRow[i];
	     if (netNum <= 9) symbol = nums[netNum];
	     else if(netNum <= 9 + 26) symbol = uc[netNum - 10];
	     else if(netNum <= 9 + 26 + 26) symbol = lc[netNum - 10 - 26];
	     else symbol = etc[netNum - 10 - 26 - 26];
	     pinLabel[0][i].setText("" + symbol);

	     netNum = crState.bottomRow[i];
	     if (netNum <= 9) symbol = nums[netNum];
	     else if(netNum <= 9 + 26) symbol = uc[netNum - 10];
	     else if(netNum <= 9 + 26 + 26) symbol = lc[netNum - 10 - 26];
	     else symbol = etc[netNum - 10 - 26 - 26];
	     pinLabel[1][i].setText("" + symbol);
	 }
	 
	 wiringPanel.repaint();  //Redraws the wiring. 
     }

    /**This innerclass recognizes when the user closes the window.
     */
    private class WindowCloser extends WindowAdapter {
	/**Given a WindowEvent that specifies that the window is closed,
	   windowClosing exits the program.
	*/
	public void windowClosing(WindowEvent event) {
	    System.exit(0);
	}
    }
    
    /**This innerclass is used to draw the wiring.
    */
    class CRWiringPanel extends JPanel{
	private int x;
	private int y;
	private int width;
	private int height;
	private Vector vBars = new Vector();
	private Vector hBars = new Vector();
	private Vector vias = new Vector();

	/**Given a Graphics object, paintComponent does the actual drawing.
	 */
	public void paintComponent(Graphics g){
	    
	    vBars.clear();
	    hBars.clear();
	    vias.clear();
	    
	    super.paintComponent(g);
	    Graphics2D g2 = (Graphics2D)g;

	    width = getWidth();
	    height = getHeight();
	 
	    final int BORDER_WIDTH = height / (crState.columns * 7);
	    final int HORIZONTAL_DISPLACEMENT = width / crState.columns;
	    //final int VERTICAL_DISPLACEMENT = height / crState.v;
	    final int HORIZONTAL_OFFSET = width / (int) (crState.columns * 2.48);
	    final int VERTICAL_OFFSET = (int) Math.round(height * 1.0 / (crState.v * 2.0));
	    int defaultWidth = width / (crState.columns * 5);
	    int wireWidth = 1;
	    if(defaultWidth >= 1) wireWidth = defaultWidth;
	    else if(defaultWidth < 1) wireWidth = 1; 
	    double viaDiam = wireWidth * 1.5;
	    if (wireWidth <= 2.0) viaDiam = wireWidth * 2.0;

	    int[] vertOrder = crState.getVertsOrder();
	    	     
	    //Draws the bounding rectangle.
	    Rectangle backGround = new Rectangle(0, 0, width - 1, height - 1);
	    g2.setColor(Color.white);
	    g2.fill(backGround);
	    g2.setColor(Color.black);

	    //Draws the two horizontal channel width indicators.
	    Rectangle topBorder = new Rectangle(0, 0, width - 1, BORDER_WIDTH);
	    g2.fill(topBorder);
	    Rectangle bottomBorder = new Rectangle(0, (height - 1) - BORDER_WIDTH, width - 1, BORDER_WIDTH);
	    g2.fill(bottomBorder);
	 
	    //Draw the wires and via circles.
	    int xStart = 0;
	    int xEnd = 0;
	    int y = 0;
	    int firstColumn = 0;
	    int secColumn = 0;
	    	    
	    for (int trackNum = 0; trackNum < crState.v; trackNum++){
				
		for (int subNum = 0; subNum < crState.subsInVert[vertOrder[trackNum]]; subNum++){

		    y = height - VERTICAL_OFFSET - (int) Math.round(1.0 * trackNum / crState.v * height);

		    firstColumn = crState.verts[vertOrder[trackNum]][subNum].begin;
		    secColumn = crState.verts[vertOrder[trackNum]][subNum].end;
		    xStart = HORIZONTAL_OFFSET +  firstColumn * HORIZONTAL_DISPLACEMENT;
		    xEnd = HORIZONTAL_OFFSET + secColumn * HORIZONTAL_DISPLACEMENT;
		    
		    if (firstColumn == secColumn) 
			vBars.add(new Rectangle(xStart, BORDER_WIDTH, wireWidth, (height - 1) - BORDER_WIDTH));
		    else {

			vias.add(new Ellipse2D.Double(1.0 * xStart - wireWidth / 3.0, 1.0 * y - wireWidth / 3.0, viaDiam, viaDiam));
			vias.add(new Ellipse2D.Double(1.0 * xEnd - wireWidth / 3.0, 1.0 * y - wireWidth / 3.0, viaDiam, viaDiam));
		    
			hBars.add(new Rectangle(xStart, y, (xEnd - xStart) + wireWidth, wireWidth));
		    
			if (crState.verts[vertOrder[trackNum]][subNum].net 
			    == crState.topRow[firstColumn]) 
			    vBars.add(new Rectangle(xStart, BORDER_WIDTH, wireWidth, y));
			else 
			    vBars.add(new Rectangle(xStart, y, wireWidth, (height - 1) - y - BORDER_WIDTH));
		    
			if (crState.verts[vertOrder[trackNum]][subNum].net 
			    == crState.topRow[secColumn])
			    vBars.add(new Rectangle(xEnd, BORDER_WIDTH, wireWidth, y));
			else 
			    vBars.add(new Rectangle(xEnd, y, wireWidth, (height - 1) - y - BORDER_WIDTH));
		    }
		    		    
		}
	    }

	    g2.setColor(Color.blue);
	    for (int i = 0; i < vBars.size(); i++)
		g2.fill((Rectangle) vBars.get(i));
	    g2.setColor(new Color(194, 77, 28));
	    for (int i = 0; i < hBars.size(); i++)
		g2.fill((Rectangle) hBars.get(i));
	    g2.setColor(Color.black);
	    for (int i = 0; i < vias.size(); i++)
		g2.fill((Ellipse2D.Double) vias.get(i));
	}
	
    }
    
   } // CRStateDisplay



	 






