/******************************************************************************
 *                                                                            *
 *  Copyright (C) 2008-2010 Alexander Barth <barth.alexander@gmail.com>.      *
 *                                                                            *
 *  This program is free software: you can redistribute it and/or modify      *
 *  it under the terms of the GNU Affero General Public License as published  *
 *  by the Free Software Foundation, either version 3 of the License, or      *
 *  (at your option) any later version.                                       *
 *                                                                            *
 *  This program is distributed in the hope that it will be useful,           *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 *  GNU Affero General Public License for more details.                       *
 *                                                                            *
 *  You should have received a copy of the GNU Affero General Public License  *
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
 *                                                                            *
 ******************************************************************************/

// HorizontalSection extends anim class

HorizontalSection.prototype = new anim();
HorizontalSection.prototype.constructor = HorizontalSection;

function HorizontalSection() {
    anim.call(this,
	      "map",
	      document.getElementById('map_colorbars')
	      );

    this.downloadFormats.push('application/vnd.google-earth.kmz');

    this.wms_url = "Python/web/wms?";

    // theme is null because it will be include in the html page
    // this allows to override some style elements
    this.map = new OpenLayers.Map('map', {tileSize: new OpenLayers.Size(512,512),
					  theme: null} );

    // fix zoom level or not
    this.zoom = true;

    // progressbar instance for loading tiles
    this.progressbar = new MapProgressbar("progressbar",this.map);


    /*    var resolutions = [1.40625,0.703125,0.45,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.00137329101,0.0007346938775510204];*/

    var resolutions = [1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.00137329101,0.0007346938775510204];

    this.bm = new OpenLayers.Layer.WMS( "NASA Blue marble",
					"Python/web/bluemarble?", 
					{layers: 'BMNG', format: 'image/png', 
					 exceptions: 'application/vnd.ogc.se_blank'},
					{isBaseLayer: true,
					 resolutions: resolutions,
					 buffer: 0 });


    this.ol_wms = new OpenLayers.Layer.WMS("Continents",baselayer_url, 
					   {layers: baselayer_name, 
					    format: baselayer_format,
					    exceptions: 'application/vnd.ogc.se_xml'},
					   {resolutions: resolutions});

    this.map.addLayers([this.bm, this.ol_wms]);
    this.map.addControl(new OpenLayers.Control.LayerSwitcher());
    this.map.addControl(new OpenLayers.Control.CustomNavToolbar(this));

    this.map.zoomToMaxExtent();

    var obj = this;

    var style = OpenLayers.Util.applyDefaults({strokeWidth: 2, strokeColor: "black"}, 
					      OpenLayers.Feature.Vector.style["default"]);

    var control = new OpenLayers.Control();
    OpenLayers.Util.extend(control, {
	    draw: function () {
		// this Handler.Box will intercept the shift-mousedown
		// before Control.MouseDefault gets to see it
		this.box = new OpenLayers.Handler.Box( control,
						       {"done": this.notice}
						       ,{keyMask: OpenLayers.Handler.MOD_SHIFT}
						       );
		this.box.activate();
	    },

		notice: function (bounds) {
		var ll = this.map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.left, bounds.bottom)); 
		var ur = this.map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.right, bounds.top)); 

		/*
		  alert(ll.lon.toFixed(4) + ", " + 
		  ll.lat.toFixed(4) + ", " + 
		  ur.lon.toFixed(4) + ", " + 
		  ur.lat.toFixed(4));
		*/

		console.log(ll.lon,ur.lon,ll.lat,ur.lat);
	    }
	});



    this.map.addControl(control);

    // botton to change zoom level to include all layers
    var panel = new OpenLayers.Control.Panel();
    var button = new OpenLayers.Control.Button({displayClass: "ZoomAllLayersVisible", 
						title: 'Change zoom to include all layers',
						trigger: function() { 
		obj.map.zoomToExtent(obj.get_bounds());
	    }
	});
    panel.addControls([button]);
    this.map.addControl(panel);
}

