/**
 * @ MapGenerator.java
 * @ version 1.0 2009/6/22
 */
import java.awt.*;
import java.awt.event.*;
import java.io.*;
//import java.util.LinkedList;
import java.util.Vector;

public class MapGenerator extends Frame 
{
	boolean bProcessed = false;	//to prevent partial draws on paint method
	
	int upperLeftX = 25;	//upperLeft Offset
	int upperLeftY = 50;
	int areaWidth = 830;	//writable area
	int areaHeight = 605;
	int screenWidth = 880;	//total Area
	int screenHeight = 680;
	
	// List structures should DEF be rnd-access based
	Vector listOfLines = new Vector();
	Vector formattedLines = new Vector();	//wish this wasn't needed
	
	double minX, minY, maxX, maxY;	//can't assume ANYTHING
	
	int newAreaHeight = -1;	//derived Ratio from the Input
	int newAreaWidth = -1;
	
	String inputFile = "<empty>";
	FileDialog fd;	//AWT
	File myFile;
	
	Dialog statusBox;	//The Loading Elements
	Label statusLabel;
	
	public static void main(String[] args) 
	{
		new MapGenerator();
	}
	public MapGenerator()
	{
		//FRAME SETUP FIRST
		setTitle("Map Generator 1.0");
		setSize(screenWidth, screenHeight);
		setResizable(false);
		setVisible(true);
		addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent we){System.exit(0);} }	);
		//File Dialog
		fd = new FileDialog(MapGenerator.this, "Select Vector File", FileDialog.LOAD);
		//fd.setLocation(100, 100);	//forget this for now
		fd.setVisible(true);
		if(fd.getFile() == null)
			System.exit(0);
		myFile = new File(fd.getDirectory() + fd.getFile());
		inputFile = fd.getFile();
		this.repaint();	//repaints the file name basically
		//Loading Set up Calls (Dialog, Label)
		statusBox = new Dialog(MapGenerator.this, "Loading...");
		statusBox.setResizable(false);
		statusBox.setSize(100, 75);
		statusBox.setLocation((screenWidth/2)-(statusBox.getWidth()/2), (screenHeight/2)-(statusBox.getHeight()/2));
		statusBox.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent we) {System.exit(0);} } );
		statusLabel = new Label(" Parsing... ", Label.CENTER);
		statusBox.add(statusLabel);
		statusLabel.setVisible(true);
		statusBox.pack();	//packed up and all set...
		statusBox.setVisible(true);
		//Parser
		try
		{
			FileInputStream fis = new FileInputStream(myFile);
			int x = fis.available();
			byte bArray[] = new byte[x];
			fis.read(bArray);						//so now bArray has all the data
			fis.close();
			int fileIndexPointer = 0;
	line:	while(fileIndexPointer < bArray.length)	//Each Iteraton is for one line...
			{
				double var1, var2, var3, var4;
				String tempHolder = "";
				// Coord (1) ==================================================
				// Tab/Space Eater
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 10)||(bArray[fileIndexPointer] == 32)||(bArray[fileIndexPointer] == 9))
					{	fileIndexPointer++;
						continue;}
					else
						break;
				}
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	
						fileIndexPointer++;
						break;
					}
					else
					{
						tempHolder = tempHolder.concat(   ((char)bArray[fileIndexPointer]) + "");
						fileIndexPointer++;
					}
				}
				var1 = Double.parseDouble(tempHolder);
				tempHolder = "";
				// Coord (2) ==================================================
				// Tab/Space Eater
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	fileIndexPointer++;
						continue;}
					else
						break;
				}
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	
						fileIndexPointer++;
						break;
					}
					else
					{
						tempHolder = tempHolder.concat(   ((char)bArray[fileIndexPointer]) + "");
						fileIndexPointer++;
					}
				}
				var2 = Double.parseDouble(tempHolder);
				tempHolder = "";
				// Coord (3) ==================================================
				// Tab/Space Eater
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	fileIndexPointer++;
						continue;}
					else
						break;
				}
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	
						fileIndexPointer++;
						break;
					}
					else
					{
						tempHolder = tempHolder.concat(   ((char)bArray[fileIndexPointer]) + "");
						fileIndexPointer++;
					}
				}
				var3 = Double.parseDouble(tempHolder);
				tempHolder = "";
				// Coord (4) ==================================================
				// Tab/Space Eater
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 32) || (bArray[fileIndexPointer] == 9))
					{	fileIndexPointer++;
						continue;}
					else
						break;
				}
				while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] == 10)||(bArray[fileIndexPointer] == 32)||(bArray[fileIndexPointer] == 9))
					{	
						fileIndexPointer++;
						break;
					}
					else
					{
						tempHolder = tempHolder.concat(   ((char)bArray[fileIndexPointer]) + "");
						fileIndexPointer++;
					}
				}
				var4 = Double.parseDouble(tempHolder);
				tempHolder = "";
				
				//End of Line, objs loaded
				LineSegment myLineSegment = new LineSegment(var1, var2, var3, var4);
				listOfLines.add(myLineSegment);
				
				//Update the Loading Screen
				int display =  (int) (((double) fileIndexPointer/x) * 100.0);
				statusLabel.setText("Parsing " + display + "%");
				
				//EOF Probe
	EOFProbe:	while(fileIndexPointer < bArray.length)
				{
					if((bArray[fileIndexPointer] != 9) &&
						 (bArray[fileIndexPointer] != 10) &&
							(bArray[fileIndexPointer] != 32) &&
								(bArray[fileIndexPointer] != 13) )
						continue line;
					else
					{
						fileIndexPointer++;
						continue EOFProbe;
					}
				}
			}//end while (line)
		}
		catch(IOException e)
		{ 
			e.printStackTrace(); 
		}
		//find max/min Xs and Ys
		LineSegment firstLine = (LineSegment)listOfLines.get(0);
		minX = firstLine.x1;
		maxX = firstLine.x1;
		minY = firstLine.y1;
		maxY = firstLine.y1;
		if(minX > firstLine.x2)
			minX = firstLine.x2;
		if(maxX < firstLine.x2)
			maxX = firstLine.x2;
		if(minY > firstLine.y2)
			minY = firstLine.y2;
		if(maxY < firstLine.y2)
			maxY = firstLine.y2;
		for(int i=1; i<listOfLines.size(); i++)
		{
			LineSegment thisLine = (LineSegment)listOfLines.get(i);
			if(minX > thisLine.x1)
				minX = thisLine.x1;
			if(maxX < thisLine.x1)
				maxX = thisLine.x1;
			if(minY > thisLine.y1)
				minY = thisLine.y1;
			if(maxY < thisLine.y1)
				maxY = thisLine.y1;
			if(minX > thisLine.x2)
				minX = thisLine.x2;
			if(maxX < thisLine.x2)
				maxX = thisLine.x2;
			if(minY > thisLine.y2)
				minY = thisLine.y2;
			if(maxY < thisLine.y2)
				maxY = thisLine.y2;
				
			//Update the Loading Screen
			int display =  (int) (((double) i/listOfLines.size()) * 100.0);
			statusLabel.setText("Max / Min " + display + "%");
		}

		//Global Mins/Maxs all set at this point
		double originalDrawableRatio = ((double)areaHeight/(double)areaWidth);
		double inputRatio = (( maxY - minY)/(maxX - minX));
		
		newAreaWidth = areaWidth;
		newAreaHeight = areaHeight;
		
		if(inputRatio <= originalDrawableRatio)
			newAreaHeight = (int)(areaWidth * inputRatio);
		if(inputRatio > originalDrawableRatio)
			newAreaWidth = (int)(areaHeight / inputRatio);	
		
		//Format the Linked list (one to another)
		for(int i=0; i<listOfLines.size(); i++)
		{
			LineSegment tempSeg = (LineSegment)listOfLines.get(i);
			tempSeg.processIntCoordinates(minX, maxX, minY, maxY, newAreaWidth, newAreaHeight);
			formattedLines.add(tempSeg);	//Now, Formatted Lines has it all...	
			
			//Update the Loading Screen
			int display =  (int) (((double) i/listOfLines.size()) * 100.0);
			statusLabel.setText("ReProcessing " + display + "%");
		}
		statusBox.setVisible(false);	//Loading done 
		bProcessed = true;	//ok to draw now.	
		this.repaint();
	} //end MapGenerator Constructor
	
	public void paint(Graphics g)
	{
		g.drawString("File:  " + inputFile, 20, 40);
		// My Border 
		// DIMENSIONS: 
		//		X: 830 width (25 to 855)
		//		Y: 605 height(50 to 655)
		g.setColor(Color.black);
		int pad = 4;
		g.drawLine(upperLeftX -pad, upperLeftY -pad, upperLeftX + areaWidth +pad, upperLeftY -pad);
		g.drawLine(upperLeftX -pad, upperLeftY -pad, upperLeftX -pad, upperLeftY + areaHeight +pad);
		g.drawLine(upperLeftX -pad, upperLeftY + areaHeight +pad, upperLeftX + areaWidth +pad, upperLeftY + areaHeight +pad);
		g.drawLine(upperLeftX + areaWidth +pad, upperLeftY + areaHeight +pad, upperLeftX + areaWidth +pad, upperLeftY -pad);
		//Shadow
		g.setColor(Color.gray);
		g.drawLine(upperLeftX-pad+1,upperLeftY+areaHeight+pad+1,upperLeftX+areaWidth+pad+1,upperLeftY+areaHeight+pad+1);
		g.drawLine(upperLeftX+areaWidth+pad+1,upperLeftY+areaHeight+pad+1,upperLeftX+areaWidth+pad+1,upperLeftY-pad+1);
		g.drawLine(upperLeftX-pad+2,upperLeftY+areaHeight+pad+2,upperLeftX+areaWidth+pad+2,upperLeftY+areaHeight+pad+2);
		g.drawLine(upperLeftX+areaWidth+pad+2,upperLeftY+areaHeight+pad+2,upperLeftX+areaWidth+pad+2,upperLeftY-pad+2);
		//Border Is now All-Set
		
		if(bProcessed)
		{
			g.setColor(Color.blue);
			for(int i=0; i<formattedLines.size(); i++)
			{
				int first, second, third, fourth;
				LineSegment tempSeg = (LineSegment)formattedLines.get(i);
				first = tempSeg.intx1;
				second = tempSeg.inty1;
				third = tempSeg.intx2;
				fourth = tempSeg.inty2;
				g.drawLine(first, second, third, fourth);
			}
		}		
	}
	public class LineSegment	//stores the natural coordinates, and derived ones (ints)
	{
		public double 	x1, 	y1, 	x2, 	y2;
		public int 		intx1, 	inty1, 	intx2, 	inty2;
		public LineSegment(double a, double b, double c, double d)
		{
			x1 = a;
			y1 = b;
			x2 = c;
			y2 = d;
			intx1 = 0;
			inty1 = 0;
			intx2 = 0;
			inty2 = 0;
		}
		//Inputs are max/min for the entire data set!
		//New screen heights/widths for different aspect ratios
		public void processIntCoordinates(double minX, double maxX, double minY, double maxY, int screenWidth, int screenHeight)
		{
		//Assume MAX is always more than MIN 
			double wholeDifferenceX = maxX - minX;
			double wholeDifferenceY = maxY - minY;
			double specificDifferenceX1 = this.x1 - minX;
			double specificDifferenceY1 = this.y1 - minY;
			double specificDifferenceX2 = this.x2 - minX;
			double specificDifferenceY2 = this.y2 - minY;
			intx1 = (int)((specificDifferenceX1 / wholeDifferenceX)* screenWidth) ; 
			intx2 = (int)((specificDifferenceX2 / wholeDifferenceX)* screenWidth) ;
			inty1 = (int)((specificDifferenceY1 / wholeDifferenceY)* screenHeight) ;
			inty2 = (int)((specificDifferenceY2 / wholeDifferenceY)* screenHeight) ;
		//Flips the Image Vertically (img origin is at lower left, java's is upper left)
			inty1 = screenHeight - inty1;
			inty2 = screenHeight - inty2; 
		//offsets
			intx1 += 25;
			intx2 += 25;
			inty1 += 50;
			inty2 += 50;
		}
		public String toString()	//Testing Purposes Only
		{
			return "(" + x1 + ", " + y1 + ") : (" + x2 + ", " + y2 + ")";
		}	
	}
}