/**
 * $Workfile: atUI.js $
 * $Revision: 14 $
 *  $Modtime: 25/02/10 9:13 $
 *   $Author: Peter.goulborn $ 
 * Class: Astun.JS.UI
 * Container for UI classes and functions.  
 */
if( !Prototype ) throw new Error( 'Prototype library not found' );  // Needs to be nicer, possibly iSharemaps-wide library error?

if( !Astun ) {
	var Astun = {};
}
if( !Astun.JS ) {
	Astun.JS = {};
}
if( !Astun.JS.UI ) {
	Astun.JS.UI = {};
}

Astun.JS.UI.Panel = Class.create( 
	{
	/**
		* Constructor: Astun.JS.UI.Panel
		* Create a new iShareMaps panel with header-content-footer structure.
		* Example: 
		*		<div class="atPanel">
		*			<div class="atPanelHeader">
		*				<h3>Panel header</h3>
		*			</div>
		*			<div class="atPanelContent"></div>
		*			<div class="atPanelFooter"></div>
		*		</div>
		* Parameters:
		* options - {object} container for:
		*		title - {string} header text for panel
		*		relative - {string | HTMLElement} element relative to which 
		*			this panel will be inserted.
		*		position - {string} position relative to parent( if specified )
		*			allowed: 'top', 'bottom', 'before' or 'after'.
		*			See: http://www.prototypejs.org/api/element/insert
		*		names - {object} classes and IDs of various elements in the panel.
		*				If absent no additional classes or ids will be added.
		*		names.panel.classes - {array}
		*		names.panel.id - {string}
		*		names.header.classes - {array}
		*		names.header.id - {string}
		*		names.content.classes - {array}
		*		names.content.id - {string}
		*		names.footer.classes - {array}
		*		names.footer.id - {string}
		* 
		* Returns:
		* new instance of class.
		*/
		'initialize': function( options ) {
			var panelType = this.CLASS.replace( /Astun\.JS\.UI\./, 'at' ).replace( /\./, '-' ).camelize();
			var childElements = [ 'header', 'content', 'footer' ] ;
			var addNames = function( element, id, classes ) {
				if( !!classes ) {
					if( classes instanceof Array )
					{
						while( classes.length ) {
							element.addClassName( classes.shift() );
						}
					}
				}
				if( !!id ) {
					if( typeof( id ) === 'string' ) {
						element.id = id;
					}
				}
				
			}
			this.elements = $A();
			this.elements.main = new Element( 'div');
			this.elements.main.addClassName( 'atPanel' );
			
			this.elements.main.addClassName( panelType );
						
			if( !!options && !!options.names && !!options.names.panel ) {
			    if( !options.names.panel.id ) {
				    options.names.panel.id = 'atPanel' +  Math.random().toString().substring( 3, 8 );
				}
				addNames( this.elements.main, options.names.panel.id, options.names.panel.classes );
			}
						
			for( var i = 0; i < childElements.length; i++ ) {
				var type = childElements[ i ];
				var newElement = new Element( 'div' );
				newElement.addClassName( ( 'at-panel-' + type ).camelize() );
				if( !!options && !!options.names && !!options.names[ type ] ) {
					addNames( newElement, options.names[ type ].id, options.names[ type ].classes );
				}
				this.elements[ type ]  = newElement;
				this.elements.main.insert( newElement );
			}
			
			this.elements.title = new Element( 'h3' );
			this.elements.header.insert( this.elements.title );
			
			if( !!options ) {
				if( !!options.title ) {
					this.elements.title.update( options.title );
				}
				if( !!options.relative ) {
					var position = {};
					position[ options.position || 'bottom' ] = this.elements.main;
					$( options.relative ).insert( position );
				}
			}
			
		}, 
		'appendTo': function( parent ) {	
		   /**
			* Function: appendTo
			* Appends the panel to another Element
			* 
			* Parameters:
			* parent - { string | HTMLElement } append panel to this element
			* 
			* Returns:
			* { HTMLElement } the panel object
			*/
			$( parent ).insert( this.elements.main );
			return this;
			
		}, 
		'hide': function(){		
		   /**
			* Function: hide
			* Hides the panel
			*
			*/	
			this.elements.main.hide();
		}, 
		'show': function(){	
		   /**
			* Function: show
			* Shows the panel
			*
			*/	
			this.elements.main.show();
		}, 
		'CLASS' : 'Astun.JS.UI.Panel'
	}
 );


