// Outage Map
var map;
var mapWidth = 578;
var mapHeight = 413;

// Location of the Weather Map (kml file from NOAA = RTX_Radar_Composite_Reflectivity.kml)
var weatherImageLocation = "http://radar.weather.gov/ridge/RadarImg/NCR/RTX_NCR_0.gif";

// Weather Image boundaries from RTX_Radar_Composite_Reflectivity.kml.  GLatLngBounds is sw, ne.
var sw = new GLatLng(42.876772627397, -126.049474723122);
var ne = new GLatLng(48.5429255814986, -119.86821695501);
var weatherImageBoundaries = new GLatLngBounds(sw, ne);

// Weather Overlay
var weatherImageOverlay = new GGroundOverlay(weatherImageLocation, weatherImageBoundaries);

// Weather Legend
var weatherLegendLocation = "/safety_outages/outages/images/legend.gif";

// Weather Legend Overlay
var weatherLegendOverlay = new GScreenOverlay(weatherLegendLocation,
	new GScreenPoint(260, 20, 'pixels', 'pixels'), // screenXY
	new GScreenPoint(0, 0, 'pixels', 'pixels'), // overlayXY
	new GScreenSize(312, 39, 'pixels', 'pixels') // size
	);

// Google servers cache KML/KMZ files by default.
// To make sure we deliver the most recent version, send a random parameter in the querystring for the KML/KMZ file query.
var randomParameter = new Date().getTime();

// Location of PGE's Service Area kml file
var serviceAreaFileLocation = "http://www.portlandgeneral.com/safety_outages/outages/outage_updates/outage_data/PGE_SvcTerritory2.kml?random=" + randomParameter;

// Location of the outages kml file
var outagesFileLocation = "/safety_outages/outages/outage_updates/outage_data/outages.kml?random=" + randomParameter;

// Location of the Current Conditions kml file
var currentConditionsFileLocation = "/safety_outages/outages/outage_updates/outage_data/current_conditions.kml";

// Service Area Overlay
var serviceAreaOverlay = new GGeoXml(serviceAreaFileLocation,
	function()
	{
		// Verify the Service Area has loaded
		if (!serviceAreaOverlay.hasLoaded())
		{
			DisplayError();
		}
	}
);

// Controls
var mapControls = new GLargeMapControl3D();

// Zoom levels
var defaultZoomLevel = 8;
var minZoomLevel = 8; // full map
var maxZoomLevel = 11; // building level
var defaultWeatherZoomLevel = 7;
var minWeatherZoomLevel = 7; // full map
var maxWeatherZoomLevel = 7; // building level

// Center Point of PGE's Service Region
var defaultLatLng = new GLatLng(45.319244, -122.658051)

// Array to hold a reference to the outage markers so that we can interact with them
var markers = [];

// Array to hold a reference to the current conditions markers
var currentConditionMarkers = [];

// Create the Zip Code Search control
function ZipCodeSearchControl()
{
}

// Set the prototype object to a new GControl instance
ZipCodeSearchControl.prototype = new GControl();

// Zip Code Search container
var divZipCodeSearchControl = document.createElement("div");

