/* 
 * Code for loading data from a WFS server and rendering it on a Google map.
 * Includes specific functionality for HiROC WFS data types.
 *
 * footprints.js,v 1.25 2011/01/06 18:00:44 guym Exp
 */

// base URL for geoserver instance
var URL_GEO = '/geoserver/wfs?request=GetFeature&outputFormat=json';

//base URL for marker icons
var URL_ICO = '/hiwish/include/';

var CTX =
{
	name: 'CTX', 
	wfs: URL_GEO + '&typename=hi:CTX&propertyname=hi:PRODUCT_ID,hi:RATIONALE_DESC,hi:CENTER,hi:FOOTPRINT', 
	ico: URL_ICO + 'mm_20_orange.png', 
	color: '#ff7700', 
	id: 'PRODUCT_ID', 
	text: 'RATIONALE_DESC', 
	box: 'FOOTPRINT',
	blurb: 'From the <a href="http://www.msss.com/mro/ctx/">Context Camera (CTX)</a> on NASA\'s <a href="http://mars.jpl.nasa.gov/mro/">Mars Reconnaissance Orbiter</a>.',
	base: 'http://global-data.mars.asu.edu/ctx/img/'
};

var CRISM =
{
	name: 'CRISM', 
	wfs: URL_GEO + '&typename=hi:CRISM&propertyname=hi:OBSERVATION_ID,hi:COMMENT,hi:PRODUCT_URL,hi:CENTER,hi:FOOTPRINT', 
	ico: URL_ICO + 'mm_20_blue.png', 
	color: '#0030FF', 
	id: 'OBSERVATION_ID', 
	text: 'COMMENT', 
	box: 'FOOTPRINT', 
	url: 'PRODUCT_URL',
	blurb: 'From the <a href="http://crism.jhuapl.edu/">Compact Reconnaissance Imaging Spectrometer for Mars (CRISM)</a> on NASA\'s <a href="http://mars.jpl.nasa.gov/mro/">Mars Reconnaissance Orbiter</a>'
};

var MOC =
{
	name: 'MOC', 
	wfs: URL_GEO + '&typename=hi:MOC&propertyname=hi:PRODUCT_ID,hi:RATIONALE_DESC,hi:CENTER,hi:FOOTPRINT', 
	ico: URL_ICO + 'mm_20_yellow.png', 
	color: '#ffff00', 
	id: 'PRODUCT_ID', 
	text: 'RATIONALE_DESC', 
	box: 'FOOTPRINT',
	blurb: 'From the <a href="http://www.msss.com/mgs/moc/">Mars Orbital Camera (MOC)</a> on  NASA\'s <a href="http://mars.jpl.nasa.gov/mgs/">Mars Global Surveyor</a>.',
	base: 'http://viewer.mars.asu.edu/planetview/inst/moc/'
};

var HiT =
{
	name: 'HiRISE Target', 
	wfs: URL_GEO + '&typename=hi:Suggested_Observations_WFS&propertyname=hi:ID,hi:STL_DESCRIPTION,hi:CENTER,hi:REGION_OF_INTEREST',
	ico: URL_ICO + 'mm_20_white.png', 
	color: '#ffffff', 
	id: 'ID', 
	text: 'STL_DESCRIPTION', 
	box: 'REGION_OF_INTEREST',
	blurb: 'This is a <a href="http://www.uahirise.org/">HiRISE</a> Suggestion footprint.',
	base: 'http://www.uahirise.org/hiwish/view/'
};

var RDR =
{
	name: 'HiRISE Observation', 
	wfs: URL_GEO + '&typename=hi:RDR_Products_WFS&propertyname=hi:OBSERVATION_ID,hi:RATIONALE_DESC,hi:CENTER,hi:FOOTPRINT', 
	ico: URL_ICO + 'mm_20_red.png', 
	color: '#ff0000', 
	id: 'OBSERVATION_ID', 
	text: 'RATIONALE_DESC', 
	box: 'FOOTPRINT',
	blurb: 'From the <a href="http://www.uahirise.org/">High Resolution Imaging Science Experiment (HiRISE)</a> on NASA\'s <a href="http://mars.jpl.nasa.gov/mro/">Mars Reconnaissance Orbiter</a>.',
	base: 'http://www.uahirise.org/'
};

