///////////////////////////////////////////////
//  Copyright (c) 2008 3TIER-Inc 
//  Author: Clay Teeter
///////////////////////////////////////////////

///////////////////////////////////////////////
//  Initial display variables 
///////////////////////////////////////////////

// bounds
var lat=31;
var latMax= 49;
var lon=-124;
var lonMax=-101;

var maxZoom = 12;
var minZoom = 5;
var minOverviewZoom = 2;

var iconLt25 = 'images/windmill_blue'
var icon25_30 = 'images/windmill_ltgreen'
var icon30_35 = 'images/windmill_yellow'
var icon35_40 = 'images/windmill_orange'
var iconGt40 = 'images/windmill_red'

////////////////////////////////////////////////
//  Script variables 
////////////////////////////////////////////////

var delta = 180.0 / Math.pow(2, 9);
var map; 
var popup;
var grid = {}
var markers;  // the marker layer
var defaultStation;

function round(num, dec){
    return Math.round(num*Math.pow(10, dec))/Math.pow(10,dec)
}

function lonLat2Index(lonlat){
    x_index = Math.floor((lonlat.lon + 180) / delta)
    y_index = Math.floor((lonlat.lat + 90) / delta)
    return {'x': x_index, 'y': y_index }
}

function createPopup(marker){
    // check to see if the popup was hidden by the close box
             // if so, then destroy it before continuing

    if (popup != null) {
	map.removePopup(popup);
	if(popup.marker)
	    markers.removeMarker(popup.marker);
	    
	popup.destroy();
	popup = null;
    }
    if (popup == null) {

	popup = new OpenLayers.Popup.Anchored(marker.id + "_popup", marker.lonlat, new OpenLayers.Size(332, 184), null, marker.icon, true, function () { map.removePopup(popup); popup.destroy(); markers.removeMarker(popup.marker); popup =null});
	popup.marker = marker;
	var content = "<div class='name'>ID " + marker.station_id + ", Loc. " + Math.round(marker.lonlat.lat * 100) / 100 + "N " + -1 * Math.round(marker.lonlat.lon * 100) / 100 + "W, " + "</div><div class='data mean'>Cap. " + round(marker.station_capacity, 1) + "%</div><br>" + 

	    "<div class='container' width='100%' height='100%'>" + 
	    "<table width='100%'>" +
	    "<tr><th width: '10'>power density</th><td width='100'>" + round(marker.station_density, 1) + " W/m2" + 
	    "<th>speed</th><td> " + round(marker.station_speed, 1) + " m/s" + "</td></tr>" + 
	    "<tr><th>power capacity</th><td colspan='3'>" + round(marker.station_capacity,1) + "%" + "</td></tr>" + 
	    "<tr><th>elevation</th><td> " + round(marker.station_elevation, 0) + " m</td>" +
	    "<th>state</th ><td>" + marker.station_state_code + "</td></tr>" + 
	    "<tr><td colspan='4'>" + 
	    "Download dataset: <a class='tooltip' title='Right click to download' href='data/2004/" + marker.station_id + ".csv'> 2004</a> - " + 
	    "<a class='tooltip' title='Right click to download' href='data/2005/" + marker.station_id + ".csv'> 2005</a> - " + 
	    "<a class='tooltip' title='Right click to download' href='data/2006/" + marker.station_id + ".csv'> 2006</a></td></tr>" + 
	    "</table>" + 
	    "</div></div>";

	popup.setContentHTML(content);

	popup.setBackgroundColor("transparent");
	popup.setOpacity(1);
	popup.events.register('mousemove', popup, function (e) {try{e.stopPropagation();}catch(e){}});    
	map.addPopup(popup);

    } else {
	map.removePopup(popup);
	popup.destroy();
	popup = null;
    }
}

function createMarker(data){
    var lonLat = new OpenLayers.LonLat(data.longitude, data.latitude);

    var size = new OpenLayers.Size(21 * 2 ,26 * 2);
    var offset = new OpenLayers.Pixel(-(size.w/2), -size.h/2);
	
    if(parseFloat(data['capacity']) < 25)
        var iconUrl = iconLt25 + ".png";		
    if(parseFloat(data['capacity']) >= 25 && parseFloat(data['capacity']) < 30)
        var iconUrl = icon25_30 + ".png";		
    if(parseFloat(data['capacity']) >= 30 && parseFloat(data['capacity']) < 35)
        var iconUrl = icon30_35 + ".png";		
    if(parseFloat(data['capacity']) >= 35 && parseFloat(data['capacity']) < 40)
        var iconUrl = icon35_40 + ".png";		
    if(parseFloat(data['capacity']) >= 40)
	var iconUrl = iconGt40 + ".png";		

    var icon = new OpenLayers.Icon(iconUrl,size,offset);
    marker = new OpenLayers.Marker(lonLat,icon);

    marker.station_id = data['id'];
    marker.station_density = data['density'];
    marker.station_capacity = data['capacity'];
    marker.station_speed = data['speed'];
    marker.station_state_code = data['state_code'];
    marker.station_elevation = data['elevation'];
	
    marker.events.register('click', marker, markerClick);    
    markers.addMarker(marker);
    return marker;
}

