/**
 * Map Generator Groovy weather sample
 */
package weather.map.generator;

import idea.geometry.CartesianDimension;
import idea.geometry.CartesianPosition;
import idea.geometry.Offset;
import idea.graphics.shapes.complex.meteo.WindBarb.SpeedUnit;
import idea.geographic.coordsys.orthogonal2d.CartesianGeoDimension;
import idea.geographic.coordsys.orthogonal2d.CartesianGeoOffset;
import idea.geographic.coordsys.orthogonal2d.CartesianGeoPosition;
import idea.geographic.coordsys.orthogonal3d.WGS84GeoPosition;
import idea.geometry.CartesianDimension;
import idea.geometry.CartesianOffset;
import idea.geometry.CartesianPosition;
import idea.graphics.map.GeographicImageMap;
import idea.graphics.map.HtmlImageMap;
import idea.graphics.map.HtmlImageMapItemsFromInputDataValues;
import idea.graphics.map.GeographicImageMap.ImageMapParameters;
import idea.graphics.shapes.complex.ListColorScaleLegend;
import idea.graphics.shapes.complex.geo.czech.RegionsCzechRepublic;
import idea.graphics.shapes.simple.Text;
import idea.graphics.shapes.complex.meteo.WindBarb;
import idea.map.colorscale.ColorForValueRange;
import idea.map.colorscale.StandardListColorScale;
import idea.map.generator.GeographicMapCanvas;
import idea.map.generator.MapGenerator;
import idea.map.generator.MapGenerator.MapGeneratorResult;
import idea.map.matrix.ComputedMatrix;
import idea.map.interpolator.IDWInterpolator;
import idea.map.interpolator.IDWParameters;
import idea.map.matrix.MatrixParameters;
import idea.map.renderer.AbstractRenderer;
import idea.map.renderer.GeoImageMapRenderer;
import idea.map.writer.AbstractMapWriter;
import idea.map.writer.ImageMapWriterToCanvas;
import idea.map.writer.MapWriterToFile;
import idea.map.writer.MapWriterToHtmlFile;
import idea.map.writer.MapWriters;
import idea.map.writer.WriterGroup;
import idea.geographic.coordsys.transformation.BursaWolf;
import idea.geographic.coordsys.transformation.CoordinateTransformationWGS84_S42;
import idea.geographic.coordsys.transformation.CoordinateTransformationWGS84_S42.S42zoneWide;

import java.awt.Color;
import java.awt.Font;
import java.net.URI;
import java.util.ArrayList;
import java.util.Locale;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;

import weather.data.*;


/**
 * Entry point
 * Use this for educational purposes only, not for real flying
 * 
 * @author Lumir Vanek, vanek@idea-envi.cz
 * 
 */