var baseIcon = new GIcon(G_DEFAULT_ICON);
baseIcon.shadow = URL_ICO + 'mm_20_shadow.png';
baseIcon.iconSize = new GSize(12, 20);
baseIcon.shadowSize = new GSize(22, 20);
baseIcon.iconAnchor = new GPoint(9, 20);
baseIcon.infoWindowAnchor = new GPoint(9, 2);

// true if browser has native JSON API
var HAVE_NATIVE_JSON = (this.JSON) ? true : false;

/*
 * Base Footprints object
 */
function Footprints(defs)
{
    this.name = defs.name;
    this.wfsUrl = defs.wfs;
    this.gicon = new GIcon(baseIcon);
    this.gicon.image = defs.ico;
    this.color = defs.color;
    this.idKey = defs.id;
    this.textKey = defs.text;
    this.boxKey = defs.box;
    this.urlKey = defs.url;
    this.link = defs.base;
    this.credit = defs.blurb;
    
    // cache marker overlays, id => GMarker
    this.marks = {};
    
    // cache polygon overlays, id => GPolyLine
    this.polys = {};    
    
    // if true, markers and lines are shown
    this.enabled = true;
    
    // if true, has been updated
    this.updated = false;
}

/**
 * 
 * @return
 */
Footprints.prototype.toString = function()
{
    return this.name;
};

/**
 * Hide the footprint
 * 
 * @param fps
 * @return
 */
Footprints.prototype.hide = function()
{
    this.enabled = false;

    for (var id in this.polys)
    {
        this.polys[id].hide();
    }
    
    for (id in this.marks)
    {
        this.marks[id].hide();
    }    
};

/**
 * Show the footprints
 * 
 * @param fps
 * @return
 */
Footprints.prototype.show = function()
{
    this.enabled = true;
    
    for (var id in this.polys)
    {
        this.polys[id].show();
    }
    
    for (id in this.marks)
    {
        this.marks[id].show();
    }    
};

/**
 * function to load features, calls addFeature for each
 *
 * @param bounds GLatLngBounds
 * @param map GMap2
 */
Footprints.prototype.update = function(bounds, map)
{    
    var leftLongitude = bounds.getSouthWest().lng();
    var rightLongitude = bounds.getNorthEast().lng();
    
    var urls = []; //the queries to the Geoserver to get the footprints and features:
    
    //the box crosses the 180/-180 degree antimeridian, so make two queries, 
    // because geoserver cannot handle a query of the type westLongitude=177, eastLongitude=-177.
    //The 0/360 meridian is not a problem: westLongitude=-5, eastLongitude=5 works fine.
    if (leftLongitude >=0 && rightLongitude <=0)
    {
        var lowerLatitude = bounds.getSouthWest().lat();
        var upperLatitude = bounds.getNorthEast().lat();
        
        //make a request for the left half (positive longitude)
        var  southwest = new GLatLng(lowerLatitude, leftLongitude);      
        var northeast = new GLatLng(upperLatitude, 180); 
        var leftUrl = this.wfsUrl + '&bbox=' + southwest.toUrlValue(13) + ',' + northeast.toUrlValue(13);
        
        //make a request for the right half (negative longitude)
        southwest = new GLatLng(lowerLatitude, -180);                 
        northeast = new GLatLng(upperLatitude, rightLongitude);    
        var rightUrl = this.wfsUrl + '&bbox=' + southwest.toUrlValue(13) + ',' + northeast.toUrlValue(13);
  
        urls.push( leftUrl );
        urls.push( rightUrl );
    }
    else 
    {
        var url = this.wfsUrl + '&bbox=' + bounds.getSouthWest().toUrlValue(3) + ',' + bounds.getNorthEast().toUrlValue(3);
        urls.push(url);
    }

    var self = this;

    // hide those that have gone out of bounds
    for (var id in this.marks)    
    {
        if (bounds.containsLatLng(this.marks[id].getLatLng())) { continue; }
        
        map.removeOverlay(this.marks[id]);
        map.removeOverlay(this.polys[id]);
            
        delete this.marks[id];
        delete this.polys[id];
    }
   
    // iterate through the generated queries 
    //and fetch footprints for new bounds
    for (var j = 0; j < urls.length; j++)
    {
        GDownloadUrl
        (
            urls[j], function(data, response)
            {
                var json;
                
                var have = {};
                
                if (response != 200) throw "Server returned " + response;
                
                if (HAVE_NATIVE_JSON)
                {
                    try 
                    {
                    	json = JSON.parse(data); // faster, better, safer
                    } 
                    catch (ex)
                    {                    	
                    	console.log(ex);
                    }
                }    
                else
                {
                    json = eval('(' + data + ')'); // old standby
                }
                //console.log("Got " + json.features.length + " features for " + self.name);
                for ( var i = 0 ; i < json.features.length ; i++ )
                {
                    var key = json.features[i].geometry.coordinates.toString();
                    
                    // exclude overlying (seasonal/stereo/repeat suggestions)
                    if (have[key]) continue;
                    self.addFeature(map, json.features[i]);
                    have[key] = 1;
                }
            }
            
        );
    }

    this.updated = true;
};