// Initializes the ZipCodeSearchControl container.  Errors should follow the standard PGE error format.
ZipCodeSearchControl.prototype.initialize = 
	function(map)
	{
		divZipCodeSearchControl.id = "divZipCodeSearchControl";
		divZipCodeSearchControl.style.backgroundColor = "white";
		divZipCodeSearchControl.style.border = "solid 1px black";
		divZipCodeSearchControl.style.fontFamily = "Arial, sans-serif";
		divZipCodeSearchControl.style.fontSize = "12px";
		divZipCodeSearchControl.style.padding = "2px";
		
		var content = 
			"<table style=\"font-size:12px; border-collapse:collapse; white-space:nowrap;\">" +
				"<tr>" +
					"<td></td>" +
					"<td colspan=\"3\"><div id=\"divSearchByZipCodeMessage\" class=\"global_form_field_error\" style=\"display:none;\"></div></td>" + 
				"</tr>" + 
				"<tr>" + 
					"<td>Zip Code: </td>" + 
					"<td>" + 
						"<table style=\"border-collapse:collapse;\">" + 
							"<tr>" + 
								"<td>" + 
									"<img src=\"/Global/Images/errarrow.gif\" id=\"imgErrorArrow\" style=\"border:0px; display:none; height:15px; width:10px; vertical-align:middle;\"/>" + 
								"</td>" + 
								"<td style=\"width:50px;\">" + 
									"<input id=\"txtZipCode\" type=\"text\" style=\"width:50px;\" maxlength=\"5\" onkeypress=\"return HandleZipcodeKeypress(event);\" />" + 
								"</td>" + 
								"<td>" + 
									"<a class=\"global_table_data_highlighted\" href=\"javascript:ShowInfoWindow(document.getElementById('txtZipCode').value);\" style=\"text-decoration:none;\">" + 
										"<img src=\"/Global/Images/arrow_grey.gif\" style=\"border-width:0px;\" />Go" + 
									"</a>" + 
								"</td>" + 
							"</tr>" + 
						"</table>" + 
					"</td>" + 
				"</tr>" +
			"</table>";
			
		// Add the content
		divZipCodeSearchControl.innerHTML = content;
		
		// Append the control to the map
		map.getContainer().appendChild(divZipCodeSearchControl);
		
		return divZipCodeSearchControl;
	}

// Set the position of the Zip Code Search control
ZipCodeSearchControl.prototype.getDefaultPosition = 
	function()
	{
		return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(70, 8));
	}

var zipCodeSearchControl = new ZipCodeSearchControl();

// Function to only allow numeric input characters, and to open the info window on an Enter keypress.
function HandleZipcodeKeypress(event)
{
	var key = event.keyCode ? event.keyCode : event.which; // keyCode for IE, which for FF
	if (key == 13)
	{
		ShowInfoWindow(document.getElementById("txtZipCode").value);
		return false;
	}
	else if (!((key >= 48 && key <= 57) || key == 37 || key == 39 || key == 46 || key == 8 || key == 16)) // 0-9, left-arrow, right-arrow, delete, backspace
	{
		return false;
	}
	return true;
}

// Create the Current Conditions control
function CurrentConditionsControl()
{
}

// Set the prototype object to a new GControl instance
CurrentConditionsControl.prototype = new GControl();

// Current Conditions container
var divCurrentConditionsControl = document.createElement("div");

// Initialize the Current Conditions container.
CurrentConditionsControl.prototype.initialize = 
	function(map)
	{
		try
		{
			divCurrentConditionsControl.id = "divCurrentConditionsControl";
			divCurrentConditionsControl.style.backgroundColor = "white";
			divCurrentConditionsControl.style.border = "solid 1px black";
			divCurrentConditionsControl.style.fontFamily = "Arial, sans-serif";
			divCurrentConditionsControl.style.fontSize = "12px";
			divCurrentConditionsControl.style.padding = "2px";
			divCurrentConditionsControl.style.height = "165px";
			divCurrentConditionsControl.style.width = "130px";
			divCurrentConditionsControl.style.overflow = "auto";
			divCurrentConditionsControl.style.textAlign = "center";
			
			// Build the Current Conditions from the current_conditions.kml file
			var content = 
				"<div style=\"font-weight:bold;\">Current Conditions</div>" + 
				"<hr />" +
				"<div id=\"divCurrentConditionLocations\" style=\"text-align:left;margin-left:20px;\" />";
				
			// Add the content
			divCurrentConditionsControl.innerHTML = content;
			
			// Append the control to the map
			map.getContainer().appendChild(divCurrentConditionsControl);
			
			return divCurrentConditionsControl;
		}
		catch (Error)
		{
			DisplayError();
		}
	}