Astun.JS.UI.Panel.ContentSwitcher = Class.create( 
	Astun.JS.UI.Panel, 
	{
   /**
	* Constructor: Astun.JS.UI.Panel.ContentSwitcher
	* Create { Astun.JS.UI.Panel } with switchable content.
	* Example: 
	*		<div class="atPanel atPanelContentSwitcher">
	*			<div class="atPanelHeader">
	*				<h3>Panel header</h3>
	*			</div>
	*			<div class="atPanelContent">
	*				<dl>
	*					<dt>[ label ]</dt>
	*					<dd>[ text ]</dd>
	*					...
	*           </div>
	*			<div class="atPanelFooter"></div>
	*		</div>
	* Parameters: 
	* options - see { Astun.JS.UI.Panel }
	* 
	* Returns:
	* { HTMLElement | boolean } - Returns the inserted element or false if 
	* creation failed.
	*/
		'initialize': function( $super, options ) {
	
			$super( options );
			
			/* Private properties */
			var names = [ ];
			var labels = {};
			var contents = {};
			var current = null;
			var contentlist = new Element( 'dl' );
			this.elements.content.update( contentlist );
			
			var select = function( name ) {
				//basically placeholder in case want to allow custom select function 
				var element = contents[ name ]
				labels[ name ].addClassName( 'atSelected' );
				return element.show();
			}
			
			var deselect = function( name ) {
				//basically placeholder in case want to allow custom deselect function
				var element = contents[ name ]
				labels[ name ].removeClassName( 'atSelected' );
				return element.hide();
			}
			
			var updateClasses = function () {
			   /**
				* Function: updateClasses
				* Sets utility classes on items.
				*
				* Parameters: none
				*/	
				var upperBound = names.length - 1;
				
				for( var i = 0; i < names.length; i++ ) {					
					var label = labels[ names[ i ] ]; 
					var content = contents[ names[ i ] ]; 
					
					if( label.hasClassName( 'atFirst' ) ) {
						if( i !== 0 ) {
							label.removeClassName( 'atFirst' );
						}
					}
					else if (i === 0 ) {
						label.addClassName( 'atFirst' );
					}
					
					if( content.hasClassName( 'atFirst' ) ) {
						if( i !== 0 ) {
							label.removeClassName( 'atFirst' );
						}
					}
					else if (i === 0 ) {
						content.addClassName( 'atFirst' );
					}
					
					if( label.hasClassName( 'atLast' ) ) {
						if( i !== upperBound ) {
							label.removeClassName( 'atLast' );
						}
					}
					else if (i === upperBound ) {
						label.addClassName( 'atLast' );
					}
					
					if( label.hasClassName( 'atFirst' ) ) {
						if( i !== upperBound ) {
							label.removeClassName( 'atLast' );
						}
					}
					else if (i === upperBound ) {
						label.addClassName( 'atLast' );
					}
				}
			
			}
			
			/* Methods with access to private functions and properties */
			
			this.addItem = function( name, label, content ) {	
			   /**
				* Function: addItem
				* Adds some content with label to the panel.
				*
				* Parameters: 
				* name - { string } Unique identifier for item to add
				* label - { string | HTMLElement} This will be the identifier 
				*         for the content and used as the clickable item to 
				*         show the content.
				* content - { string | HTMLElement } HTML content to be shown.
				*/	
				if( label.blank() ||( names.length && names.indexOf( names ) !== -1 ) ) {
					return; // Can't add content with no name or with name that's already used.
				}
				names.push( name );
				
				var identifier = this.elements.main.id + '_' + name;
				var anchor = new Element( 'a', { 'name': identifier } ).update( label );
				anchor.id = identifier;
						
				var labelElement = new Element( 'dt' ).update( anchor );
				var contentElement = new Element( 'dd' ).update( content );
				
				labels[ name ] = labelElement;
				contents[ name ] = contentElement;				
				deselect( name );
				
				if( !current ) {
					current = name;
					this.switchTo( name );
				}
				
				var labelClick = function( evt ) {
					try {
						this.switchTo( evt.element().name.split( '_' ).pop() );
					}
					finally {
						Event.stop( evt );
					}
				}
				
				Event.observe( anchor, 'click', labelClick.bindAsEventListener( this ) );
				contentlist.insert( labelElement ).insert( contentElement );
				updateClasses();
			}
			
			this.removeItem = function( name ) {	
			   /**
				* Function: addItem
				* Adds some content with label to the panel.
				*
				* Parameters: 
				* label - { string } This will be the identifier for the content and 
				*         used as the clickable item to show the content.
				* content - { string | HTMLElement } HTML content to be shown.
				*/
				var i = names.indexOf( name );
				if( i === -1 ) {
					return; // Can't find name
				}
				names.splice( i, 1 );
				
				labels[ name ].remove();
				delete labels[ name ];
				
				contents[ name ].remove();
				delete contents[ name ];
				
				if( current === name && names.length ) {
					this.switchTo( names[ 0 ] );
				}
				updateClasses();
				
			}
			
			this.switchTo = function( name ) {
				if( current ) {
					deselect( current );
				}	
				select( name );
				current = name;
			}
			
			
		}, 
		'CLASS' : 'Astun.JS.UI.Panel.ContentSwitcher'
	}
 );