HorizontalSection.prototype.addLayer = function(Layer) {
    anim.prototype.addLayer.call(this,Layer);
    var id = Layer.id;    
    var obj = this;


    // query depth dimension and add to dialog if appropriate

    var depths = Layer.get_dimension('elevation');

    if (depths.range.length > 0) {
	this.figprops[id].set_dimension('elevation','depth',depths);
    }

    // query time dimension and add to dialog if appropriate

    var time = Layer.get_dimension('time');

    if (time.range.length > 0) {	
	this.figprops[id].set_dimension('time','time',time);
	
	this.Layers[id].anim = new AnimLayer(
					     this.figprops[id].button_anim,
					     this.figprops[id].dimensions['time'].sel,
					     this,id);
    }


    if (Layer.WMS_extensions == 'box-select' || Layer.WMS_extensions == 'box-select-wfs' ) {
	console.log('Layer.ext',Layer.WMS_extensions);

	var style = OpenLayers.Util.applyDefaults({strokeWidth: 2, strokeColor: "green"}, 
						  OpenLayers.Feature.Vector.style["default"]);

	this.Layers[id].vectors = new OpenLayers.Layer.Vector("Vector Layer", {style: style});
	this.map.addLayer(this.Layers[id].vectors);
	this.Layers[id].vectors.setZIndex(this.map.Z_INDEX_BASE.Feature);
	//control = new OpenLayers.Control.DrawFeature(this.vectors,OpenLayers.Handler.Box, {handlerOptions: {style: style}});

	this.Layers[id].control = new OpenLayers.Control();
	var control = this.Layers[id].control;
	var layer = this.Layers[id];
	layer.download_url = null;
	layer.selected_region = null;

	OpenLayers.Util.extend(this.Layers[id].control, {
	    draw: function () {
		// this Handler.Box will intercept the shift-mousedown
		// before Control.MouseDefault gets to see it
		this.box = new OpenLayers.Handler.Box( layer.control,
						       {"done": this.notice}
						       //,{keyMask: OpenLayers.Handler.MOD_SHIFT}
						       );
		//this.box.activate();
	    },

	    notice: function (bounds) {
		var ll = this.map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.left, bounds.bottom)); 
		var ur = this.map.getLonLatFromPixel(new OpenLayers.Pixel(bounds.right, bounds.top)); 
		layer.vectors.destroyFeatures();

		console.log(ll.lon,ur.lon,ll.lat,ur.lat);

		var bounds2 = new OpenLayers.Bounds(ll.lon,ll.lat,ur.lon,ur.lat);
		var box = new OpenLayers.Feature.Vector(bounds2.toGeometry());
		layer.vectors.addFeatures(box);

		layer.selected_region = {ll: ll, ur: ur};

		//window.open(layer.download_url,'Data Download');
	    }
	});


	this.map.addControl(this.Layers[id].control);

	// activate or not the select box feature
	var element = this.figprops[id].box_select;
	element.onclick = function(element) {
	    return function() {	
		if (element.checked) {
		    layer.control.box.activate();
		}
		else {
		    layer.control.box.deactivate();
		}
	    };
	}(element);


	if (Layer.WMS_extensions == 'box-select') {
	    this.figprops[id].download_callback = function() {
		if (layer.selected_region) {
		    var ll = layer.selected_region.ll;
		    var ur = layer.selected_region.ur;
		    
		    var step='005' + ll.lon + '|'  + ur.lat + '|'  + ur.lon + '|'  + ll.lat;		
		    layer.download_url = 'http://emodnet-chemistry.maris2.nl/v_cdi_v2/browse_step.asp?step=' + step;
		    console.log('url',layer.download_url);

		    window.open(layer.download_url,'Download');
		}
		else {
		    alert('Please select a domain first.');
		}
	    };
	}

	if (Layer.WMS_extensions == 'box-select-wfs' ) {
	    this.figprops[id].button_metadata.onclick = function() {
		if (layer.selected_region) {
		    
		    var ll = layer.selected_region.ll;
		    var ur = layer.selected_region.ur;
		    console.log(ll.lon,ur.lon,ll.lat,ur.lat);		    

		    xsl=Util.loadXMLDoc("http://gher-diva.phys.ulg.ac.be/upload/Alex/Test/feature.xsl");

		    var wfs_url = 'http://geoservice.maris2.nl/wfs/seadatanet/cdi_v2/simorc';		    
		    var params = {
			service: 'WFS',
			version: '1.0.0', 
			request: 'getfeature',
			outputformat: 'gml3',
			typename: layer.name,
			bbox: [ll.lon,ll.lat,ur.lon,ur.lat].join(','),
			//maxfeatures: 10
			maxfeatures: $('#max_wfs_features').val()
		    };

		    document.getElementById("metadata_content").innerHTML = 'Loading ...';

		    var metadata_handle = function(resp) {
			var xml = resp.responseXML;
			var elem = document.getElementById("metadata_content");


			// remove previous results
			if ( elem.hasChildNodes() ) {
			    while ( elem.childNodes.length >= 1 ) {
				elem.removeChild(elem.firstChild);       
			    } 
			}

			document.getElementById("metadata_content").innerHTML = 'A search returns maximum ' + params.maxfeatures + ' hits. This can be changed in "Settings"';

			// add new results
			Util.XSLTransform(xml,xsl,elem);
			$('#metadata_dialog').dialog('open');
		    };

		    new OpenLayers.Request.GET({url: wfs_url, params: params, callback: metadata_handle});

		}
		else {
		    alert('Please select a domain first.');
		}
	    };
	}

    }

    // zoom if the first layer is added (except base layers)
    this.zoom = this.map.getNumLayers() == 2;
};