class Main
{
	/**
	 * Generate simple weather map
	 * 
	 * @param args Arguments
	 */
	static main(args)
	{
		/*
		 * Load airports data from XML
		 */
		def xmlAirports = new XmlParser().parse('./input/airports.xml');

		final List< Airport > airports = new ArrayList< Airport >();
		
		xmlAirports.each
		{
			Airport airport = new Airport(icaoCode: it.@icaoCode,
							name: it.@name,
							geoPosition: new WGS84GeoPosition(Double.valueOf(it.WGS84GeoPosition[0].@longitude), Double.valueOf(it.WGS84GeoPosition[0].@latitude)));

			println "Loaded airport: " + airport.toString();
			airports.add airport;
		}
		
		/*
		 * For each airport, get weather info - simple METAR decoding
		 */
		airports.each { Airport airport ->
		 
			URL url = new URL("http://weather.noaa.gov/pub/data/observations/metar/stations/" + airport.icaoCode + ".TXT");
			URLConnection connection = url.openConnection();
			
			connection.connect();
			String metar = connection.content.text;
			println "Metar for:" + airport.icaoCode + " is: " + metar;
			
			airport.weather = new Weather(airport.icaoCode, metar);
		}	
	
		/**
		 * Create weather map
		 */
		final String renderedMatrixId = 'matrix';
		
		/*
		 * Define Color scale ranges and colors
		 */
		int seq = 0; // value range sequence
		List colorScaleItems = [
			new ColorForValueRange("Lowest", "#FFFFFF", null, 0.0f, 900.0f, ++seq),
			new ColorForValueRange("Lower", "#D7F2FD", null, 900.0f, 950.0f, ++seq),
			new ColorForValueRange("Low", "#C2E4FD", null, 950.0f, 1000.0f, ++seq),
			new ColorForValueRange("Low-Mid", "#AED5FE", null, 1000.0f, 1015.0f, ++seq),
			new ColorForValueRange("Mid", "#98C1FF", null, 1015.0f, 1016.0f, ++seq),
			new ColorForValueRange("High", "#81ABFF", null, 1016.0f, 1017.0f, ++seq),
			new ColorForValueRange("Higher", "#6B8FFF", null, 1017.0f, 1020.0f, ++seq),
			new ColorForValueRange("Highest", "#5970F4", null, 1020.0f, null, ++seq)
			] as ArrayList;
		
		// HTML image map serves tooltips, when user move mouse over map in HTML viewer
		HtmlImageMap htmlImageMap = new HtmlImageMap('imageMap');
		
		BursaWolf bursaWolf = new BursaWolf(-23, 124, 84, -0.13, -0.25, 0.02, -1.1e-6);
		final CoordinateTransformationWGS84_S42 ct = new CoordinateTransformationWGS84_S42(3, S42zoneWide.dg6, bursaWolf);
				
		MapGenerator generator = new MapGenerator('Weather info',
				Locale.ENGLISH,
				null, // create own collector
				ct, 
				// Matrixes parameters
				new MatrixParameters(450, 680, 1000, new CartesianGeoPosition(3200000, 5300000)),
				// Color scale
				new StandardListColorScale("Air pressure", "hPa", colorScaleItems),
				// Map parameters
				renderedMatrixId,
				new CartesianDimension(680, 450),
				new CartesianGeoPosition(3200000, 5300000),
				1000, // Size of pixel in geographic units
				Color.white, // Background color
				htmlImageMap);
			
		htmlImageMap.add(new MyHtmlImageMapItems(HtmlImageMapItemsFromInputDataValues.Type.CIRCLE,
			renderedMatrixId,
			8) // Size of item in pixels
		);
		
		/*
		 * Add computed matrix
		 */
		generator.getMatrixes().put(renderedMatrixId,
				new ComputedMatrix(generator.getMatrixes(),
						renderedMatrixId,
						new IDWInterpolator(new IDWParameters(), null),
						new WeatherDataValues(airports)));
		
		/*
		 * Add map writers
		 */
		
		// To show final map in GUI window
		generator.getMapWriters().add(new ImageMapWriterToCanvas(false));
		
		// Write map PNG image and enclosing HTML
		generator.getMapWriters().add(new MapWriterToFile('./output/map.png', MapWriterToFile.OutputFormat.PNG, false));
		generator.getMapWriters().add(new MapWriterToHtmlFile('./output/weather.html', 
			'map.png', 
			null,
			null, // headerFileName,
			null, // footerFileName,
			'Weather map',
			'wz_tooltip.js',
			null, // jsGraphicsFileName,
			null, // divMapCanvasClass,
			null, // divMapCanvasStyle,
			null, // alternateText,
			false));
			
		/*
		 * Setup renderer					
		 */
		AbstractRenderer renderer = generator.getRenderer();
		if(renderer instanceof GeoImageMapRenderer)
		{
			final GeoImageMapRenderer imageMapRenderer = (GeoImageMapRenderer) renderer;
			final GeographicImageMap geographicMap = imageMapRenderer.getGeographicMap();
			final ImageMapParameters mapParameters = geographicMap.getImageMapParameters();
			
			/**
			 * Add vector shapes, you wish to render over map 
			 */
				
			// Czech Republic regions borders
			geographicMap.addShape(new RegionsCzechRepublic(1.0f, Color.gray, geographicMap.getImageMapParameters()));
				
			// Color scale legend
			geographicMap.addShape(new ListColorScaleLegend(ListColorScaleLegend.Type.STANDARD,
					new CartesianGeoPosition(3700000, 5740000).convertToPixels(mapParameters), // Left bottom position
					new CartesianGeoDimension(165000, 120000).convertToPixels(mapParameters), // Dimension
					new CartesianGeoDimension(20000, 10000).convertToPixels(mapParameters), // Dimension of Item rectangle
					new CartesianOffset(3, 15),  // Main label offset
					new CartesianOffset(3, 20), // Items offset
					new CartesianOffset(22, 10), // Item ranges offset
					new CartesianOffset(110, 10), // Item names offset
					"####", // DecimalFormat pattern for formatting numbers
					new Font("Lucida Sans" , Font.BOLD, 14), // Font for drawing main label text
					new Font("Lucida Console" , Font.PLAIN, 12), // Font for drawing items text
					true, // True, if legend has rectangular frame
					true, // True, if legend items has names
					false) // Show item for NODATA ?
			);
							
			// Text with copyright info		
			geographicMap.addShape(new Text(new CartesianPosition(10, 15),
					"Map Generator, © IDEA-ENVI s.r.o.",
					new Font("Lucida Console" , Font.PLAIN, 15),
					Color.BLUE,
					null));
	
			// For each airport put WindBarb info
			airports.each { Airport airport ->
					
					geographicMap.addShape(new WindBarb(airport.weather.windSpeed,
						airport.weather.windDirection,
						SpeedUnit.KNOTS,
						airport.weather.skyCoverage,
						generator.getCoordTransformation().transformWGS84ToCartesianGeoPos(airport.geoPosition).convertToCartesianGeoPosition().convertToPixels(mapParameters), 
						new CartesianDimension(8, 8),
						5,
						Color.black,
						Color.white,
						airport.icaoCode,
						new Font("Lucida Sans" , Font.PLAIN, 10),
						Color.red,
						new CartesianOffset(5, 5)));
				}
		}
		else assert false;
	
		// Generate map
		generator.initialize();
		MapGeneratorResult result = generator.generate(WriterGroup.getAll());
		
		if(result == MapGeneratorResult.success)
		{
			MapWriters mapWriters = generator.getMapWriters();
			
			// Find ImageMapWriterToCanvas, force it to render final map to GUI
			for(AbstractMapWriter mapWriter : mapWriters)
			{
				if(mapWriter instanceof ImageMapWriterToCanvas)
				{
					ImageMapWriterToCanvas imageMapWriterToCanvas = (ImageMapWriterToCanvas) mapWriter;
					
					GeographicMapCanvas canvas = imageMapWriterToCanvas.getCanvas();
					
					if(canvas != null)
					{
						JFrame frame = new JFrame(generator.getDescription() == null ? "Map" : generator.getDescription());
						frame.add(canvas);
						frame.setSize(canvas.getGeographicsMap().getImageMapParameters().getDimension().toAwtDimension());
						   imageMapWriterToCanvas.setParent(frame);
						   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
						frame.setVisible(true);
					}
					
					break;
				}
			}
		}
		
		println 'Finished';
	}
}