/* Author:  Tz-Yang Tang
            Bhashinee Garg
 */


import wdcor.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.NumberFormat;


import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.InputMismatchException;
import java.lang.Math;


public class GECLlibrary{

final String outputFilename = "GECLoutput.kml"; // OUPTUT FILENAME	
PrintWriter outp;

WorldCoords[] citiesByName = new WorldCoords[9117];
int cityNumber = 0;
int num = 8;

NumberFormat fmt = NumberFormat.getInstance();

// Print Point Object
	public void printPoint(GECLdatatypes geclobj)
	{
		
		dist tempdist = new dist(geclobj.getelv());
		double tempdb;
		tempdb= tempdist.getDouble(); // covert to meter
		tempdb= tempdb/0.3048;  // from meter convert to feet 
        fmt.setMaximumFractionDigits(num);
	
		outp.println("<Point>   " );
		outp.println("<coordinates>" +fmt.format(geclobj.getlon())+',' +fmt.format(geclobj.getlat()) +','+tempdb+"</coordinates>");
		outp.println("</Point>   " );
		}
	
// Print Distance Object		
	public void printdis(String dists)
	{
		outp.println("<Distance>   " );
		outp.println("<coordinates>" +dists+"</coordinates>");
		outp.println("</Distance>   " );
		}

// Print Coordinate Object
	public void printcoord(GECLdatatypes geclobj)
	{
		dist tempdist = new dist(geclobj.getelv());
		double tempdb;
                fmt.setMaximumFractionDigits(num);
		tempdb= tempdist.getDouble(); // covert to meter
		tempdb= tempdb/0.3048;  // from meter convert to feet 		
		outp.println("<coordinates>" +fmt.format(geclobj.getlon())+',' +fmt.format(geclobj.getlat()) +','+tempdb+"</coordinates>");
		}

// Print Square
public void printquadrangle(GECLdatatypes geclobj)
	{
        fmt.setMaximumFractionDigits(num);
	    outp.println("<Placemark>");
	    outp.println("<name> "+ geclobj.getname() +" </name>");		
		outp.println(" <Polygon>");
   		outp.println("<extrude>1</extrude>");
    	outp.println("<altitudeMode>relativeToGround</altitudeMode>");
   		outp.println(" <outerBoundaryIs>");
   		outp.println("   <LinearRing>");
    	outp.println("    <coordinates>");
     	outp.println(""+fmt.format(geclobj.getlfuplo()) +','+fmt.format(geclobj.getlfupla())  +','+geclobj.getstrhi());
     	outp.println(""+fmt.format(geclobj.getlfdnlo())+','+fmt.format(geclobj.getlfdnla()) +','+geclobj.getstrhi());
    	outp.println(""+fmt.format(geclobj.getrtdnlo())+','+fmt.format(geclobj.getrtdnla()) +','+geclobj.getstrhi());
  		outp.println(""+fmt.format(geclobj.getrtuplo())+','+fmt.format(geclobj.getrtupla())+','+geclobj.getstrhi());
  		outp.println(""+fmt.format(geclobj.getlfuplo()) +','+fmt.format(geclobj.getlfupla())  +','+geclobj.getstrhi());
   		outp.println("     </coordinates>");
    	outp.println("  </LinearRing>");
   		outp.println(" </outerBoundaryIs>");
  		outp.println("</Polygon>");
		outp.println("</Placemark> ");		
		}


// Print Triangle
   /*public static void printtriangle(GECLdatatypes geclobj) {
       
        fmt.setMaximumFractionDigits(num);
        outp.println("<Placemark>");
	    outp.println("<name> Test TRIANGLE </name>");		
		outp.println(" <Polygon>");
   		outp.println("<extrude>1</extrude>");
    	outp.println("<altitudeMode>relativeToGround</altitudeMode>");
   		outp.println(" <outerBoundaryIs>");
   		outp.println("   <LinearRing>");
    	outp.println("    <coordinates>");
     	outp.println(""+fmt.format(west_lo)+','+fmt.format(west_la)+','+struct_hi);
    	outp.println(""+fmt.format(east_lo)+','+fmt.format(east_la)+','+struct_hi);
        outp.println(""+fmt.format(north_lo)+','+fmt.format(north_la)+','+struct_hi);
     	outp.println(""+fmt.format(west_lo)+','+fmt.format(west_la)+','+struct_hi);

   		outp.println(" </coordinates>");
    	outp.println("  </LinearRing>");
   		outp.println(" </outerBoundaryIs>");
  		outp.println("</Polygon>");
		outp.println("</Placemark> ");
      }*/
		
    
// Print Overlay
     public void printOverlay(GECLdatatypes geclobj)
	{
        fmt.setMaximumFractionDigits(num);
	    outp.println("<GroundOverlay>");
	    outp.println("<name> "+ geclobj.getname() +" </name>");
	    outp.println("<visibility>1</visibility>");

		outp.println("<Icon>   " );
		outp.println("	<href>" +geclobj.geturl()+"</href>");
		outp.println("</Icon>   " );
		outp.println("<LatLonBox>");
		outp.println("	<north>"+fmt.format(geclobj.getlfupla())+"</north>");
    	outp.println("	<south>"+fmt.format(geclobj.getrtdnla())+"</south>");
    	outp.println("	<east>"+fmt.format(geclobj.getrtdnlo())+"</east>");
    	outp.println("	<west>"+fmt.format(geclobj.getlfuplo())+"</west>");

		outp.println("</LatLonBox>");
		outp.println("</GroundOverlay>");
		}

// Print Line
     public void printLine(GECLdatatypes geclobj)
	{
		int SizeOfLine;
        fmt.setMaximumFractionDigits(num);
		outp.println("<Placemark>");
	    outp.println("<name> "+ geclobj.getname() +" </name>");		
   		outp.println("<visibility>1</visibility>");
 		outp.println(" <open>0</open>");
  		outp.println("<Style>");
    	outp.println("<LineStyle>");
      	outp.println("<color>ff00ffff</color>");
      	outp.println("<width>2</width>");
    	outp.println("</LineStyle>");
  		outp.println("</Style>");
  		outp.println("<LineString>");
    	outp.println("	<extrude>1</extrude>");
    	outp.println("	<tessellate>1</tessellate>");
    	outp.println("	<altitudeMode>absolute</altitudeMode>");
    	outp.println("    <coordinates>");
    	SizeOfLine = geclobj.getLineNum();
    	for (int i = 0 ; i < SizeOfLine;i++){ 
    	dist tempdist = new dist(geclobj.getLineArrayelv(i));
		double tempdb;
		tempdb= tempdist.getDouble(); // covert to meter
		tempdb= tempdb/0.3048;  // from meter convert to feet 		
     	outp.println(""+fmt.format(geclobj.getLineArraylon(i)) +','+fmt.format(geclobj.getLineArraylat(i))  +','+tempdb);
   		}
   		outp.println("     </coordinates>");
		outp.println("</LineString>");
		outp.println("</Placemark> ");		
		}

// Print Placemark --> not complete!!
     public void printPlace(GECLdatatypes geclobj)
	{
		dist tempdist = new dist(geclobj.getelv());
		double tempdb;
        fmt.setMaximumFractionDigits(num);
		tempdb= tempdist.getDouble(); // covert to meter
		tempdb= tempdb/0.3048;  // from meter convert to feet 
	    outp.println("<Placemark>");
	    outp.println("<name> "+ geclobj.gettitle() +" </name>");
		if(geclobj.minePersp.BeenSet()) 
		{
			outp.println("	<LookAt> ");
    		outp.println("		<longitude>"+fmt.format(geclobj.minePersp.getlon())+"</longitude>");
    		outp.println("		<latitude>"+fmt.format(geclobj.minePersp.getlat())+"</latitude>");
    		outp.println("		<range>"+fmt.format(geclobj.minePersp.getrange())+"</range>");
    		outp.println("		<tilt>"+geclobj.minePersp.gettilt()+"</tilt>");
    		outp.println("		<heading>"+geclobj.minePersp.getheading()+"</heading>");
  			outp.println("	</LookAt>");
			}
		outp.println("	<Point>   " );
		outp.println("		<coordinates>" +fmt.format(geclobj.getlon())+',' +fmt.format(geclobj.getlat()) +','+tempdb+"</coordinates>");
		outp.println("	</Point>   " );
		outp.println("</Placemark> ");
		}

// Print kml file header
	public void printhr()
	{
		outp.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		outp.println("<kml xmlns=\"http://earth.google.com/kml/2.0\">\n");
		
	// Add temprory	
		outp.println("<Folder>");
    	outp.println("<description>Showing-off GECL</description>");
    	outp.println("<name>GECL Output</name>");
    	outp.println("<open>0</open>");
		
		}

// Print kml file tail
	public void printtl()
	{
		// Add temprory	
		outp.println("</Folder>");
		outp.append("</kml>\n\n");
		}	

// Open kml file PrintWriter file description and print header
	public void creatkml()
		{

		System.out.print("Trying to create KML script file...\n");
		try{
			PrintWriter out = new PrintWriter(outputFilename);
			outp = out;
			printhr();
		}
		catch (IOException exception)
		{
			System.out.println("Error processing file:   " + exception);
		}
		
		
	}
	
// Close kml file PrintWriter file description and print tail	
	public void endkml()
		{
		printtl();
		outp.close();
		}
		
		
	public void sortCityCoords(){
    	  

		WorldCoords[] Cities = null;
		String needless;
		
		//try-catch block if the file could not be found
		try{
				File inputFile = new File("worldcities.txt");
				Scanner scanFile = new Scanner(inputFile);
				cityNumber = scanFile.nextInt();
				
				 Cities = new WorldCoords[cityNumber];
				 
				 for(int i = 0; i < cityNumber; i++){
					 
					 needless = scanFile.nextLine();
					 String cityState = scanFile.nextLine();
					 double longi = scanFile.nextDouble();
					 double lati = scanFile.nextDouble();
					 
					 Cities[i] = new WorldCoords(longi, lati, cityState);
				 }

                 //have the other 2 arrays' references set to the original
				 for(int j = 0; j < cityNumber; j++){
					 citiesByName[j] = Cities[j];
				 }
				 
				 //now we sort the citiesByName lexicographically
				 WorldCoordsComparator NameCmp = new CmpByName();
				 SortingAlgorithms.mySortingAlgorithm(citiesByName, NameCmp);
		}
	
		catch(FileNotFoundException FNFE){
			System.out.println("File not found.");

		}
   }	
    

