package usda.weru.erosion;

import javax.swing.*;			// For JPanel, etc.
import java.awt.*;				// For Graphics, etc.
import java.awt.geom.*;			// For Ellipse2D, etc.
import java.beans.*;

/**
 * Creates graphics panel with representation of field dimensions and orientation.
 * Is property change listener to show field and barriers.
 */

public class DrawField extends JPanel implements PropertyChangeListener {
    private static final long serialVersionUID = 1L;

	private boolean drawnToScaleFlag = true;
	private static final Color[] barColor = {Color.blue, Color.red, Color.cyan, Color.magenta, Color.orange};

	
	private void drawBarrier(Graphics2D g2d, int bdx) {

		double cX1, cX2, cY1, cY2;
		cX1 = 0;
		cX2 = 0;
		cY1 = 0;
		cY2 = 0;
//		//System.out.println("DF_dB: " + bdx + " " + XLen + " " + SXLen + " " + YLen + " " + SYLen + " " + X1[bdx] + " " + Y1[bdx] + " " + X2[bdx] + " " + Y2[bdx]);

		if (Double.isNaN(XYRatio)) {
			cX1 = X1[bdx] / XLen * 100;
			cY1 = Y1[bdx] / XLen * 100;
			cX2 = X2[bdx] / XLen * 100;
			cY2 = Y2[bdx] / XLen * 100;
		} else if (Double.isNaN(YXRatio)) {
			cX1 = X1[bdx] / YLen * 100;
			cY1 = Y1[bdx] / YLen * 100;
			cX2 = X2[bdx] / YLen * 100;
			cY2 = Y2[bdx] / YLen * 100;
		}
		// make narrow width or height barriers visible
		if (Math.abs(cY2 - cY1) < 5 && (Double.compare(cX1, cX2) != 0)) cY2 = cY1 + 5;
		if (Math.abs(cX2 - cX1) < 5 && (Double.compare(cY1, cY2) != 0)) cX2 = cX1 + 5;
		Rectangle2D.Double rect = new Rectangle2D.Double(-SXLen / 2 + cX1, SYLen / 2 - cY1 - (cY2 - cY1), cX2 - cX1, cY2 - cY1);
		g2d.setPaint(barColor[bdx]);
		g2d.fill(rect);
	}
	
//	private Rectangle2D.Double border =
//			new Rectangle2D.Double(10, 10, 190, 190);

//  private Rectangle2D.Double square2 =
//	new Rectangle2D.Double(50, 50, 100, 100);

	static	int	rotCount = 0;
	
  private final Rectangle2D.Double square2 =
	new Rectangle2D.Double(-50, -50, 100, 100);

  private Rectangle clipRect = null;
  
  /**
   * This method paints/repaints the visual source on the GUI by calling its native functions and 
   * stabilizes the pictureon the view.
   * @param g The object that is used to redraws the graphical nature of the image.
   */
    @Override
  public void paintComponent(Graphics g) {      
    clear(g);
	if (XLen <= 0 || YLen <= 0) return;
    Graphics2D g2d = (Graphics2D)g;
//	Rectangle clipRect = g2d.getClipBounds();
	if (clipRect == null) clipRect = g2d.getClipBounds();
	
	Rectangle2D.Double border = new Rectangle2D.Double(10, 10,
		clipRect.width-20, clipRect.height-20);

    g2d.draw(border);
////System.out.println("DF_pC: g size " + g2d.getClipBounds());
   // Move the origin to the center of the square.
	drawCompass(g2d);
	g2d.translate(clipRect.width/2, clipRect.height/2);
//	g2d.translate(105.0, 105.0);
	Color color = Color.green;
	if (SYLen < SXLen / 10.0) {
		SYLen = SXLen / 10.0;
		drawnToScaleFlag = false;
	} else if (SXLen < SYLen / 10.0) {
		SXLen = SYLen / 10.0;
		drawnToScaleFlag = false;
	}
	if (!drawnToScaleFlag) {
		g2d.drawString("Field not drawn to scale", -90, 90);
		color = Color.yellow;
	}
//	drawCompass(g2d);
	if (!drawnToScaleFlag) {
		g2d.drawString("Barriers not to scale", -90, -80);
	}
	g2d.rotate(Angle * Math.PI/180.0);
//	g2d.drawString("X-Axis", -15, 90);
	g2d.drawString("X-Axis", -25, (int) (SYLen / 2)+20);
	g2d.rotate(90 * Math.PI/180.0);
//	g2d.drawString("Y-Axis", -15, 90);
	g2d.drawString("Y-Axis", -25, (int) (SXLen / 2)+20);
	g2d.rotate(270 * Math.PI/180.0);
//	g2d.rotate(Angle * Math.PI/180.0);		this is where rotate was
	g2d.setPaint(color);
	if (SXLen != 0.0 && SYLen != 0.0) {
////System.out.println("DF_pC: " + (- SXLen / 2) + " " + ( - SYLen / 2) + " " + SXLen + " " +  SYLen);
		g2d.fill(new Rectangle2D.Double(- SXLen / 2, - SYLen / 2,
										SXLen, SYLen));
		g2d.setPaint(Color.red);
		for (int idx = 0; idx < numBar; idx++) {
			drawBarrier(g2d, idx);
		}
	}
    drawWind(g2d);
  }