HorizontalSection.prototype.removeLayer = function(Layer) {
    var id = Layer.id;    

    if (Layer.WMS_extensions == 'box-select' | Layer.WMS_extensions == 'box-select-wfs') {
	this.Layers[id].vectors.destroyFeatures();
	this.map.removeLayer(this.Layers[id].vectors);
	this.map.removeControl(this.Layers[id].control);
    }


    anim.prototype.removeLayer.call(this,Layer);

    this.map.removeLayer(this.analysis_wms[id]);
    delete this.analysis_wms[id];
};


HorizontalSection.prototype.onresize = function() {

};

HorizontalSection.prototype.update = function() {
    var depth;
    var time;
    var obj = this;

    for (var id in this.Layers) {
	if (this.Layers[id].WMS_extensions == 'OceanBrowser') {
	    

	    // query first colorbar-range

            depth = this.figprops[id].get_dimension('elevation');
	    time = this.figprops[id].get_dimension('time');
	
	    // name will be reencoded by OpenLayers
	    var params = {layer: decodeURIComponent(this.Layers[id].name), request: "GetStats"};

	    if (depth !== "") {
		params.elevation = depth;
	    }

	    if (time !== "") {
		params.time = time;
	    }


	    // closure around id
	    var fun = function(id,zoom) {
		return function(xmldoc) { 
		    obj.stat(xmldoc,zoom,id); 
		};
	    }(id,this.zoom);

	    Util.proxy_ajax(this.Layers[id].wms_url,params,null,fun,{proxy: this.Layers[id].use_proxy});
	}
	else {
	    // add layer directly

	    this.stat(null,this.zoom,id);
	}

    }
};

HorizontalSection.prototype.get_layer_param = function(id) {
    //console.log('get_layer_param',id);

    return this.figprops[id].get_layer_param();
};


HorizontalSection.prototype.get_wms_layer = function(id,options) {
    //console.log('get_wms_layer',id);

    var analysis_params = this.figprops[id].get_layer_param();	

    // override by parameters in options
    for (var key in options) {
	analysis_params[key] = options[key];
    }
    
    // id will be reencoded by OpenLayers

    var layer = new OpenLayers.Layer.WMS(this.Layers[id].title,
					 this.Layers[id].wms_url,
                                                {layers: decodeURIComponent(this.Layers[id].name), 
						 styles: analysis_params.style,
						 transparent: "true", 
						 format: "image/png"},
                                                {minResolution: 0.00001,
                                                 maxResolution: 1,
						 buffer: 0 });
	
    layer.mergeNewParams(analysis_params.param);

    return layer;
};




