//package com.neilmoomey.NauticalChart;


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.io.*;
import java.util.*;
//import java.text.*;
import com.neilmoomey.util.Type;

/** NauticalChartCompassRose.java
 * @author Neil Moomey, www.neilmoomey.com
 * @version 0.1
 **/

public class NauticalChartCompassRose extends JFrame {
	double r_NSEW1, r_NSEW2;
	double var = 22.25;
	int year = 2002;
	String annualIncrease = "";
	String annualDecrease = "12'";
	int radius = 900; //340;
	int width=Type.toInt(radius*2.25);
	int height=width+Type.toInt(radius*0.2);
	int center_x,center_y;
	// Outer ring (True North)
	double r1=radius*0.944;
	double r2=radius*0.956;
	double r2_5=radius*0.971;
	double r2_10=radius*0.986;

	// Middle ring arrow head
	double r4a=radius*0.79;
	double r4b=radius*0.88;
	double r4c=radius*0.82;

	// Middle ring (Magnetic North)
	double r3=radius*0.697;
	double r4=radius*0.709;
	double r4_5=radius*0.727;
	double r4_10=radius*0.74;

	// Inner ring (Magnetic North)
	double r5a=radius*0.616;
	double r5b=radius*0.636;
	double r5=radius*0.656;
	double r6=radius*0.670;

	public NauticalChartCompassRose() {
		super ("NauticalChartCompassRose");
		System.out.println("Constructor");
        setSize(width, height);
	}