function markerClick(evt) {
    createPopup(evt.object);
    OpenLayers.Event.stop(evt);
} 


function loadJsonPoints(data){
    var y_min = data['y_min'];
    var x_min = data['x_min'];
	
    var x_index = data['x_index'];
    var y_index = data['y_index'];
    
    if(!grid[x_index])
        grid[x_index] = {};

    if(!grid[x_index][y_index])
	grid[x_index][y_index] = data;

    if(defaultStation){
        showPoint(defaultStation, true);
    }

}

function loadMarkersLonLat(x, y){
    var url = "./json/9/" + x.toString() + "/" + y.toString() + ".json";
    jQuery.getJSON(url, loadJsonPoints);
}	


function loadGrid() {
    b = map.getExtent();

    // what markers do we need to load
    bl = new OpenLayers.LonLat(b.left, b.bottom);
    tr = new OpenLayers.LonLat(b.right, b.top); 

    if(map.getZoom() < 9 - minZoom + 1){
	if (popup != null) {
	    map.removePopup(popup);
	    popup.destroy();
	    popup = null;
	}
	for(mi = 0; mi < markers.markers.length; mi ++){
	    var marker = markers.markers[mi];
	    markers.removeMarker(marker);	    
	}
	return;
    }

    // the idea here is to split up the lat lon into chunks and load each chunk.
	
    for( x = Math.floor((bl.lon + 180.0) / delta ); x < Math.ceil((tr.lon + 180.0) / delta) + 1; x ++){
        for( y = Math.floor((bl.lat + 90.0) / delta); y < Math.ceil((tr.lat + 90.0) / delta) + 1; y ++){
	    // ignore this index if it has been loaded before
	    try{
	        test = grid[x][y].data;
		if(defaultStation){
		    showePoint(defaultStation, true);
		    defaultStation = null;
		}
	        continue;
            }catch(e){
	        loadMarkersLonLat(x, y);
	    }

	}
    }

    return true;
	    
}

function mapMove(evt){
    return loadGrid();
}

function mouseMove(evt){
    lonlat = map.getLonLatFromPixel(evt.xy);
    showPoint(lonlat)

}

function showPoint(lonlat, showPopup){
    var g = map.getZoom();
    	
    if(map.getZoom() < 5)
	return;

    var xy = map.getPixelFromLonLat(lonlat);

    // what is the lonlat?
    var index = lonLat2Index(lonlat);

    // is there a datapoint here?
    try{
        test = grid[index['x']][index['y']].data;
    }catch(e){
	return;
    }
    // cycle through looking for a matching point
    // this should never be very long
    for( i = 0; i < grid[index['x']][index['y']].data.length; i ++){
	record = grid[index['x']][index['y']].data[i];
	// here i am going to find out the pixel placement of this xy val
        // if the mouse is within 20 pixels of a marker continue, other wise this i
	// this is just noise
	p = map.getPixelFromLonLat(new OpenLayers.LonLat(record['longitude'], record['latitude']));
	if((p.x - xy.x) > -10 && (p.x - xy.x) < 10)
	    if((p.y - xy.y) > -10 && (p.y - xy.y) < 10){
		defaultStation = null;
	        // is this marker pass the capacity test
	        if(!map.baseLayer.filter(parseFloat(record['capacity'])))
	            return;

	        // does a marker already exist here
		for(mi = 0; mi < markers.markers.length; mi ++){
		    var marker = markers.markers[mi];
  	  	
		    m = map.getPixelFromLonLat(marker.lonlat);
	            if((m.x - xy.x) > -10 && (m.x - xy.x) < 10)
	                if((m.y - xy.y) > -10 && (m.y - xy.y) < 10)
	                    return;
		    if(!popup){
  	                markers.removeMarker(marker);
		    }else{
			if(marker != popup.marker)
			    markers.removeMarker(marker);
		    };
		}
	        // alright, we found a match, create a marker here
	        marker = createMarker(record);
		if(showPopup)
		    createPopup(marker);
	        return;
	    }
    }
    for(mi = 0; mi < markers.markers.length; mi ++){
	marker = markers.markers[mi];
	if(!popup){
	    markers.removeMarker(marker);
	}else{
	    if(marker != popup.marker)
		markers.removeMarker(marker);
	}
    }
}

function isCapacity(lbound, ubound){
    function ret(cap){
	if(lbound && ubound)
            if(cap >= lbound && cap < ubound)
	        return true;
	if(!lbound)
	    if(cap < ubound)
	        return true;
	if(!ubound)
	    if(cap >= lbound)
	        return true;

	return false;
    }

    return ret;
}

