/**
 * Requires Prototype, jQuery
 * Creator: Peter.goulborn
 * $Revision: 23 $
 * $Author: Peter.goulborn $ 
 * 
 * This file creates an Astun Technology map object.
 */
 
Astun.JS.Map = function ( elementId, options ) {
	var init = {};
	init.options = options || {};
	
	var pageUnload = function() {
		astun = null;
		Astun = null;
	}

	Event.observe( window, 'unload', pageUnload );

	//Remove Initial Loader
	jQuery('#atInitialLoader').remove();

	if( !window.astun ) {
		window.astun = {};
	}
	window.astun.settings = {
		themeName : options.themeName || 'base'
	};
	
	if( !init.mymaps ) {
		init.mymaps = {};
	}
	
	var mapDiv = $( elementId ),
		$mapDiv = jQuery('#'+elementId );
    var loader = {};

	
	//Base Map Switcher
	if(jQuery.fn.basemapswitcher) $mapDiv.basemapswitcher();
	
	init.queryHandler = new Astun.JS.Common.QueryHandler({
        'showPagePanels': 'panels',
        'showMapPanel': 'showLayers'
    });
    init.stateManager = new Astun.iSharemaps.StateManager( document.body );
	init.mapSettings = Astun.iSharemaps.myNeighbourhood.getSettings();	
		

	init.mapOptions = {scales:init.mapSettings.mapScales};
	init.mapRaster = {};
	init.mapRaster.bbox = init.mapSettings.bounds;
	init.mapRaster.url = init.mapSettings.rasterUrl;
	init.mapRaster.type = init.mapSettings.rasterType;
	init.mapRaster.options = init.mapSettings.rasterOptions;
	init.forceMapSource = init.options.mapSource;

    var mapElement = $(init.mapSettings.elements.map || 'map');
    //alert('mapElement:' + !!mapElement);
    var mapOverlay = new Element('div', {
        'id': 'atMapOverlay'
    });
    var mapTimer = new Element('img', {
        'id': 'atMapTimer',
        'src': 'images/stopwatch.gif'
    });

    mapOverlay.update(mapTimer);
    mapOverlay.hide();
    mapOverlay.setStyle({
        'zIndex': '800',
        'height': '36px',
        'width': '36px',
        'backgroundColor': '#fff',
        'position': 'absolute',
        'top': 0,
        'right': 0,
        'border': '1px solid #aaa'
    });
    mapTimer.setStyle({
        'zIndex': '1',
        'position': 'relative',
        'height': '32px',
        'width': '26px',
        'margin': '2px 5px'
    });
    //mapOverlay.insert(new Element('div', {'style': 'opacity: 0.6; background-color: #fff; width: 100%; height: 100%; '}));
    mapElement.insert({
        'bottom': mapOverlay
    });
	
	if(jQuery)
	{
		var $mapElement	= jQuery('#'+mapElement.id),
			$mapLoader	= jQuery('<div></div>')
							.addClass('ui-state-default')
							.attr('id','atMapLoader')
							.width(75)
							.css({
								'background'	: '#fff',
								'position'		: 'absolute',
								'z-index'		: '800',
								'text-align'	: 'center',
								'padding'		: 10,
								'border-width'	: 5,
								'left'			: (parseInt($mapElement.offset().left,10)+(parseInt($mapElement.width(),10)/2)-(75/2)),
								'top'			: (parseInt($mapElement.offset().top,10)+(parseInt($mapElement.height(),10)/2)-80),
								'-moz-border-radius'	:15,
								'-webkit-border-radius'	:15,
								'box-shadow'		: '5px 5px 3px #818181',
								'-webkit-box-shadow': '5px 5px 3px #818181',
								'-moz-box-shadow'	: '5px 5px 3px #818181'
							})
							.append(
								jQuery('<img/>')
									.attr({'src':'images/stopwatch.gif', 'id':'atMapTimer'})
								,
								jQuery('<span></span>')
									.html('<br /><span id="atLoaderText" style="display:block; padding-top:7px">Loading...</span>')
							)
							.hide()
							.appendTo(jQuery('body'));
			//If mapElement change its width or height, reposition the loader
			$mapElement.bind('repositionLoader',function(){
				//setTimeout(function(){ 
					/*
					Problem with IE6 Discovered by Peter (17 Dec 2009)
					On the follow code the while setting the left position of the mapLoader, IE6 triggers window.resize event for no reason.
					For a fix we check the height and width of the window before and after the it trigger the event and if its not changed,
					than Dont do anything.
					For solution/details please search 'winWidth' string in jquery.panelswrapper file.
					
					window.oldHeight = jQuery(window).height();  
					jQuery(window).resize(function(){ document.title = "window resized" + Date() + " -- " + (window.oldHeight == jQuery(window).height()); });*/
					$mapLoader.css({
						'left' : ($mapElement.offset().left+($mapElement.width()/2)-($mapLoader.width()/2))-parseInt(jQuery('body').offset().left,10),
						'top'  : ($mapElement.offset().top+($mapElement.height()/2)-80)
					});
				//},100);
			});
			

			var winWidth = jQuery(window).width(),
				winHeight = jQuery(window).height(),
				resizeTimeout = 0;
			
			jQuery(window).resize(function(){
				onResize = function() {
					$mapElement.trigger('repositionLoader');
				}
				
				var winNewWidth = jQuery(window).width(),
					winNewHeight = jQuery(window).height();
				if(winWidth!=winNewWidth || winHeight!=winNewHeight)
				{
					//onResize();
					window.clearTimeout(resizeTimeout);
					resizeTimeout = window.setTimeout(onResize, 10);
				}
				//Update the width and height
				winWidth = winNewWidth;
				winHeight = winNewHeight;
			});
	}//End of if(jQuery)
	
	var showLoader = function(evt)
						{
							$mapLoader.show();
						},
		hideLoader = function(evt)
						{
							$mapLoader.hide();
							//debug('Completed');
						};

    mapElement
		.observe('astun:layerStart', showLoader)
		.observe('astun:dataLoadBegin', showLoader);
    mapElement
		.observe('astun:layerEnd', hideLoader)
		.observe('astun:dataLoadComplete', hideLoader);


    init.mapCallbacks = {
        'click': function(e) {
            this.map.wrapper.mapElement.fire('astun:mapClick', {
                mapEvent: e
            });
        },
        'hoverPause': function(e) {
            this.map.wrapper.mapElement.fire('astun:mapHover', {
            mapEvent: e
            });
        },
        'hoverMove': function(e) {
            /*clearTimeout(this.map.wrapper.timers.hover);*/
        }
    };

    init.mapStateManager = new Astun.iSharemaps.StateManager(mapElement);
    var mapWrapper = new Astun.iSharemaps.OLMap(
		mapElement, 
		init.mapSettings.ismUrl, 
		{
			callbacks: init.mapCallbacks, 
			themeName: init.options.themeName
		},
		init.mapSettings.dataUrl);
    



    mapWrapper.interactions = new Astun.iSharemaps.OLInteractCtrl();
    

    init.layerControl = new Astun.iSharemaps.OLLayerControl(
		mapWrapper, 
		null, 
		{
			'forceThematic': init.mapSettings.forceThematic,
			'layers': init.options.layers
		}
	);


    init.mapSourceLoad = function(evt) {
        // astun:mapSourceLoad returns current mapSource as evt.memo
        var mapSource = mapWrapper.mapSource = evt.memo;        
        mapWrapper.baseMapSource = mapSource.defaultBaseMap;
        var loadOptions = {
            data: {}
        };
        if( init.options.view ) {
			loadOptions.initialView = init.options.view;
        }
        var loadMap = function() {
            var loadCurrentLocation = function(locationSetting) {
                var checkLocationChange = function(previousSetting) {
                    // Load previous setting

                    var local = {};
                    local.fn = {};
                    
					local.getDataService = new Astun.JS.GetData.JSONRequester( 
						mapWrapper.dataurl,
						'callback'
					);

                    if (locationSetting) {
                        local.currentLocation = locationSetting.evalJSON();
                    }
                    if (previousSetting) {
                        local.previousLocation = previousSetting.evalJSON();
                    }
		    
					local.previousArea = ( local.previousLocation && local.previousLocation.areaid ) ? local.previousLocation.areaid : '';
		    
                    //Initialise location object                            
                    this.currentLocation = {};

                    local.fn.load = function() {
						// Draw map, load map source   
						var $eventElement = jQuery( '#' + mapWrapper.mapElement.id );  
						var loadBaseMap = function( baseMapName ) {
							var loadInitialBase = function( evt, baseMapSource, type ) {
								if( type === 'raster'){
									mapWrapper.loadMap(baseMapSource, evt.data.dataMapSource, evt.data.loadOptions);					
									jQuery(evt.target).unbind( 'mapSourceLoaded', arguments.callee );
								}
								
							}  
							
							$eventElement.bind(
								'mapSourceLoaded', 
								{
									'dataMapSource': mapSource,
									'loadOptions': loadOptions
								},
								loadInitialBase
							);
							
							var name = mapSource.defaultBaseMap;
							if( baseMapName ) {
								for( var i = 0; i < mapSource.baseMaps.length; i++ ){
									if( mapSource.baseMaps[i] === baseMapName ) {
										name = baseMapName;
										break;
									}
								}
							}

							$eventElement.trigger('loadMapSource', [ name, 'raster']);
						}
						setTimeout(function() { mapWrapper.mapElement.fire('astun:loadSetting', {setting: 'baseMap', loadFunction: loadBaseMap})}, 0);
					}
					
                    // Is location set?
                    if (local.currentLocation && local.currentLocation.uid && local.currentLocation.uid !== -1) {
                        this.currentLocation = local.currentLocation;
                        this.currentPosition = new OpenLayers.LonLat(this.currentLocation.x, this.currentLocation.y);
                        local.validLocation = true;
                    }

                    // Is areaid set?
                    if( $('txtAreaId') ) {
						this.currentLocation.areaid = local.currentArea = $('txtAreaId').value;
					}
                    // Has area changed?
                    local.newArea = (local.currentArea && local.currentArea !== local.previousArea );
					if( local.currentArea && local.newArea ) {
						var parameters = {
							'RequestType': 'XSL',
							'ds': 'NeighbourhoodsGeoJSON',
							'xsl': 'xml\\atStripped.xsl',
							'params': local.currentArea,
							'axuid': new Date( ).valueOf( )
						}
						
						local.fn.zoomToArea = function( json ) {
							if( json.FeatureCollection ) {
								var func = {};
								func.results = json;
								local.fn.load();									
								func.geoJSON = ( new OpenLayers.Format.GeoJSON ).read( func.results );
								func.featureBounds = func.geoJSON[0].geometry.getBounds();
								mapWrapper.map.zoomToExtent(func.featureBounds.scale(1.4), true); 
							}
							else {						
								alert( 'Error: Area search results in wrong geometry format.' ); 
							}		
						}
						
						/* JSONP retrieval of JSON */
						parameters.service = 'DataFunc';
						this.getDataService.request(
							parameters,
							local.fn.zoomToArea
						);
				        
										
						func = null;
						
					}
					else {
						// If same areaid, has location changed?
						if ( local.validLocation && ( !local.previousLocation || this.currentLocation.uid !== local.previousLocation.uid ) ) {
							local.newLocation = true;
							// If location changed set start position to current location if intial view not being forced further up the stack	
							if (!loadOptions.forceInitial && loadOptions.initialViewType != 'supplied') {
								loadOptions.initialView = { 'easting': this.currentLocation.x, 'northing': this.currentLocation.y, 'zoom': this.locationZoom };
								loadOptions.initialViewType = 'supplied';
							}
						}
						local.fn.load();
					}
					if (local.newArea || local.newLocation) {
						mapWrapper.mapElement.fire('astun:saveSetting', { setting: 'previousLocation', value: Object.toJSON(mapWrapper.currentLocation) });
					}	
                }
                this.mapElement.fire('astun:loadSetting', { setting: 'previousLocation', loadFunction: checkLocationChange.bind(this) });


            }
            setTimeout(function() { mapWrapper.mapElement.fire('astun:loadSetting', { setting: 'currentLocation', loadFunction: loadCurrentLocation.bind(mapWrapper) }) }, 0);
			
			Event.observe( mapWrapper.mapElement, 'astun:mapLoaded', function( evt ) {
				init.layerControl.importLayerGroups( evt.memo || mapSource );
			} );						
        };
        // Handle parameters
        mapWrapper.queryHandler = new Astun.JS.Common.QueryHandler({
            'StartEasting': 'x',
            'StartNorthing': 'y',
            'StartZoom': 'z',
            'SearchLayer': 'sl',
            'SearchField': 'sf',
            'SearchValue': 'sv',
            'ServiceAction': 'sa',
            'Address': 'a',
            'UPRN': 'u'
        });

        var setInitialView = function(viewArray) {
            loadOptions.initialView = {
                'easting': viewArray[0],
                'northing': viewArray[1],
                'zoom': viewArray[2]
            }
            loadOptions.forceInitial = true;
        }

        mapWrapper.queryHandler.addCase(
					'zoom',
					'StartEasting, StartNorthing, StartZoom',
					function(values) {
					    // set initial view according to passed in parameters
					    setInitialView([values.starteasting, values.startnorthing, values.startzoom]);
					    loadMap();
					}
				);

        mapWrapper.queryHandler.addCase(
					'searchLayer',
					'SearchLayer, SearchField, SearchValue',
					function(values) {
					    // perform search on data layer and load map with appropriate view
					    var setLocationView = function( response, type, queryOptions ) {
							if( response.unexpectedResponse ) {
								// do something in addition to loading map?
							}
							else {
								var featureCollectionArray = response;
								var featureCol = featureCollectionArray[ 0 ];	
								
								var mapBounds = new OpenLayers.Bounds();
								
								var features = featureCol.features.slice();
								while ( features.length ) {
													
									var feature = features.shift( ); 

									var lonLat = new OpenLayers.LonLat( feature.geometry.coordinates[ 0 ][ 0 ],feature.geometry.coordinates[ 0 ][ 1 ] );
									// if third coordinate different then dealing with bounding box, extend to that too
									if( ( feature.geometry.coordinates[ 0 ][ 0 ] !== feature.geometry.coordinates[ 2 ][ 0 ] ) ||( feature.geometry.coordinates[ 0 ][ 1 ] !== feature.geometry.coordinates[ 2 ][ 1 ] ) ) {
										var topRight = new OpenLayers.LonLat( feature.geometry.coordinates[ 2 ][ 0 ],feature.geometry.coordinates[ 2 ][ 1 ] );
										var featureBounds = new OpenLayers.Bounds( );
										featureBounds.extend( lonLat );
										featureBounds.extend( topRight );
										featureBounds = featureBounds.scale( 2.0 ); // some padding around boundary as fudge to try and make sure appropriate zoom level is used
										lonLat = featureBounds.getCenterLonLat( );

									}
									mapBounds.extend(lonLat);
								}
								var boundsWidth = mapBounds.getWidth( ) ;
								var boundsHeight = mapBounds.getHeight();
								var zoom = ( boundsWidth > boundsHeight ) ? boundsWidth : boundsHeight; // make sure zoom level includes all of feature, should work so long as image width  isnt more than twice its height
										
								var viewCentre = mapBounds.getCenterLonLat();
								var view = {'easting': viewCentre.lon, 'northing': viewCentre.lat, 'zoom': zoom}
								if (view) {
									setInitialView([view.easting, view.northing, view.zoom]);
									loadOptions.data.defaultLayers = [values.searchlayer];
									loadOptions.data.defaultFilter = '^layername=' + values.searchlayer + '^qstr=' + values.searchvalue + '^';
								}
								if (init.layerControl.thematicInfo) {
									init.layerControl.thematicInfo.force = 'off';
								}
					        }
					        jQuery('#' + mapWrapper.mapElement.id ).bind('mapLoaded',[response, type, queryOptions],function(evt){mapWrapper.showResults( evt.data[0], evt.data[1], evt.data[2] )});
					        loadMap();
					    }
					    mapWrapper.searchISMLayer(values.searchlayer, values.searchfield, values.searchvalue, setLocationView);
					}
				);

        if (mapWrapper.queryHandler.cases.matched) {
            mapWrapper.queryHandler.processFirstCase();
        }
        else {
            // load map normally
            loadMap();
        }



    };

    Event.observe(mapWrapper.mapElement, 'astun:mapSourceLoad', init.mapSourceLoad);
	
	if(init.forceMapSource)
	{
    	init.msm = new Astun.iSharemaps.MapSourceManager(init.mapSettings.dataUrl, mapElement , init.forceMapSource);
	}
	else
	{
		init.msm = new Astun.iSharemaps.MapSourceManager(init.mapSettings.dataUrl, mapElement);
	}

    options.click = options.click || 'none';
    switch (options.click) {
		case 'infopanel':
			var clickFunc = mapWrapper.interactions.onInfoClick;
			break;
		case 'tooltip':
			var clickFunc = mapWrapper.interactions.showMapToolTip;
			break;
		default: 
			// do nothing
			var clickFunc = function( evt ){};
    }
    options.hover = options.hover || 'tooltip';
    switch (options.hover) {
		case 'tooltip':
			var hoverFunc = mapWrapper.interactions.showMapToolTip;
			break;
		default: 
			// do nothing
			var hoverFunc = function( evt ){};
    }
    
    Event.observe(mapWrapper.mapElement, 'astun:mapClick', function( evt ) {
		clickFunc.bind(this)( evt );
		
	}.bindAsEventListener(mapWrapper));
	
    Event.observe(mapWrapper.mapElement, 'astun:mapHover', function( evt ) {
		hoverFunc.bind(this)( evt );
		
	}.bindAsEventListener(mapWrapper));	
	
    Event.observe(mapWrapper.mapElement, 'astun:layerQuery', mapWrapper.interactions.findNearest.bindAsEventListener(mapWrapper));

    Event.observe(mapWrapper.mapElement, 'astun:resultsReceived', function(e) {
		if(typeof astun.intranetApp!='undefined')
		{
			//Too make sure its info or selection tools results
			if(typeof e.memo.queryOptions!='undefined')
			{
				//Intranet - 'astun:resultsReady' look for jQuery.infobox plugin for this event
				$mapElement.trigger('astun:resultsReady',[e.memo.json, e.memo.queryOptions]);
			}
		}
		else
		{
			if (jQuery('#atPanelResults').length>0)
			{
				//If content panel hidden, show it
				if(!jQuery('#atResultsSwitcher').is(':visible')) jQuery('#atInfoBoxOpenClose').trigger('click');
				jQuery('#atPanelResults').show();
				$('atResults').update(e.memo.html);
	
				//Styling
				jQuery('#atResults fieldset, #atResults legend').css({'padding':5, 'margin':3}).addClass('ui-corner-all ui-state-default');
				jQuery('#atResults fieldset').css('background','#fff');
				jQuery('#atResults legend').prepend(jQuery('<span/>').addClass('ui-icon ui-icon-carat-1-e').css('float','left'));
				if(!jQuery.browser.msie) jQuery('#atResults .contentDisplay').width('99%');
	
				//Animate the Resultbox so that user can see something happened there
				if(!jQuery('#atResults, .infoResult').is(':animated')) jQuery('.infoResult').addClass('ui-state-default ui-corner-all').css({'background':'#fff', 'padding-left':5}).add('#atResults').effect('highlight', {}, 3000);
			}
		}
    });
    Event.observe(mapWrapper.mapElement, 'astun:resultsCleared', function(e) {
		if(jQuery('#atPanelResults').length>0) {
			jQuery('#atPanelResults').hide();
            $('atResults').update('');
        }
    });
    //alert('mapWrapper: ' + !!mapWrapper);
    return mapWrapper;
}