	public void paint(Graphics g) {
		System.out.println("paint method");
		//setBackground(Color.white);
		int x1,x2,x3,x4,x5,x6,y1,y2,y3,y4,y5,y6;
		double rad, radVar, rad90;
		String varText;
		Hashtable map;
		// Create a BufferedImage to draw in

		BufferedImage bi = new BufferedImage(width , height, BufferedImage.TYPE_INT_RGB);
		Graphics2D g2D = bi.createGraphics();
		//Graphics2D g2D = (Graphics2D)g;  Use this for displaying only, not for saving image.
		g2D.setPaint(Color.white);
		g2D.fillRect(0,0,width,height);
		g2D.setColor(new Color(155,67,160));
		center_x=width/2;
		center_y=width/2+Type.toInt(radius*0.2);

		//****** draw plus in center ******
		int plusLength=Type.toInt(radius*0.029);
		g2D.drawLine(center_x,center_y - plusLength,center_x,center_y +plusLength);
		g2D.drawLine(center_x - plusLength,center_y,center_x +plusLength,center_y);

		//****** draw 360 degree hack marks ******
		for (double theta=0; theta<360; theta++) {
			rad=Math.toRadians(theta);
			radVar=Math.toRadians(theta+var);

			// Outer ring (True North)
			x1=Type.toInt(r1*Math.cos(rad));
			y1=Type.toInt(r1*Math.sin(rad));
			x2=Type.toInt(r2*Math.cos(rad));
			y2=Type.toInt(r2*Math.sin(rad));

			//Middle ring (Magnetic North)
			x3=Type.toInt(r3*Math.cos(radVar));
			y3=Type.toInt(r3*Math.sin(radVar));
			x4=Type.toInt(r4*Math.cos(radVar));
			y4=Type.toInt(r4*Math.sin(radVar));
			// Change length of hack marks for intevals of 10 and 5.
			if(theta/5==(Math.rint(theta/5))) {
				System.out.println("theta / 5 = " + theta/5);
				x2=Type.toInt((r2_5)*Math.cos(rad));

				y2=Type.toInt((r2_5)*Math.sin(rad));
				x4=Type.toInt((r4_5)*Math.cos(radVar));
				y4=Type.toInt((r4_5)*Math.sin(radVar));
			}

			if(theta/10==(Math.rint(theta/10))) {
				System.out.println("theta / 10 = " + theta/10);
				x2=Type.toInt((r2_10)*Math.cos(rad));
				y2=Type.toInt((r2_10)*Math.sin(rad));
				x4=Type.toInt((r4_10)*Math.cos(radVar));
				y4=Type.toInt((r4_10)*Math.sin(radVar));
			}


			g2D.drawLine(center_x + x1,center_y + y1,center_x +x2,center_y +y2);
			g2D.drawLine(center_x + x3,center_y + y3,center_x +x4,center_y +y4);
			System.out.println("theta= " + theta +"  x1= "+x1+"  y1= "+y1);
		}

		//****** 112 hack marks for inner ring ******
		for (double theta=0; theta<360; theta+=2.8125) {
			//rad=Math.toRadians(theta);
			radVar=Math.toRadians(theta+var);
			x5=Type.toInt(r5*Math.cos(radVar));
			y5=Type.toInt(r5*Math.sin(radVar));
			x6=Type.toInt(r6*Math.cos(radVar));
			y6=Type.toInt(r6*Math.sin(radVar));
			if(theta/5.625==(Math.rint(theta/5.625))) {
				x5=Type.toInt(r5b*Math.cos(radVar));
				y5=Type.toInt(r5b*Math.sin(radVar));
			}
			if(theta/45==(Math.rint(theta/45))) {
				x5=Type.toInt(r5a*Math.cos(radVar));
				y5=Type.toInt(r5a*Math.sin(radVar));
			}
			g2D.drawLine(center_x + x5,center_y + y5,center_x +x6,center_y +y6);
		}

		//****** Draw true north NSEW outer lines ******
		r_NSEW1=radius*1.04;
		r_NSEW2=radius*1.11;
		for (double theta=0; theta<360; theta+=90) {
			rad=Math.toRadians(theta);
			x1=Type.toInt((r_NSEW1)*Math.cos(rad));
			y1=Type.toInt((r_NSEW1)*Math.sin(rad));
			x2=Type.toInt((r_NSEW2)*Math.cos(rad));
			y2=Type.toInt((r_NSEW2)*Math.sin(rad));
			System.out.println("NSEW theta= " + theta +"  x1= "+x1+"  y1= "+y1);
			g2D.drawLine(center_x+x1,center_y+y1,center_x +x2,center_y +y2);
		}

		//****** Draw magnetic NSEW inner lines ******
		r_NSEW1=radius*0.304;
		r_NSEW2=radius*0.548;
		for (double theta=0; theta<360; theta+=90) {
			if (theta>0) r_NSEW2=radius*0.616;
			radVar=Math.toRadians(theta+var);
			x1=Type.toInt((r_NSEW1)*Math.sin(radVar));
			y1=Type.toInt((r_NSEW1)*Math.cos(radVar));
			x2=Type.toInt((r_NSEW2)*Math.sin(radVar));
			y2=Type.toInt((r_NSEW2)*Math.cos(radVar));
			System.out.println("NSEW theta= " + theta +"  x1= "+x1+"  y1= "+y1);
			g2D.drawLine(center_x+x1,center_y-y1,center_x +x2,center_y -y2);
		}

		//****** Draw magnetic north arrow ******
			radVar=Math.toRadians(var);
			x1=Type.toInt((r4a)*Math.sin(radVar));
			y1=Type.toInt((r4a)*Math.cos(radVar));
			x2=Type.toInt((r4b)*Math.sin(radVar));
			y2=Type.toInt((r4b)*Math.cos(radVar));
			g2D.drawLine(center_x+x1,center_y-y1,center_x+x2,center_y-y2);
			radVar=Math.toRadians(var-1.8);
			x1=Type.toInt((r4c)*Math.sin(radVar));
			y1=Type.toInt((r4c)*Math.cos(radVar));
			g2D.drawLine(center_x+x1,center_y-y1,center_x+x2,center_y-y2);
			radVar=Math.toRadians(var+1.8);
			x1=Type.toInt((r4c)*Math.sin(radVar));
			y1=Type.toInt((r4c)*Math.cos(radVar));
			g2D.drawLine(center_x+x1,center_y-y1,center_x+x2,center_y-y2);

		//****** Draw degree numbers for True North ******
		map = new Hashtable();
		map.put(TextAttribute.FAMILY, "Courier");
		map.put(TextAttribute.SIZE, new Float(Type.toInt(radius*0.035)));		
		for (double theta=0; theta<360; theta+=30) {
			drawTextPath(g2D, map, theta, radius, Type.toString(Type.toInt(theta)));
		}

		//****** Draw degree numbers for Magnetic North ******	
		for (double theta=0; theta<360; theta+=30) {
			drawTextPath(g2D, map, theta+var, radius*0.75, Type.toString(Type.toInt(theta)));
		}


		//****** Draw text for middle ******
		map.put(TextAttribute.BACKGROUND, Color.blue);
		//map.put(TextAttribute.JUSTIFICATION_FULL);
		//map.put(TextAttribute.POSTURE, 0.20);
		drawTextPath(g2D, map, var, radius*0.58, "MAGNETIC");
		varText = "VAR " + convertVar(var) + "(" + year + ")";
		drawTextPath(g2D, map, var, radius*0.25, varText);
		
		
		//rad180=Math.toRadians(Math.toDegrees(theta+180));
		//AffineTransform rotate = AffineTransform.getRotateInstance(rad);
		//map.put(TextAttribute.TRANSFORM, rotate);
		if (annualIncrease.length() > 0) drawTextPathFlip(g2D, map, var+180, radius*0.25, "ANNUAL INCREASE " + annualIncrease);
		else drawTextPathFlip(g2D, map, var+180, radius*0.25, "ANNUAL DECREASE " + annualDecrease);


		//****** Display graph ******
		Graphics2D g_display = (Graphics2D)g;
		g_display.setPaint(new TexturePaint(bi, new Rectangle(width, height)));
		g_display.fill(new Rectangle2D.Double(0,0,width,height));

		//****** Save image as png file ******
		ImageUtil iu= new ImageUtil();
		File file1 = new File("NauticalChartCompassRose.png");
		iu.savePNG(bi,file1);
	}
	
