package tim.prune.function.srtm;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.GpsPrune;
import tim.prune.I18nManager;
import tim.prune.config.Config;
import tim.prune.data.DoubleRange;
import tim.prune.gui.ProgressDialog;

/**
 * Class to provide a download function for the Space Shuttle's SRTM data files.
 * HGT files are downloaded into memory via HTTP and stored in the map cache.
 */
public class DownloadSrtmFunction extends GenericFunction implements Runnable
{
	/** Progress dialog */
	private ProgressDialog _progress = null;
	/** Flag to check whether this function is currently running or not */
	private boolean _running = false;


	/**
	 * Constructor
	 * @param inApp  App object
	 */
	public DownloadSrtmFunction(App inApp) {
		super(inApp);
	}

	/** @return name key */
	public String getNameKey() {
		return "function.downloadsrtm";
	}

	/**
	 * Begin the download
	 */
	public void begin()
	{
		_running = true;
		if (_progress == null) {
			_progress = new ProgressDialog(_parentFrame, getNameKey());
		}
		_progress.show();
		// start new thread for time-consuming part
		new Thread(this).start();
	}

	/**
	 * Run method using separate thread
	 */
	public void run()
	{
		// Compile list of tiles to get
		ArrayList<SrtmTile> tileList = new ArrayList<SrtmTile>();

		// First, loop to see which tiles are needed
		DoubleRange lonRange = _app.getTrackInfo().getTrack().getLonRange();
		DoubleRange latRange = _app.getTrackInfo().getTrack().getLatRange();
		final int minLon = (int) Math.floor(lonRange.getMinimum());
		final int maxLon = (int) Math.floor(lonRange.getMaximum());
		final int minLat = (int) Math.floor(latRange.getMinimum());
		final int maxLat = (int) Math.floor(latRange.getMaximum());

		for (int lon=minLon; lon<= maxLon; lon++)
		{
			for (int lat=minLat; lat <= maxLat; lat++)
			{
				SrtmTile tile = new SrtmTile(lat, lon);
				boolean alreadyGot = false;
				for (int t = 0; t < tileList.size(); t++)
				{
					if (tileList.get(t).equals(tile)) {
						alreadyGot = true;
					}
				}
				if (!alreadyGot) {tileList.add(tile);}
			}
		}

		downloadTiles(tileList);
		// Finished
		_running = false;
	}


	/**
	 * Download the tiles of SRTM data
	 * @param inTileList list of tiles to get
	 */
	private void downloadTiles(ArrayList<SrtmTile> inTileList)
	{
		// Update progress bar
		if (_progress != null)
		{
			_progress.setMaximum(inTileList.size());
			_progress.setValue(0);
		}

		String errorMessage = null;

		// Check the cache is ok
		final String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
		if (diskCachePath != null)
		{
			File srtmDir = new File(diskCachePath, "srtm");
			if (!srtmDir.exists() && !srtmDir.mkdir()) {
				// can't create the srtm directory
				errorMessage = I18nManager.getText("error.downloadsrtm.nocache");
			}
		}
		else {
			// no cache set up
			errorMessage = I18nManager.getText("error.downloadsrtm.nocache");
		}

		// Get urls for each tile
		URL[] urls = TileFinder.getUrls(inTileList);
		int numDownloaded = 0;
		for (int t=0; t<inTileList.size() && !_progress.isCancelled(); t++)
		{
			if (urls[t] != null)
			{
				// Define streams
				FileOutputStream outStream = null;
				InputStream inStream = null;
				try
				{
					// Set progress
					_progress.setValue(t);
					// See if we've already got this tile or not
					File outputFile = getFileToWrite(urls[t]);
					if (outputFile != null)
					{
						// System.out.println("Download: Need to download: " + urls[t]);
						outStream = new FileOutputStream(outputFile);
						URLConnection conn = urls[t].openConnection();
						conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
						inStream = conn.getInputStream();
						// Copy all the bytes to the file
						int c;
						while ((c = inStream.read()) != -1)
						{
							outStream.write(c);
						}

						numDownloaded++;
					}
					// else System.out.println("Don't need to download: " + urls[t].getFile());
				}
				catch (IOException ioe) {errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
				}
				// Make sure streams are closed
				try {inStream.close();} catch (Exception e) {}
				try {outStream.close();} catch (Exception e) {}
			}
		}

		_progress.dispose();
		if (_progress.isCancelled()) {
			return;
		}

		if (errorMessage != null) {
			_app.showErrorMessageNoLookup(getNameKey(), errorMessage);
		}
		else if (numDownloaded == 1)
		{
			JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm.1", numDownloaded),
				I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
		}
		else if (numDownloaded > 1)
		{
			JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm", numDownloaded),
				I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
		}
		else if (inTileList.size() > 0) {
			_app.showErrorMessage(getNameKey(), "confirm.downloadsrtm.none");
		}
	}

	/**
	 * See whether the SRTM file is already available locally
	 * @param inUrl URL for online resource
	 * @return file object to write to, or null if already there
	 */
	private static File getFileToWrite(URL inUrl)
	{
		String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
		if (diskCachePath != null)
		{
			File srtmDir = new File(diskCachePath, "srtm");
			if (srtmDir.exists() && srtmDir.isDirectory() && srtmDir.canRead())
			{
				File srtmFile = new File(srtmDir, new File(inUrl.getFile()).getName());
				if (!srtmFile.exists() || !srtmFile.canRead() || srtmFile.length() <= 1) {
					return srtmFile;
				}
			}
		}
		return null;
	}

	/**
	 * @return true if a thread is currently running
	 */
	public boolean isRunning()
	{
		return _running;
	}
}