  private void drawCompass(Graphics2D g2d)
  {
	  g2d.setPaint(Color.blue);
//	  Rectangle clipRect = g2d.getClipBounds();
	  g2d.translate(clipRect.width-30, 20);
	  int[] xpoints = {5, 10, 10,  6,  6, 4, 4, 0, 0};
	  int[] ypoints = {0, 5, 7, 2, 30, 30, 2, 7, 5};
//	  int[] xpoints = {85, 90, 90, 86, 86, 84, 84, 80, 80};
	  //int[] ypoints = {-15, -10, -8, -13, 15, 15, -13, -8, -10};
//	  int[] ypoints = {-90, -85, -83, -88, -60, -60, -88, -83, -85};
	  Polygon arrow = new Polygon(xpoints, ypoints, xpoints.length);
	  g2d.fill(arrow);
	  g2d.setPaint(Color.black);
	  //g2d.drawString("N", 80, 5);
////System.out.println("DF_dC: " + g2d.getClipBounds());

//	Rectangle2D.Double border = new Rectangle2D.Double(10, 10,
//		clipRect.width-20, clipRect.height-20);
		
//	  g2d.drawString("N", 80, -70);
	g2d.drawString("N", 0, 20);
	g2d.translate(-(clipRect.width-30), -20);
  }
  
  private void drawWind(Graphics2D g2d)
  {
	  g2d.setPaint(Color.red);
	  g2d.translate(0, -20);
    	g2d.rotate(windDir * Math.PI/180.0);
//	  Rectangle clipRect = g2d.getClipBounds();
	  int[] xpoints = {5, 10, 10,  6,  6, 4, 4, 0, 0};
	  int[] ypoints = {0, 5, 7, 2, 30, 30, 2, 7, 5};
//	  int[] xpoints = {85, 90, 90, 86, 86, 84, 84, 80, 80};
	  //int[] ypoints = {-15, -10, -8, -13, 15, 15, -13, -8, -10};
//	  int[] ypoints = {-90, -85, -83, -88, -60, -60, -88, -83, -85};
	  Polygon arrow = new Polygon(xpoints, ypoints, xpoints.length);
	  g2d.fill(arrow);
	  g2d.setPaint(Color.black);
	  //g2d.drawString("N", 80, 5);
////System.out.println("DF_dC: " + g2d.getClipBounds());

//	Rectangle2D.Double border = new Rectangle2D.Double(10, 10,
//		clipRect.width-20, clipRect.height-20);
		
//	  g2d.drawString("N", 80, -70);
	g2d.drawString("W", 0, 20);
    	g2d.rotate(-windDir * Math.PI/180.0);
        	  g2d.translate(0, 20);

  }
  
  // super.paintComponent clears offscreen pixmap,
  // since we're using double buffering by default.
  
  /**
   * Clears the screen from the barrier drawing that were drawn on te GUI panel for displaying the
   * field details or existance.
   * @param g The graphics object used to clear the contents from the screen acting as an eraser.
   */
  protected void clear(Graphics g) {
    super.paintComponent(g);
  }

  /**
   * Default constructor for the class that initialises some basic things and calls 
   * its super constructor which is from the panel.
   */ 
  public DrawField() {
	  super();
	  setToolTipText("DrawField:main");
  
		//{{INIT_CONTROLS
		setLayout(new FlowLayout(FlowLayout.CENTER,5,5));
		setSize(0,0);
		//$$ lineBorder1.move(0,1);
		//}}
	}