Astun.JS.UI.Panel.FindAddress = Class.create( 
	Astun.JS.UI.Panel, 
	{
   /**
	* Constructor: Astun.JS.UI.Panel.FindAddress
	* Create { Astun.JS.UI.Panel } with address search and selector.
	*
	* Parameters: 
	* options - see { Astun.JS.UI.Panel }
	* eventElement - { HTMLElement } the element on which to fire and check for 
	*		address	search events.  E.g. the mapElement property of an
	*		Astun.iShareMaps.OLMap control.
	* listSize = { Integer } how many results listed per page.
	*
	* Returns:
	* new instance of class.
	*/
		/*'initialize': function( $super, eventElement, listSize, options ) {
			options.title = options.title || 'Find address';
			listSize = listSize || 10;
			
			
			$super( options );
			
			var fieldname = 'atTxtSearch';
			var inputField;
			var goButton;
			var resultsList;
			var resultsNav;
			var resultsClear;
			var findPage = 0;
			var searchString;
			
			this.elements.content.update( 
				new Element( 'form', { 'method': 'get', 'action': 'atFindAddress.aspx' } ).update( 
						inputField = new Element( 'input', { 'type': 'text', 'id': fieldname, 'name': fieldname } ) 
					).insert(
						goButton = new Element( 'input', { 'type': 'submit', 'value': 'Go' } )
					)
			);
			
			this.elements.content.insert( 
				this.elements.results = new Element( 'div')
			);
			
			var goFindAddress = function( ) {
				searchString = inputField.value;
				eventElement.fire( 'astun:findAddress', { 'searchString': searchString, 'limit': listSize, 'offset': findPage * listSize } );
			}
			
			var writeResults = function( evt ) {
				var results = evt.memo.results;
				var countFirst = evt.memo.offset + 1;
				var countLast = evt.memo.offset + evt.memo.limit;
				if( resultsNav ) {
					resultsNav.update('');
				}
				( resultsList ) ? this.elements.results.update( resultsList.update('') ) : this.elements.results.insert( resultsList = new Element ( 'ol' ) );
				resultsList.setAttribute( 'start', countFirst );
				if( results.name === 'FindAddress' ) {
					var count = results.data.length;
					var addresses = results.data;
					for( var j = 0; j < results.columns.length; j++ ) {
						switch( results.columns[ j ] ) {
							case 'DisplayName': 
								var iName = j;
								break;
							case 'UniqueId': 
								var iUID = j;
								break;
							case 'X': 
								var iX = j;
								break;
							case 'Y': 
								var iY = j;
								break;
							default:
								break;
						}
					}
					
					for( var i = 0; i < count; ++i ) {
						var addressItem;
						var addressLink;
						resultsList.insert( 
							addressItem = new Element( 'li' ).update( 
								addressLink = new Element( 'a', { 'href': '#address' + i } ).update(
									addresses[i][iName] 
								)
							) 
						);
						Event.observe( addressLink, 'click', function( evt ) {
							var i = evt.element().href.split('#address')[1] - 0;
							Event.stop( evt );
							eventElement.fire( 'astun:setAddress', {
								'address': addresses[i][iName],
								'uid': addresses[i][iUID],
								'x': addresses[i][iX],
								'y': addresses[i][iY]								
							} );
							return false;
						}.bindAsEventListener( this ) );
					}
				}
				if( countFirst > 1 || evt.memo.more ) {
					this.elements.results.insert( resultsNav = new Element( 'ul' ) );		
					if( countFirst > 1) {
						var prevNav;
						resultsNav.insert( 
							prevNav = new Element( 'li' ).update( 
								new Element( 'a', { 'href': 'atFindAddress.aspx?searchString=' + searchString + '&amp;page=' + ( findPage - 1 ) } ).update( '< previous' ) 
							)
						);
						prevNav.addClassName( 'atResultsNavBackWard' );
						Event.observe( prevNav, 'click', function( evt ) {
							--findPage;
							goFindAddress( evt );
							Event.stop( evt );
						}.bindAsEventListener( this )  );
						
					}		
					if( evt.memo.more ) {
						var nextNav;
						resultsNav.insert( 
							nextNav = new Element( 'li' ).update( 
								new Element( 'a', { 'href': 'atFindAddress.aspx?searchString=' + searchString + '&amp;page=' + ( findPage + 1 ) } ).update( 'next >' ) 
							)
						);
						nextNav.addClassName( 'atResultsNavForward' );
						Event.observe( nextNav, 'click', function( evt ) {
							++findPage;
							goFindAddress( evt );
							Event.stop( evt );
						}.bindAsEventListener( this )  );
						
					}
				}
				var clearLink;
				this.elements.results.insert( resultsClear = new Element( 'p' ).update( clearLink = new Element( 'a', { 'href': '#' } ).update( 'Clear results' ) ) );
				
				Event.observe( clearLink, 'click', function( evt ) {
					this.elements.results.update( '' );
					Event.stop( evt );
				}.bindAsEventListener( this )  );
				
			}
						
			Event.observe( eventElement, 'astun:addressesFound', writeResults.bindAsEventListener( this ) );
			Event.observe( eventElement, 'astun:addressesNotFound', function( evt ) {
				this.elements.results.update(
					new Element( 'p' ).update(
						'No results found.'
					)	
				);
			}.bindAsEventListener( this ) );
			
			Event.observe( goButton, 'click', function( evt ) {
				findPage = 0;
				goFindAddress();
				Event.stop( evt );
			} );
			
			var inputAddress = function ( evt ) {
				var keynum = evt.keyCode || evt.which;
				if ( keynum == 13 ) { 
					Event.stop( evt );
				}
				else {
					clearTimeout( this.inputTimeout );
					this.inputTimeout = setTimeout( function(){
						findPage = 0;
						goFindAddress();				
					}, 250 );
				}
				if( evt.stopPropogation ) {
					evt.stopPropogation();
				}
				else {
					evt.cancelBubble = true;
				}
			}
			
			Event.observe( inputField, 'keydown', inputAddress.bindAsEventListener( this ) );
			//Event.observe( inputField, 'keypress', function( evt ) { Event.stop( evt ) } );
			
		}, 
		'CLASS': 'Astun.JS.UI.Panel.FindAddress'
		*/
	}
 );
 
 
 