	public void drawTextPath(Graphics2D g2D, Hashtable map, double theta, double r, String text) {
		double rad, rad90, fontSize;
		int x1,y1;
		for (int i=0; i<text.length(); i++) {
			fontSize = Type.toDouble(map.get(TextAttribute.SIZE).toString());
			rad=Math.toRadians((theta+(i/r*1000)) - text.length()/r*500); //420,210
			x1=Type.toInt((r)*Math.sin(rad));
			y1=Type.toInt((r)*Math.cos(rad));
			AffineTransform rotate = AffineTransform.getRotateInstance(rad);
			map.put(TextAttribute.TRANSFORM, rotate);
			Font font = new Font(map);
			g2D.setFont(font);
			g2D.drawString(text.substring(i,i+1), center_x+x1, center_y-y1);	
			//System.out.println("char =  " +text.substring(i,i+1));
		}
	}
	
	public void drawTextPathFlip(Graphics2D g2D, Hashtable map, double theta, double r, String text) {
		double rad, rad90, fontSize;
		int x1,y1;
		for (int i=0; i<text.length(); i++) {
			fontSize = Type.toDouble(map.get(TextAttribute.SIZE).toString());
			rad=(Math.toRadians((theta+(i/r*1000)) - text.length()/r*500));
			x1=Type.toInt((r)*Math.sin(rad));
			y1=Type.toInt((r)*Math.cos(rad));
			AffineTransform rotate = AffineTransform.getRotateInstance(rad+Math.PI);
			map.put(TextAttribute.TRANSFORM, rotate);
			Font font = new Font(map);
			g2D.setFont(font);
			g2D.drawString(text.substring( (text.length()-1)-i,text.length()-i ) , center_x+x1, center_y-y1);	
		}
	}	
	
	public String convertVar(double var) {
		String varText;
		int degrees, minutes;
		double varAbs = Math.abs(var);
		degrees = new Double(varAbs).intValue();
		minutes = Type.toInt((varAbs - degrees)*60);
		if (var > 0) varText = degrees + "°" + minutes + "'E";
		else varText = degrees + "°" + minutes + "'W";
		return varText;
	}

	public static void main(String[] args) {
        JFrame f = new NauticalChartCompassRose();
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //System.exit(0);
	}
}

