package org.geotools.gui.swing.example;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.RenderingHints;
import java.io.File;
import java.io.IOException;

import javax.media.jai.InterpolationNearest;
import javax.media.jai.JAI;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;

import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.DataSourceException;
import org.geotools.data.coverage.grid.AbstractGridCoverage2DReader;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.geotools.gce.image.WorldImageReader;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.gui.swing.JMapPane;
import org.geotools.gui.swing.PanAction;
import org.geotools.gui.swing.ResetAction;
import org.geotools.gui.swing.SelectAction;
import org.geotools.gui.swing.ZoomInAction;
import org.geotools.gui.swing.ZoomOutAction;
import org.geotools.map.DefaultMapContext;
import org.geotools.map.MapContext;
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.resources.Arguments;
import org.geotools.styling.RasterSymbolizer;
import org.geotools.styling.StyleBuilder;
import org.opengis.coverage.grid.GridCoverageReader;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.TransformException;

/**
 * Sample application that may be used to try JMapPane from the command line.
 * 
 * @author Simone Giannecchini
 * @author Andrea Antonello
 * @author Andrea Aime
 */
public class TestTiffs {
	private JFrame frame;

	private JMapPane mp;

	private JToolBar jtb;

	private MapContext map;

	/**
	 * {@link CoordinateReferenceSystem} for the loaded data.
	 */
	private CoordinateReferenceSystem crs;

	/**
	 * {@link ReferencedEnvelope} for the loaded data.
	 */
	private ReferencedEnvelope dataEnvelope;