// Set the position of the Current Conditions control
CurrentConditionsControl.prototype.getDefaultPosition = 
	function()
	{
		return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(8, 30));
	}

var currentConditionsControl = new CurrentConditionsControl();

// Initialze the map
function InitializeOutageMap()
{
	// Verify the browser is compatible with the Google Maps API
	if (GBrowserIsCompatible())
	{
		try
		{
			// Create the Outage Map button, and set the zoom levels
			var outageMap = new GMapType(G_NORMAL_MAP.getTileLayers(), G_NORMAL_MAP.getProjection(), "Outages");
			outageMap.getAlt = function() { return "Go to Outage Map" };
			outageMap.getMinimumResolution = function() { return minZoomLevel };
			outageMap.getMaximumResolution = function() { return maxZoomLevel };
			
			// Create the Weather Map button, and set the zoom levels
			var weatherMap = new GMapType(G_NORMAL_MAP.getTileLayers(), G_NORMAL_MAP.getProjection(), "Weather");
			weatherMap.getAlt = function() { return "Go to Weather Map" };
			weatherMap.getMinimumResolution = function() { return minWeatherZoomLevel };
			weatherMap.getMaximumResolution = function() { return maxWeatherZoomLevel };
			
			// Create the Online Outage Map GSize(width, height)
			map = new GMap2(document.getElementById("divOutageMap"), { mapTypes: [outageMap, weatherMap], size: new GSize(mapWidth, mapHeight) });
			
			// Set the Map's default center location
			map.setCenter(defaultLatLng, defaultZoomLevel);
			
			// Add Map Type Buttons and Scale Control
			map.addControl(new GMapTypeControl());
			map.addControl(new GScaleControl());
			
			// Event handler which fires off when the map buttons are pressed
			GEvent.addListener(map, "maptypechanged",
				function()
				{
					// Clear existing overlays.  
					// Includes the Weather Image, Weather Legend, Service Territory and Outage Markers and Current Conditions Markers.
					map.clearOverlays();
					
					// Display the overlay that is associated with the Map button
					switch (map.getCurrentMapType().getName())
					{
						case weatherMap.getName():
							DisplayWeatherMap();
							break;
						case outageMap.getName():
							DisplayOutageMap();
							break;
						default:
							DisplayOutageMap();
							break;
					}
	            }
	        );
			
			// Show the Outage Map
            DisplayOutageMap();
		}
		catch (Error)
		{
			DisplayError();
		}
	}
	else 
	{
		document.getElementById("divOutageMap").innerHTML = "Sorry, the Google Maps API is not compatible with this browser.";
	}
}

