﻿using System.IO;
using System;
using SimpleJSON;
using UnityEngine;
using System.Collections;
using UnityEditor;

public class BingMapDownloader : GISSplatData
{
	public int zoomLevel = 9;
	public string bingMapKey = "";  // Insert your Bing Map key here

	public double eastLongitudeRequired = 180; 
	public double westLongitudeRequired = -180; 
	public double northLatitudeRequired = 90; // 90
	public double southLatitudeRequired = -90; 

	public int bingImageWidth = 256;
	public int bingImageHeight = 256;

	public void GetBingMap()
	{

		// Set the default geo coordinates from the required coordinates
		eastLongitude = eastLongitudeRequired;
		westLongitude = westLongitudeRequired;
		northLatitude = northLatitudeRequired;
		southLatitude = southLatitudeRequired;

		// Grab all tiles until we reach where we want to go
		ArrayList downloadedFilenames = new ArrayList ();
		double startLong = westLongitudeRequired;
		double startLat = northLatitudeRequired;
		int row = 1;
		int column = 1;
		int predictedTotalDownloadMap = 0;
		string assetPath = Path.GetDirectoryName (AssetDatabase.GetAssetPath (this));
		EditorUtility.DisplayProgressBar ("Bing Map Download", "Downloading maps", 0.0f);

		rowCount = 1;
		columnCount = 1;
		try
		{
			while (true)
			{
				string[] urlParts = new string[4];
				// centerPoint/zoomLevel
				urlParts[0] = "http://dev.virtualearth.net/REST/v1/Imagery/Map/Aerial/{0},{1}/{2}?";
				urlParts[1] = "key=" + bingMapKey;
				urlParts[2] = "mapSize={3},{4}";
				urlParts[3] = "format=png";
				string finalURL = String.Join ("&", urlParts);
				finalURL = String.Format (finalURL,
					startLat, startLong,
					zoomLevel,
					bingImageWidth, bingImageHeight);
				
				string filename = String.Format ("{0}/bingmap_{1}_{2}_{3}_{4}.png", assetPath, row, column, zoomLevel, name);
				filename = AssetDatabase.GenerateUniqueAssetPath (filename);

				WWW www = new WWW (finalURL);
				WaitForDownload (www);

				// If it's done but progress is not full. it failed.
				if (www.progress < 1.0f) {
					Debug.LogError ("Downloading from bing map failed.");
					EditorUtility.ClearProgressBar ();
					return;
				}

				File.WriteAllBytes (filename, www.bytes);
				AssetDatabase.ImportAsset (filename);
				downloadedFilenames.Add (filename);

				// Get the meta data				
				finalURL += "&mmd=1";
				www = new WWW (finalURL);
				WaitForDownload (www);

				var result = SimpleJSON.JSON.Parse (www.text);

				var resourceSets = result["resourceSets"];
				var resources = resourceSets[0]["resources"];			
				
				var bbox = resources[0]["bbox"];
				var mapCenter = resources[0]["mapCenter"]["coordinates"];
				double localWestLongitude = bbox[1].AsDouble;
				double localSouthLatitude = bbox[0].AsDouble;
				double localEastLongitude = bbox[3].AsDouble;
				double localNorthLatitude = bbox[2].AsDouble;

				// Update given lat long
				eastLongitude = Math.Max (localEastLongitude, eastLongitude);
				westLongitude = Math.Min (localWestLongitude, westLongitude);
				northLatitude = Math.Max (localNorthLatitude, northLatitude);
				southLatitude = Math.Min (localSouthLatitude, southLatitude);

				// Stop if we have everything
				if (localSouthLatitude < southLatitudeRequired && localEastLongitude > eastLongitudeRequired){
					break;
				}

				if (startLong > eastLongitudeRequired || localEastLongitude > eastLongitudeRequired){
					startLong = westLongitudeRequired;
					if (startLat < southLatitudeRequired || localSouthLatitude < southLatitudeRequired){
						break;
					}
					// If we have all the column image, start a new row
					startLat = mapCenter[0].AsDouble + (localSouthLatitude - localNorthLatitude);
					++row;
					rowCount = Math.Max(rowCount, row);
					column = 1;
				}
				else {
					// Go on with the next column image
					startLong = mapCenter[1].AsDouble + (localEastLongitude - localWestLongitude);
					++column;
					columnCount = Math.Max(columnCount, column);
				}

				// Calculate prediction for progress bar
				if (predictedTotalDownloadMap == 0)
				{
					int predictTotalColumn = (int)Math.Ceiling((eastLongitudeRequired - localWestLongitude) / (localEastLongitude - localWestLongitude));
					int predictTotalRow = (int)Math.Ceiling((southLatitudeRequired - localNorthLatitude) / (localSouthLatitude - localNorthLatitude));
					predictedTotalDownloadMap = predictTotalRow * predictTotalColumn;
				}

				// Progress bar
				EditorUtility.DisplayProgressBar ("Bing Map Download", "Downloading maps", (((row - 1) * columnCount + (column - 1)) / (float)predictedTotalDownloadMap));				
			}
		}
		finally
		{
			EditorUtility.ClearProgressBar ();
		}
		
		
		

		// Store the number of rows and columns we have
		rowCount = Math.Max (rowCount, row);
		columnCount = Math.Max (columnCount, column);

		// Init the texture array
		InitTextureArray ();
		for (int i = 0; i < rowCount; ++i) {
			for (int j = 0; j < columnCount; ++j)	{
				// Load the downloaded file as texture asset
				int index = i * columnCount + j;
				Texture2D tex = AssetDatabase.LoadAssetAtPath (downloadedFilenames[index] as String, typeof(Texture2D)) as Texture2D;
				tex.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
				// textures is a member of GISSplatData with access level protected
				Textures [index] = tex;
			}
		}

		// Since we have the required geo coordinate, use the helper function to calculate offset
		CalculateTextureOffset ((float)eastLongitudeRequired, (float)westLongitudeRequired, (float)northLatitudeRequired, (float)southLatitudeRequired);
	}

	void WaitForDownload (WWW download) 
	{
		while (!download.isDone)
		{
			System.Threading.Thread.Sleep (100);
		}
	}

	[MenuItem ("GIS/Bing Map Splat Asset")]
	static void CreateGISBingMapSplatAsset () 
	{
		BingMapDownloader gisBingMapSplatAsset = ScriptableObject.CreateInstance (typeof (BingMapDownloader)) as BingMapDownloader;
		AssetDatabase.CreateAsset (gisBingMapSplatAsset, AssetDatabase.GenerateUniqueAssetPath ("Assets/BingMapAsset.asset"));
		EditorUtility.FocusProjectWindow ();
		Selection.activeObject = gisBingMapSplatAsset;
	}

}