Astun.JS.UI.Panel.FaultLayers = Class.create( 
	Astun.JS.UI.Panel, 
	{
   /**
	* Constructor: Astun.JS.UI.Panel.FaultLayers
	* Create { Astun.JS.UI.Panel } with fault layer selector.
	*
	* Parameters: 
	* options - see { Astun.JS.UI.Panel }
	* eventElement - { HTMLElement } the element on which to fire and check for 
	*		address	search events.  E.g. the mapElement property of an
	*		Astun.iShareMaps.OLMap control.
	* 
	* Returns:
	* new instance of class.
	*/
		'initialize': function( $super, eventElement, options ) {		
			
			$super( options );
			Event.observe( eventElement, 'astun:faultlogger_layersupdated', function( evt ) {
				var layers = evt.memo;
				this.setLayers( layers.list, layers.current );
			}.bindAsEventListener( this ) );
			this.eventElement = eventElement;
		},
		'setLayers': function( faults, current ) {
		   /**
			* Function: setLayers
			* Updates the fault layers list and sets up events
			* 
			* Parameters:
			* fault - { Array } list of available layers.
			* 
			* Returns:
			* { HTMLElement } the panel object
			*/
			var list = true;		
			var layers;
			
			if( current.layerName ) {
				this.elements.title.update( 'You are reporting on:' );
			}			
			else {
				this.elements.title.update( 'Select category to report:' );
			}
			
			if( faults.length > 1 ) {
				this.elements.content.update( layers = new Element( 'ul' ) );
			}
			else {
				this.elements.content.update( layers = new Element( 'p' ) );
			}
			
			
			for ( var i=0; i < faults.length;i++ )
			{
				var layer, image, imagelink, name, namelink;
				var faultLayer = faults[i]
				
				if( faults.length > 1 ) {
					layers.insert( layer = new Element( 'li' ) );
				}
				else {
					layer = layers;
				}
				
				
				
				layer.update( image = new Element( 'img', { 'src': faults[i].iconImage } ) );
				layer.insert( name = new Element( 'span' ).update( faults[i].displayName ) );
				if( faultLayer != current ) {
					var href = document.location.toString().replace( /type=.*[&$](.*)/ig, '$1' );
					href += ( href.indexOf('?') > 0 ) ? '&' : '?' ;
					href += 'type=' + faultLayer.layerName;
					layer.insert( imageLink = new Element( 'a', { 'href': href } ) );
					layer.insert( nameLink = new Element( 'a', { 'href': href } ) );
					imageLink.update( image );
					nameLink.update( name );
					
					var setLayer = function( faultLayer, index, evt ) {
						this.eventElement.fire( 'astun:faultlogger_setlayer', { 
							'name':  faultLayer.layerName.replace( ' ', '_' ), 
							'index': index } 
						);
						if( evt ) {
							Event.stop(evt);
						}
					}
						
					Event.observe( imageLink, 'click', setLayer.curry( faultLayer, i ).bindAsEventListener( this ) );					
					Event.observe( nameLink, 'click', setLayer.curry( faultLayer, i ).bindAsEventListener( this ) );
					
				};
				
			}				
		},
		'CLASS': 'Astun.JS.UI.Panel.FaultLayers'
	}
 );
 