HorizontalSection.prototype.stat = function(xmldoc,zoom,id) {

    //alert('stat ' + id);
    //console.log('stat',id);

    if (xmldoc) {
	var xmin = xmldoc.getElementsByTagName("xmin")[0].firstChild.nodeValue;
	var xmax = xmldoc.getElementsByTagName("xmax")[0].firstChild.nodeValue;
	var ymin = xmldoc.getElementsByTagName("ymin")[0].firstChild.nodeValue;
	var ymax = xmldoc.getElementsByTagName("ymax")[0].firstChild.nodeValue;
	
	this.figprops[id].set_stat(xmldoc);

    }

    if (zoom) {
	var bounds = this.get_bounds();
	this.map.zoomToExtent(bounds);
    }

    if (!(id in this.analysis_wms)) {
	this.analysis_wms[id] = this.get_wms_layer(id);
	this.map.addLayers([this.analysis_wms[id]]);
    }
    else {
	var analysis_params = this.get_layer_param(id);
	this.analysis_wms[id].mergeNewParams(analysis_params.param);
	this.analysis_wms[id].mergeNewParams({styles: analysis_params.style});
	this.analysis_wms[id].redraw();
    }
};

// update_layer is called when style, elevation or time is changed
// it is called when
// - when a layer is added to a map
// - when user clicks on update
// - when FigureProperties window is closed

HorizontalSection.prototype.update_layer = function(id) {

    if (!(id in this.analysis_wms)) {
	this.analysis_wms[id] = this.get_wms_layer(id);
	this.map.addLayers([this.analysis_wms[id]]);
    }
    else {
	var analysis_params = this.get_layer_param(id);
	this.analysis_wms[id].mergeNewParams(analysis_params.param);
	this.analysis_wms[id].mergeNewParams({styles: analysis_params.style});
	this.analysis_wms[id].redraw();
    }

};


// download current view

HorizontalSection.prototype.download = function(id,opt) {
    // same extend as current view

    var lp = this.figprops[id].get_layer_param();
    var extent = this.map.getExtent();

    var bounds = new OpenLayers.Bounds(opt.xmin,opt.ymin,opt.xmax,opt.ymax);

    var layers = decodeURIComponent(this.Layers[id].name);
    var styles = this.figprops[id].get_style();

    var params = 
      {layers: layers,
       request: "GetMap",
       width: opt.width,
       height: opt.height,
       bbox: bounds.toBBOX(),
       transparent: true,
       decorated: true,
       styles: styles,
       format: opt.format
      };

    if (lp.param.elevation !== undefined) {
	params.elevation = lp.param.elevation;
    }

    if (lp.param.time !== undefined) {
	params.time = lp.param.time;
    }

    var url = Util.append_param(this.Layers[id].wms_url,params);
    window.open(url,'Image');    
};


HorizontalSection.prototype.dburl = function (id) {
    return "http://seadatanet.maris2.nl/v_cdi_v2/print_ajax.asp?n_code=" + id.replace('SDN:CDI:','');
};