// Loads markers for each Placemark in the outages.kml file
function LoadOutageMarkers()
{
	try
	{
		// Clear the markers array
		markers = [];
		
		// Retrieve the outages from the outages file
		GDownloadUrl(outagesFileLocation, 
		    function(data, responseCode)
		    {
				// Verify the outages file was downloaded
			    if (responseCode == 200)
			    {
				    // Each Placemark in the Outages file represents a zip code outage, and should be placed on the map
				    var xml = GXml.parse(data);
				    var outages = xml.documentElement.getElementsByTagName("Placemark");
				    for (var count = 0; count < outages.length; count++)
				    {
					    var zipCode = outages[count].getElementsByTagName("name")[0].childNodes[0].nodeValue;
					    var infoWindowHTML = outages[count].getElementsByTagName("description")[0].childNodes[0].nodeValue;
					    
					    // Split the coordinates xml attribute by ",".  Format is lon, lat, z
					    var coordinates = outages[count].getElementsByTagName("coordinates")[0].childNodes[0].nodeValue.split(",");
					    var lat = coordinates[1];
					    var lon = coordinates[0];
					    
					    // Create the point for the marker
					    var point = new GLatLng(parseFloat(lat), parseFloat(lon));
					    
					    // Create the zip code outage marker
					    map.addOverlay(CreateOutageMarker(point, zipCode, infoWindowHTML));
				    }
			    }
			    else
			    {
				    DisplayError();
			    }
			}
		);
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Creates an outage marker
function CreateOutageMarker(point, zipCode, infoWindowHTML)
{
	try
	{
		// Create a marker for this Zip code
		var marker = new GMarker(point, { title: zipCode });
		
		// Add a listener to open the info window on a click event
		GEvent.addListener(marker, "click", 
			function()
			{
				// Clear the zip code search box, if the marker clicked has a different zip code
				if (zipCode != document.getElementById("txtZipCode").value)
				{
					document.getElementById("txtZipCode").value = "";
				}
				
				// Open the info window
				marker.openInfoWindowHtml(infoWindowHTML);
			}
		);
		
		// Add marker to the markers array so that they can be accessed directly
		markers[zipCode] = marker;
		
		return marker;
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Loads markers for each Placemark in the current_conditions.kml file
function LoadCurrentConditionMarkers()
{
	try
	{
		// Clear the markers array
		currentConditionMarkers = [];
		
		// Retrieve the current conditions from the current_conditions file
		GDownloadUrl(currentConditionsFileLocation, 
		    function(data, responseCode)
		    {
		    	// Verify the current_conditions file was downloaded
		    	if (responseCode == 200)
		    	{
		    		// Each Placemark in the current_conditions file represents a location and should be loaded
		    		var xml = GXml.parse(data);
		    		var locations = xml.documentElement.getElementsByTagName("Placemark");
		    		for (var count = 0; count < locations.length; count++)
		    		{
		    			var locationName = locations[count].getElementsByTagName("name")[0].childNodes[0].nodeValue;
		    			var infoWindowHTML = locations[count].getElementsByTagName("description")[0].childNodes[0].nodeValue;
		    			
		    			// Split the coordinates xml attribute by ",".  Format is lon, lat, z
		    			var coordinates = locations[count].getElementsByTagName("coordinates")[0].childNodes[0].nodeValue.split(",");
		    			var lat = coordinates[1];
		    			var lon = coordinates[0];
		    			
		    			// Create the point for the marker
		    			var point = new GLatLng(parseFloat(lat), parseFloat(lon));
		    			
		    			// Create the Current Condition marker
		    			map.addOverlay(CreateCurrentConditionMarker(point, locationName, infoWindowHTML));
						
						// Add each location to the Current Conditions div
		    			document.getElementById("divCurrentConditionLocations").innerHTML +=
		    				"<a id='link" + locationName + 
		    				"' class='global_table_data_highlighted' href=\"javascript:ShowCurrentConditionInfoWindow('" + locationName + 
		    				"');\">" + locationName + "</a><br />";
		    		}
		    	}
		    	else
		    	{
		    		DisplayError();
		    	}
		    }
		);
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Creates an invisible Current Condition marker
function CreateCurrentConditionMarker(point, locationName, infoWindowHTML)
{
	try
	{
		// Create a hidden marker for this location
		var marker = new GMarker(point, { title: locationName, hide: true });
		
		// Add a listener to open the info window on a click event
		GEvent.addListener(marker, "click", 
			function()
			{
				// Open the info window
				marker.openInfoWindowHtml(infoWindowHTML);
			}
		);
		
		// Add marker to the markers array so that they can be accessed directly
		currentConditionMarkers[locationName] = marker;
		
		return marker;
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Displays the Outage Map
function DisplayOutageMap()
{
	try
	{
		// Remove the Current Conditions Control
		map.removeControl(currentConditionsControl);
		
		// Add the Map Controls, Zip Code Search Control, Service Area Overlay
		map.addControl(mapControls);
		map.addControl(zipCodeSearchControl);
		map.addOverlay(serviceAreaOverlay);
		
		// Load the Outage Markers
		LoadOutageMarkers();
		
		// Hide the any zip code search errors
		HideSearchError();
		
		// Set focus to the zip code search textbox
		document.getElementById("txtZipCode").focus();
		
		// Set the Map's default center location
		map.setCenter(defaultLatLng, defaultZoomLevel);
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Displays the Weather Map
function DisplayWeatherMap()
{
	try
	{
		// Remove the Map Controls and Zip Code Search Control
		map.removeControl(mapControls);
		map.removeControl(zipCodeSearchControl);
		
		// Add the Current Conditions Control, Weather Image Overlay and Weather Legend Overlay
		map.addControl(currentConditionsControl);
		map.addOverlay(weatherImageOverlay);
		map.addOverlay(weatherLegendOverlay);
		
		// Load the Current Conditions Markers
		LoadCurrentConditionMarkers();
		
		// Set the Map's default center location
		map.setCenter(defaultLatLng, defaultWeatherZoomLevel);
	}
	catch (Error)
	{
		DisplayError();
	}
}

// Opens the info window for a zip code.  Called from the Go button, or an Enter keypress from txtZipCode.
//	Zip code must be entered
//	Zip code must be 5-digits
//	Zip Code must be in the PGE Region
//	Zip code must have marker
function ShowInfoWindow(zipCode)
{
	try
	{
		// Hide the any zip code search errors
		HideSearchError();
		
		// Verify the zip code entered is valid, and open an infoWindow if an outage is found.
		if (document.getElementById("txtZipCode").value == "")
		{
			// Display "no zip code" message
			DisplaySearchError("Please enter a zip code.");
			
		}
		else if (document.getElementById("txtZipCode").value.length < 5)
		{
			// Display "invalid zip code" message
			DisplaySearchError("Zip code must be a 5-digit number.");
		}
		else if (zipcodes[zipCode]) // Check whether the zip code entered is within the PGE Service Area
		{
			// Check whether there is an outage for this zip code
			var zipMarker = markers[zipCode];
			if (zipMarker)
			{
				// Fire the click event for this marker
				GEvent.trigger(zipMarker, "click");
			}
			else
			{
				// Display "no outages found" message
				DisplaySearchError("No outage was found for the zip code entered.");
			}
		}
		else
		{
			// Display "not in service area" message
			DisplaySearchError("Zip code entered is not in PGE's service area.");
		}
	}
	catch (error)
	{
		alert("Unable to load the Outage Information Window.\n");
	}
}

// Opens the InfoWindow for a given location.  Called from clicking on a link in the Current Conditions Control.
function ShowCurrentConditionInfoWindow(id)
{
    try
	{
		var currentCondition = currentConditionMarkers[id];
		if (currentCondition)
		{
			// Fire the click event for this marker
			GEvent.trigger(currentCondition, "click");
			
			// Highlight the link
			HighlightCurrentConditionLink(id);
		}
    }
    catch (Error)
    {
    	alert("Unable to show the Current Condition Information Window.\n");
    }
}

// Set's the currently selected location's color to the hover color
function HighlightCurrentConditionLink(id)
{
	// Reset link colors
	var links = document.getElementById("divCurrentConditionLocations").children;
	for (var count = 0; count < links.length; count++)
	{
		links[count].style.color = "";
	}
	
	// Set the selected color to the "A.global_table_data_highlighted:hover" color
	document.getElementById("link" + id).style.color = "#0288b7";
}

// Display's an error message in the Zip Code Search Control
function DisplaySearchError(message)
{
	document.getElementById("divSearchByZipCodeMessage").innerHTML = message;
	document.getElementById("divSearchByZipCodeMessage").style.display = "block";
	document.getElementById("imgErrorArrow").style.display = "inline";
}

// Hide's the error message in the Zip Code Search Control
function HideSearchError()
{
	document.getElementById("divSearchByZipCodeMessage").innerHTML = "";
	document.getElementById("divSearchByZipCodeMessage").style.display = "none";
	document.getElementById("imgErrorArrow").style.display = "none";
}

// Hides the content div and shows the error div
function DisplayError()
{
	document.getElementById("divContent").style.display = "none";
	document.getElementById("divError").style.display = "block";
}