  /**
   * This method is used if this dialog is rum as an independent application. If executed,
   * makes the GUI visible.
   * @param args These are the command line arguments passed to the main method.
   */
  public static void main(String[] args) {
//    WindowUtilities.openInJFrame(new DrawField(), 240, 260);
//	JFrame frame = new JFrame(title);
    JFrame frame = new JFrame("Draw Field Test");
	frame.setBackground(Color.white);
	DrawField df = new DrawField();
	df.XLen = 100;
	df.YLen = 80;
	df.setBackground(Color.white);  
	df.addPropertyChangeListener(df);
	frame.setSize(240, 260);
//	frame.setContentPane(content);
	frame.setContentPane(df);
//	frame.addWindowListener(new ExitListener());
	frame.setVisible(true);

	df.propertyChange(new PropertyChangeEvent(df,DataStore.SimRegLenX, null, "100"));
	df.propertyChange(new PropertyChangeEvent(df,DataStore.SimRegLenY, null, "80"));
	try {
		Thread.sleep(1000);
	} catch (java.lang.InterruptedException f) {
	}
	System.exit(0);
  }

  double XLen = 0;
  double YLen = 0;
  double Angle = 0;
  double SYLen = 0;
  double SXLen = 0;
  double windDir = 0;

	/**
	 *
	 */
	public static final int maxNumBar = 5;
  int numBar = 0;
  double [] X1 = new double[maxNumBar];
  double [] Y1 = new double[maxNumBar];
  double [] X2 = new double[maxNumBar];
  double [] Y2 = new double[maxNumBar];
  double XYRatio = 0;
  double YXRatio = 0;
  double baseLen = 50;
  
  /**
   * Listens and updates changes to incorporate the modifications intended by an event trigger on the 
   * same or a different GUI component being registered to listen or react based on
   * @param e The event triggered when some property that is registered with this object happen to
   * undergo changes due to user interaction or other screen's event generation.
   */
    @Override
    public void propertyChange(PropertyChangeEvent e) {        
////System.out.println("DF-pC: " + e.getPropertyName());
		String property = e.getPropertyName();
        if (!(e.getNewValue() instanceof String)) return;
		String value = (String) e.getNewValue();
	    if (property.equals(DataStore.SimRegLenX)) {
			drawnToScaleFlag = true;
			try {
 				XLen = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			if (XLen == 0 || YLen == 0) return;
			if (XLen > YLen) {
                SXLen = baseLen;
				YXRatio = YLen / XLen;
				XYRatio = Double.NaN;
				SYLen = (YLen / XLen) * baseLen;
				if (SYLen < SXLen / 10.0) {
					SYLen = SXLen / 10.0;
					YXRatio = 0.1;
					drawnToScaleFlag = false;
				}
			} else {
				SYLen = baseLen;
				YXRatio = Double.NaN;
				XYRatio = XLen / YLen;
				SXLen = (XLen / YLen) * baseLen;
				if (SXLen < SYLen / 10.0) {
					SXLen = SYLen / 10.0;
					XYRatio = 0.1;
					drawnToScaleFlag = false;
				}
			}
			repaint();
		} else if (property.equals(DataStore.SimRegLenY)) {
			drawnToScaleFlag = true;
			try {
				YLen = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			if (XLen == 0 || YLen == 0) return;
			if (XLen > YLen) {
//				SXLen = 100;
				SXLen = baseLen;
//				SYLen = (YLen / XLen) * 100;
				SYLen = (YLen / XLen) * baseLen;
				YXRatio = YLen / XLen;
				XYRatio = 0;
			} else {
//				SYLen = 100;
				SYLen = baseLen;
				YXRatio = 0;
				XYRatio = XLen / YLen;
//				SXLen = (XLen / YLen) * 100;
				SXLen = (XLen / YLen) * baseLen;
			}
			repaint();
		} else if (property.equals(DataStore.SimRegAngle)) {
			try {
				Angle = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		} else if (property.equals(DataStore.BarriersNum)) {
			numBar = Integer.parseInt(value);
			repaint();
		} else if (property.startsWith(DataStore.BarriersOrgX)) {
			int idx = getBarNum(property);
			try {
				X1[idx] = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		} else if (property.startsWith(DataStore.BarriersOrgY)) {
			int idx = getBarNum(property);
			try {
				Y1[idx] = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		} else if (property.startsWith(DataStore.BarriersLenX)) {
			int idx = getBarNum(property);
			try {
				X2[idx] = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		} else if (property.startsWith(DataStore.BarriersLenY)) {
			int idx = getBarNum(property);
			try {
				Y2[idx] = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		} else if (property.startsWith(DataStore.WeaWindDir)) {
			try {
				windDir = Double.parseDouble(value);
			} catch (NumberFormatException k) {
				//System.err.println("RP-pC: bad XLen from rfd " + k);
			}
			repaint();
		}
	}
	private int getBarNum(String inpProp) {
//		//System.out.println("DF_gBN: " + inpProp);
		return Integer.parseInt(inpProp.substring(inpProp.length()-1));
	}

}