//Initialise the 'map' object
function mapInit() {

    mapOptions = {	    
	restrictedExtent: new OpenLayers.Bounds(-125.0, 30, -100.0, 50.0),
	maxResolution:1.40625/Math.pow(2, minZoom),
	minZoom: minZoom,
	numZoomLevels:( maxZoom - minZoom ) }

    map = new OpenLayers.Map ("map", mapOptions);

    map.addControl(new OpenLayers.Control.Navigation());
    map.addControl(new OpenLayers.Control.ScaleLine());
    map.addControl(new OpenLayers.Control.Attribution());

    OpenLayers.Util.onImageLoadErrorColor = "transparent";                

    var layerAll = new OpenLayers.
	Layer.TMS(
		  "All",
		  "cache/tiles/merged/all/",
		  {
		      filter: isCapacity(0, 200), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );

    var layerLT25 = new OpenLayers.
	Layer.TMS(
		  "<img class='trans' src='" + iconLt25 + ".gif' />< 25",
		  "cache/tiles/merged/lt25/",
		  {
		      filter: isCapacity(null, 25), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );


    var layer25_30 = new OpenLayers.
	Layer.TMS(
		  "<img class='trans' src='" + icon25_30 + ".gif' />25 - 30",
		  "cache/tiles/merged/25_30/",
		  {
		      filter: isCapacity(25, 30), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );

    var layer30_35 = new OpenLayers.
	Layer.TMS(
		  "<img class='trans' src='" + icon30_35 + ".gif' />30 - 35",
		  "cache/tiles/merged/30_35/",
		  {
		      filter: isCapacity(30, 35), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );


    var layer35_40 = new OpenLayers.
	Layer.TMS(
		  "<img class='trans' src='" + icon35_40 + ".gif' />35 - 40",
		  "cache/tiles/merged/35_40/",
		  {
		      filter: isCapacity(35, 40), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );

    var layerGT40 = new OpenLayers.
	Layer.TMS(
		  "<img class='trans' src='" + iconGt40 + ".gif' />> 40 ",
		  "cache/tiles/merged/gt40/",
		  {
		      filter: isCapacity(40, null), type: 'png', getURL: getTileURL, isBaseLayer: true, visibility: false, buffer:1
		  }
		  
		  );


    mapOptions['minZoom'] = minOverviewZoom;
    mapOptions['maxResolution'] = 1.40625/Math.pow(2, minOverviewZoom);
    mapOptions['numZoomLevels'] = ( maxZoom - minOverviewZoom);

    var overview = new OpenLayers.Control.OverviewMap({
	minRatio: 8,
	maxRatio: 256,
	mapOptions: mapOptions});

    map.addControl(overview);				


    var layerSwitcher = new OpenLayers.Control.ThreetierLayerSwitcher();
    map.addControl(layerSwitcher);

    layerSwitcher.maximizeControl(null);
    map.events.register("moveend", map, mapMove);
    map.events.register("mousemove", map, mouseMove); 


    var options = {
	'displayInLayerSwitcher': false
    }

    markers = new OpenLayers.Layer.Markers( markers, {'displayInLayerSwitcher': false } );

    map.addLayers([layerAll, layerLT25, layer25_30, layer30_35, layer35_40, layerGT40, markers])

    map.zoomToMaxExtent();
    overview.maximizeControl(null);

    
    setTimeout(loadGrid, 0);
}

function generateStationLongLat(id){
    ret = function loadStationLongLat(data){
	var myid = id;
	var latitude = data[id]['latitude'];
	var longitude = data[id]['longitude'];
	var point = new OpenLayers.LonLat(longitude, latitude);
	map.setCenter (point, 9 - minZoom + 1);
	defaultStation = new OpenLayers.LonLat(longitude, latitude);
	loadGrid();
    }
    return ret;
}

function gotoStation(){
    var val = $("#station-id-input").val();
    if(!(val.match(/^\d+$/))){
	alert("Please enter a valid station id");
	return;
    }
    var id = parseFloat($("#station-id-input").val());

    // all avaiable stations
    if(id > 32043 || id < 1){
	alert("Please enter a valid station id");
	return;
    }

    // ok all looking good.  We need to switch to the "all capacity" layer
    var g = map.getLayersByName("All")[0];
    map.setBaseLayer(g);

    var file_id = Math.floor(id / 10);
    jQuery.getJSON("json/ids/" + file_id + ".json", generateStationLongLat(id));
};

function getTileURL(bounds) {
    var res = this.map.getResolution();
    var x = Math.round((bounds.left - this.maxExtent.left) / (res * this.tileSize.w));
    var y = Math.round((this.maxExtent.top - bounds.top) / (res * this.tileSize.h));
    var z = this.map.getZoom() + this.map.minZoom - 1;
    var limit = Math.pow(2, z);
    if (y < 0 || y >= limit) {
	return OpenLayers.Util.getImagesLocation() + "404.png";
    } else {
	x = ((x % limit) + limit) % limit;
	return this.url + z + "/" + x + "/" + y + "." + this.type;
    }
}