HorizontalSection.prototype.show_feature_info = function (response,id,latlon,format) {

    function roundr(val,range) {
	digits = Math.ceil(log10(range)+2);
	return Util.round(val,digits);	
    }
    
    console.log('got',id);


    // extract information from response.responseXML and format it

    //var xmldoc = response.responseXML;
    // proxy_ajax returns directly an xmldoc
    var xmldoc = response; 

    if (format == 'text/xml') {
    var val;
    var digits;

    var lon = parseFloat(xmldoc.getElementsByTagName("longitude")[0].firstChild.nodeValue);
    var lat = parseFloat(xmldoc.getElementsByTagName("latitude")[0].firstChild.nodeValue);

    // round lon and lat based on their range
    var e = this.map.getExtent();
    lon = roundr(lon,e.getWidth());
    lat = roundr(lat,e.getHeight());


    var xmlval = xmldoc.getElementsByTagName("value")[0].firstChild;
    if (xmlval) {
	val = parseFloat(xmlval.nodeValue);
	var vmin = parseFloat(this.figprops[id].get_style_param('vmin'));
	var vmax = parseFloat(this.figprops[id].get_style_param('vmax'));

	var range = vmax - vmin;
	val = roundr(val,range);
    }
    else {
	val = "no data"; 
	
    }



    var str = "longitude:" + remove_spurious_decimals(lon) +
              ", latitude:" + remove_spurious_decimals(lat) +
              ", value:" + remove_spurious_decimals(val);

    this.figprops[id].set_info(str);

    }    
    else if (format == 'application/vnd.ogc.gml') {

	var html;
	html  = '<div style="width:350px; height: 140px; overflow: auto">';
	html += '<h5>' + this.Layers[id].title + '</h5>';
	html += '<table class="tableFeatureInfo" border="1" ><tbody>';

	var features = xmldoc.getElementsByTagName('REPHY-EDMODNET_feature');
	if (features.length === 0) {
	    features = xmldoc.getElementsByTagName('feature');

	    if (features.length === 0) {
		return;
	    }
	}

	var item = features[0].firstChild;
	if (!item) {
	    return;
	}


	var tagsname = {'LON': '', 'LAT': '', 'PLATFORM': '', 'IDENT': ''}, title, 
	name, url, time, depth, CDI, CDI_elem, ids, data_elem;

	// regular expression matching for example URL_NO2_d
	var re = /URL_(.*)_D/;
	
	while (item !== null) {
	    if (item.tagName) {
		if (item.tagName in tagsname && item.firstChild) {
		    html += '<tr><td>' + item.tagName + '</td><td>' + item.firstChild.data + '</td></tr>';
		}
		else if (item.tagName == 'DataURL' && item.firstChild) {
		    title = item.getElementsByTagName("Title")[0].firstChild.data;
		    url = item.getElementsByTagName("OnlineResource")[0].getAttribute("href");
		    time = item.getElementsByTagName("time")[0].firstChild.data;
		    depth = item.getElementsByTagName("depth")[0].firstChild.data;

		    time = time.replace(/T00:00:00/g,'');

		    /*html += '<tr><td>' + title + '</td>';
		      html += '<td><a href="' + url + '" target="_blank">Image</a></td></tr>';*/

		    //html += '<tr><td colspan="2"><a href="' + url + '" target="_blank">' + title + '</a></td></tr>';


		    /*html += '<tr><td>' + title + '</td>';
		      html += '<td><a href="' + url + '" target="_blank">' +  time + ' (at ' + depth + ' m)' + '</a></td></tr>';*/

		    html += '<tr><td>parameter</td><td>' + title + '</td></tr>';
		    html += '<tr><td>time</td><td>' + time + '</td></tr>';
		    html += '<tr><td>depth (m)</td><td>' + depth + '</td></tr>';
		    html += '<tr><td>plot</td><td><a href="' + url + '" target="_blank">Image</a></td></tr>';

		    CDI_elem = item.getElementsByTagName("CDI");

		    if (CDI_elem.length > 0) {		    
			CDI = CDI_elem[0].firstChild.data;
			ids = CDI.split(',');

			var CDI_list = ''; 
			for (var i=0; i < ids.length; i++) { 
			    CDI_list += '<a href="' + this.dburl(ids[i]) + '" target="_blank">' + ids[i] + '</a>\n'; 
			}

			html += '<tr><td>CDI metadata</td><td>' + CDI_list + '</td></tr>';
		    }

		    data_elem = item.getElementsByTagName("data");
		    if (data_elem.length > 0) {		    
			html += '<tr><td>data access</td><td><a href="' + data_elem[0].firstChild.data + '" target="_blank">download</a></td></tr>';
		    }

		    html += '<tr><td></td><td></td></tr>';


		}
		else {		
		    var m = re.exec(item.tagName);
			
		    if (m && item.firstChild) {
			html += '<tr><td>' + m[1] + '</td><td><a href="' + item.firstChild.data + '" target="_blank">Image</a></td></tr>';
		    }
		    
		}
	    }
	    item = item.nextSibling;         
	}

	html += '</tbody></table></div>';

	var popup = new OpenLayers.Popup.FramedCloud(
	//new OpenLayers.Popup.AnchoredBubble(
              "FeatureInfo", 
	      latlon,
	      new OpenLayers.Size(350,200),
	      html,
	      null,
	      true);

	this.map.addPopup(popup);
    }
};