    public WorldCoords getCityCoords(String City, String Country){

                //clean possible data remains from last time
				WorldCoords result1 = null, result2 = null;
				String city1, state1, fileName, c_s, cityForSearch;
				int resultNum = 1;
				result1 = null;
				result2 = null;
				
				city1 = City;
				state1 = Country;
				c_s = city1 + state1;
				
				//now make the city and state into a form that facilitates the searching, 
				//namely making it into the same form as the String name in WorldCoords
				StringBuilder tmp = new StringBuilder("");
			    char c;
			    for(int i=0, j=0; i< c_s.length(); i++){
			      c = Character.toUpperCase(c_s.charAt(i));
			      if( c >= 'A' && c <= 'Z' ) tmp.append(c);
			    }
			    cityForSearch = tmp.toString();
				   
				//now we perform a binary search on citiesByName and put the results in 
			    //result1 and result2
				int low = 0;
				int high = cityNumber - 1;
				int mid = 0;
				
				while(low <= high){
					mid = (low + high) / 2;
					if(cityForSearch.compareTo(citiesByName[mid].name) < 0)
						high = mid - 1;
					else if(cityForSearch.compareTo(citiesByName[mid].name) > 0)
						low = mid + 1;
					else
						break;
				}
			System.out.println("found city " + citiesByName[mid]);	
			
			return citiesByName[mid];
    }
   
    public void reportError(String msg, String id)
    {
        System.err.println(msg + ": " + id);
        System.exit(0);
    }
}