	/**
	 * This program is a simple example of how to use the {@link JMapPane} in
	 * coordination with coverages. In particular this example employs either
	 * the {@link WorldImageReader} or the {@link GeoTiffReader} in ordedr to
	 * show a coverage.
	 * 
	 * <p>
	 * It is worth to point out that when constructing a {@link MapContext} it
	 * is crucia to feed it with the {@link AbstractGridCoverage2DReader}
	 * created for the various formats instead of with the
	 * {@link GridCoverage2D} directly since the reader will allow the renderer
	 * to leverage, when present, internal overviews or, when absent, decimation
	 * on reading which allows to perform nearest neighbor susampling directly
	 * on reading.
	 * 
	 * @throws TransformException
	 * @throws FactoryException
	 * @throws IOException
	 */
	public TestTiffs(final String file) throws TransformException,
			FactoryException, IOException {

		// /////////////////////////////////////////////////////////////////////
		//
		// Create frame and the like
		//
		// /////////////////////////////////////////////////////////////////////
		frame = new JFrame("Test");
		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		Container content = frame.getContentPane();
		mp = new JMapPane();
		// mp.addZoomChangeListener(this);
		content.setLayout(new BorderLayout());
		jtb = new JToolBar();
		Action zoomIn = new ZoomInAction(mp);
		Action zoomOut = new ZoomOutAction(mp);
		Action pan = new PanAction(mp);
		Action select = new SelectAction(mp);
		Action reset = new ResetAction(mp);
		jtb.add(zoomIn);
		jtb.add(zoomOut);
		jtb.add(pan);
		jtb.addSeparator();
		jtb.add(reset);
		jtb.addSeparator();
		jtb.add(select);
		content.add(jtb, BorderLayout.NORTH);

		// /////////////////////////////////////////////////////////////////////
		//
		// Load data and set the relevant parameters
		//
		// /////////////////////////////////////////////////////////////////////
		if (Boolean.getBoolean("org.geotools.test.geotiff"))
			loadImageFile(file, true);
		else
			loadImageFile(file, true);

		// /////////////////////////////////////////////////////////////////////
		//
		// Creating renderer and setting the context
		//
		// /////////////////////////////////////////////////////////////////////
		GTRenderer renderer = new StreamingRenderer();
		// //
		//
		// Setting multiple rendering hints to speed drawing this map up.
		//
		// This map is binary hence we need to turn off all the Java2D
		// antialising and dithering to make it more sharper and faster.
		//
		// //
		RenderingHints jhints = new RenderingHints(JAI.KEY_INTERPOLATION,
				new InterpolationNearest());
		jhints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_OFF));
		jhints.add(new RenderingHints(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_SPEED));
		jhints.add(new RenderingHints(RenderingHints.KEY_COLOR_RENDERING,
				RenderingHints.VALUE_COLOR_RENDER_SPEED));
		jhints.add(new RenderingHints(RenderingHints.KEY_DITHERING,
				RenderingHints.VALUE_DITHER_DISABLE));
		renderer.setJava2DHints(jhints);
		mp.setRenderer(renderer);
		mp.setContext(map);

		// /////////////////////////////////////////////////////////////////////
		//
		// Paint me
		//
		// /////////////////////////////////////////////////////////////////////
		mp.setBackground(Color.WHITE);
		content.add(mp, BorderLayout.CENTER);

		frame.pack();
		frame.setSize(800, 600);
		frame.setVisible(true);

	}

	/**
	 * Loads the reader (an subclass of {@link AbstractGridCoverage2DReader} for
	 * the provided imagePath. If the parameter <code>geotiff</code> is true
	 * we load it as a geotiff otherwise as a world image (which means using the
	 * world and prj file).
	 * 
	 * <p>
	 * <strong>IMPORTANT</strong> It is crucial to pass the
	 * {@link AbstractGridCoverage2DReader} subclass to the the
	 * {@link MapContext} in order to allow the {@link StreamingRenderer} to
	 * leverage on overviews and tiling fr multiple subsequent requests.
	 * 
	 * <p>
	 * If we simply pass the {@link GridCoverage2D} created using the reader
	 * without supplying any parameter to the
	 * {@link GridCoverageReader#read(org.opengis.parameter.GeneralParameterValue[])}
	 * method we will ALWAYS use the highest resolution coverage without having
	 * overviews kicking in.
	 * 
	 * @param imagePath
	 *            tells where to file to load is.
	 * @param geotiff
	 *            tells if the file is a geotiff or not.
	 * @throws TransformException
	 * @throws FactoryException
	 * @throws DataSourceException
	 */
	private void loadImageFile(final String imagePath, final boolean geotiff)
			throws TransformException, FactoryException, DataSourceException {
		// load me simply using the reader
		File tiffFile = new File(imagePath);
		AbstractGridCoverage2DReader rdr = null;
		if (geotiff)
			rdr = new GeoTiffReader(tiffFile);
		else
			rdr = new WorldImageReader(tiffFile);
		assert rdr != null;
		crs = rdr.getCrs();
		dataEnvelope = new ReferencedEnvelope(rdr.getOriginalEnvelope(), crs);

		// between 0 and 255.
		StyleBuilder sb = new StyleBuilder();
		RasterSymbolizer rsDem = sb.createRasterSymbolizer();
		org.geotools.styling.Style demStyle = sb.createStyle(rsDem);

		// map
		map = new DefaultMapContext(crs);
		map.addLayer(rdr, demStyle);
		map.setCoordinateReferenceSystem(crs);
		map.setAreaOfInterest(dataEnvelope);
		mp.setMapArea(dataEnvelope);

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// /////////////////////////////////////////////////////////////////////
		//
		// Parsing input arguments
		//
		// /////////////////////////////////////////////////////////////////////
		final Arguments arguments = new Arguments(args);
		String pathToFile;
		try {
			pathToFile = arguments.getRequiredString("path");
		} catch (IllegalArgumentException e) {
			pathToFile = null;
		}

		if (pathToFile == null | pathToFile.equalsIgnoreCase("")) {
			System.out.println("Wrong path to file provided.");
			System.exit(1);
		}

		// /////////////////////////////////////////////////////////////////////
		//
		// Instantiating
		//
		// /////////////////////////////////////////////////////////////////////
		JAI.getDefaultInstance().getTileCache().setMemoryCapacity(
				80 * 1024 * 1024);
		// final TCTool tool= new TCTool();
		TestTiffs mV = new TestTiffs(pathToFile);

	}
}