
/**
 * @author Peter Goulborn
 *
 * Date: 22/09/08
 * 
 * Class: Astun.iSharemaps.OLNearestPanel
 * User interface to control iShareMaps layers in extended OpenLayers maps.  
 * Instances of this class are created with the <Astun.iSharemaps.OLNearestPanel>
 * constructor.  
 */
if ( !OpenLayers || !Prototype || !Fx ) throw new Error( 'Dependent library not found' );  // Needs to be nicer, possibly iSharemaps-wide library error?

if ( !Astun ) {
	var Astun = {};
}
if ( !Astun.iSharemaps ) {
	Astun.iSharemaps = {};
}
Astun.iSharemaps.OLNearestPanel = Class.create( 
{
/**
     * Constructor: Astun.iSharemaps.OLNearestPanel
     * Create a new iShareMaps layer UI object. This class interacts 
     *     with Astun.iSharemaps.OLLayerControl objects to set the displayed 
     *     layers.
     *
     * Parameters:
     * atolMap : {<Astun.iSharemaps.OLMap>} Astun wrapper object for 
     * OpenLayers map.  The layer panel watches this for a custom 
     * 'astun:sourceLoad' event and then loads the layer information from the 
     * referenced layer control
     */
	initialize: function ( atolMap , element, distances, results ) {	
		this.containerElement = $( element );	
		if ( !this.containerElement ) {
			return false;
		}
		this.mapWrapper = atolMap;
		this.distances = distances || [ '250~250m','500~0.5km','1000~1.0km','2500~2.5km' ];
		this.results = results || [ '2~Two results','5~Five results','10~Ten results','25~Twenty five results','50~Fifty results' ]
		this.layers = $H( {} );
		this.pseudoLayer = {
			'layerName': '',
			'displayName': '',
			'query': {
				'findNearest': {
					'distance': 0,
					'maxResults': 0
				}
			}
		}
		Event.observe( this.mapWrapper.mapElement, 'astun:sourceLoad', this.loadLayers.bindAsEventListener( this ) );
		
	},
	loadLayers: function ( evt ) {	
	
		var loadLayers = {};
		
		this.layerControl = evt.memo.layerControl;
		var parentElement = new Element( 'fieldset', {'id': 'atFindNearestPanel'} );		
		var This = this;
		var layerSelector = Class.create ( 
		{
			initialize: function ( className ) {
				this.layers = $H( {} );
				this.element = new Element( 'select' );
				if ( className ) {
					this.element.addClassName( className );
				}
			},
			addLayer: function ( layerName, displayName ) {
				var option = new Element( 'option', {'value': layerName} ).update( displayName );
				if ( !this.layers.keys( ).length ) {
					option.writeAttribute( {'selected': 'selected'} );
				}
				this.layers.set( layerName, option );
				this.element.insert( option );
				
			},
			removeLayer: function ( layerName ) {
				this.layers.get( layerName ).remove( );
				this.layers.remove( layerName );
			}
		} )
		
		var distanceSelector = Class.create( 
		{
			initialize: function ( distances, className ) {
				/*
				 * distances {String} expected to be array, 
				 * with items of the form '[ distance ]~[ displayText ]'
				 */
				this.element = new Element( 'select' );	
				this.distances = $H( {} );
				while ( distances.length ) {
					var d = distances.shift( ).split( '~' ); 
					this.addDistance( d[ 0 ], d[ 1 ] );
				}
				if ( className ) {
					this.element.addClassName( className );
				}
			},
			addDistance: function( distance, displayText ) {
				var option = new Element( 'option', {'value': distance} ).update( displayText );
				if ( !this.distances.keys( ).length ) {
					option.writeAttribute( {'selected': 'selected'} );
				}
				this.distances.set( distance, option );
				this.element.insert( option );
			},
			removeDistance: function( distance ) {
				this.distances.get( distance ).remove( );
				this.distances.remove( distance );
			}
		} )
		
		
		var resultsSelector = Class.create( 
		{
			initialize: function ( results, className ) {
				/*
				 * results {String} expected to be array, 
				 * with items of the form '[ results ]~[ displayText ]'
				 */
				this.element = new Element( 'select' );
				this.results = $H( {} );
				while ( results.length ) {
					var d = results.shift( ).split( '~' ); 
					this.addResult( d[ 0 ], d[ 1 ] );
				}
				if ( className ) {
					this.element.addClassName( className );
				}		
			},
			addResult: function( result, displayText ) {
				var option = new Element( 'option', {'value': result} ).update( displayText );
				if ( !this.results.keys( ).length ) {
					option.writeAttribute( {'selected': 'selected'} );
				}
				this.results.set( result, option );
				this.element.insert( option );
			},
			removeResult: function( result ) {
				this.results.get( result ).remove( );
				this.results.remove( result );
			}
		} )
		
		var ls = new layerSelector( 'layerList' );
		for ( 
			loadLayers.groupId = 0, loadLayers.groupMax = this.layerControl.layerGroups.length; 
			loadLayers.groupId < loadLayers.groupMax; 
			++loadLayers.groupId 
		) {
			var groupObject = this.layerControl.layerGroups[ loadLayers.groupId ];
			for ( 
				loadLayers.layerId = 0, loadLayers.layerMax = groupObject.activeLayers.length; 
				loadLayers.layerId < loadLayers.layerMax; 
				++loadLayers.layerId 
			) {
				var layerObject = groupObject.activeLayers[ loadLayers.layerId ];
				if ( layerObject.query.findNearest ) {
					ls.addLayer( layerObject.layerName, layerObject.displayName );
				}
			}
		}
		if ( ls.layers.size( ) > 0 ) {
			Event.observe( 
				ls.element, 
				'change', 
				function( ){
					This.pseudoLayer.layerName = ls.element.value;
					This.pseudoLayer.displayName = ls.layers.get( ls.element.value ).innerHTML;
				}
			 );
			var ds = new distanceSelector( this.distances, 'distances' );
			Event.observe( 
				ds.element, 
				'change', 
				function( ){
					This.pseudoLayer.query.findNearest.distance = ds.element.value;
				}
			 );
			var rs = new resultsSelector( this.results, 'resultsCount' );
			Event.observe( 
				rs.element, 
				'change', 
				function( ){
					This.pseudoLayer.query.findNearest.maxResults = rs.element.value;
				}
			 );
			var go = new Element( 'input', {'type': 'submit', 'className': 'atFormInputSubmit', 'value': 'Go'} );
			Event.observe( 
				go, 
				'click', 
				function( evt ){
					This.mapWrapper.mapElement.fire( "astun:layerQuery", {'layer': This.pseudoLayer} );
					Event.stop( evt );
					return false;
				}
			 );
			var reset = new Element( 'p' );
			var resetLink = new Element( 'a', {'href': '#atResetQuery'} );
			reset.id = 'atResetQuery';
			resetLink.update( 'Clear current query results' );
			reset.update( resetLink );
			Event.observe( 
				reset, 
				'click', 
				function( evt ){
					This.mapWrapper.mapElement.fire( "astun:layerQuery", {'reset': true} );
					Event.stop( evt );
					return false;
				}
			 );
			this.pseudoLayer.layerName = ls.element.value;
			this.pseudoLayer.displayName = ls.layers.get( ls.element.value ).innerHTML;
			this.pseudoLayer.query.findNearest.distance = ds.element.value;
			this.pseudoLayer.query.findNearest.maxResults = rs.element.value;
			this.resetText = reset;
			this.resetText.hide( );
			this.containerElement.update( reset ).insert( ls.element ).insert( rs.element ).insert( ds.element ).insert( go );
		} 
		else {
			
			this.containerElement.update( "<p>No layers with Find Nearest settings defined.</p>" );
		}
		
		var setFindNearestLayerEvent= function( evt ) {	
		    if( evt.memo.type === 'findNearest' ) {	
			    this.resetText.show( );
			}
		}
		var resetFindNearestLayerEvent= function( evt ) {	
		    if( evt.memo.type === 'findNearest' ) {	
			    this.resetText.hide( );
			}
		}
		Event.observe( this.mapWrapper.mapElement, 'astun:resultsReceived', setFindNearestLayerEvent.bindAsEventListener( this ) );
		Event.observe( this.mapWrapper.mapElement, 'astun:resultsCleared', resetFindNearestLayerEvent.bindAsEventListener( this ) );
		
		loadLayers = null;
	}
 } );