/*
 * base addFeature method
 *
 * @param feature object from JSON
 * @param idKey key for marker ID
 * @param textKey key for marker text
 * @param boxKey key for footprint coordinates
 * @param urlKey key for product URL override
 */
Footprints.prototype.addFeature = function(map, feature)
{       
    var id = feature.properties[this.idKey];

    // skip recreating features already in the map    
    if (this.marks[id]) 
    { 
        return; 
    }
                    
    var coord = feature.geometry.coordinates;
    var gll = new GLatLng(parseFloat(coord[0]),parseFloat(coord[1]));
    
    var mark = new GMarker( gll, { icon : this.gicon, title: id + " " + feature.properties[this.textKey] } );
    mark.type = this.name;
    mark.text = feature.properties[this.textKey];
    mark.product = id;

    if (this.urlKey)
    {
        mark.url = feature.properties[this.urlKey];
    }
    else
    {
        if (typeof id == 'string')
        {
            mark.url = this.link + id.replace(/\//g, '');
        }
        else
        {
            mark.url = this.link + id;
        }  
    }

    mark.parent = this;
    var coords = feature.properties[this.boxKey].coordinates[0];
   
    var latlngs = [];
    
    for ( var i = 0; i < coords.length; i++ )
    {
        latlngs.push( new GLatLng(parseFloat(coords[i][0]), parseFloat(coords[i][1])) );
    }
   
    var poly = new GPolyline( latlngs, this.color, 1, 1, { clickable: false });
   
    map.addOverlay(mark);
    map.addOverlay(poly);
   
    this.marks[id] = mark;
    this.polys[id] = poly;   
};

Footprints.prototype.markerClicked = function(marker)
{    
    var prid = marker.product;
    var head = '';
    
	if (marker.url == '')
	{
		head = this.name + ' ' + prid;
	}
	else
	{
		head = ' <a target="_blank" href="' + marker.url + '">' + this.name + ' ' + prid + '</a>';
	}	
	
	var para = '<blockquote><p>' + marker.text + '</p></blockquote>';
    var foot = '<p>' + this.credit + '</p>';
    
    marker.openInfoWindowHtml('<div class="mark">' + head + para + foot + '</div>');	
};

Footprints.prototype.checkOverlap = function(gll, callback)
{	
	var url = this.wfsUrl + "&CQL_FILTER=INTERSECT(" + this.boxKey + ",POINT(";
	url += gll.lat().toFixed(4) + " ";
	url += gll.lng().toFixed(4) + "))";
		
    GDownloadUrl
    (
        url, function(data, response)
        {            
        	var json;
        	
            if (response != 200) 
            {
            	callback(gll, false);
            }
            
            if (HAVE_NATIVE_JSON)
            {
                json = JSON.parse(data); // faster, better, safer
            }    
            else
            {
                json = eval('(' + data + ')'); // old standby
            }
            
            callback(gll, json.features.length > 0);            
        }        
    );
};

