/*
	Javascript functionality common to all files
	If adding to this, please bear in mind progressive enhancement 
	- test for functionality before using it to avoid errors
*/

function bookmarkPage(){
	//used by "bookmark page" link in page tools
	 if(window.sidebar){
		 //syntax for FF. 3rd empty string argument is required
		window.sidebar.addPanel(document.title, location.href,'');
	}else{		
		if(window.external){
			//syntax for IE
			window.external.AddFavorite(location.href,document.title);
		}	
	}	
}

function printPage(){
	//used by "print page" link in page tools
	window.print();
}	

function findExitRamps(){
	//identify any links with an exit ramp
	
	aryExtLinks=getElementsByClassName(document,'external');
	/*
		possible HTML is:
		<a class="external"></a>
		<span class="external"><a></a></span>
		<a><span class="external"></span></a>
	*/
	for(i=0;i<aryExtLinks.length;i++){
		switch(aryExtLinks[i].tagName.toLowerCase()){
			case 'span':
				//is this within the link?
				if(aryExtLinks[i].parentNode.tagName.toLowerCase()=='a'){
					operativeElement=aryExtLinks[i].parentNode;
				}else{
					//is it around a link?
					if(aryExtLinks[i].firstChild && aryExtLinks[i].firstChild.tagName && aryExtLinks[i].firstChild.tagName.toLowerCase()=='a'){
						operativeElement=aryExtLinks[i].firstChild;					
					}else{
						//if neither condition is met, class must have been applied in error	
						operativeElement=false;
					}
				}
			break;
			case 'a':
					operativeElement=aryExtLinks[i];
			break;			
			default:
				//class must have been applied in error	
				operativeElement=false;
			break;
		}
		if(operativeElement){
			href=aryExtLinks[i].href;
			aryExtLinks[i].onclick=function(){return showExitWarning(href)};
		}	
	}
}	
	
function showExitWarning(url){
	//shows confirmation message when clicking on external links
	//only do this if exit message is populated
	//this will only be the case where an additional local js file is present. 
	//see defect 268
	if(window.exitMessage){
		if(confirm(exitMessage)){
			return true;
		}else{
			return false;
		}	
	}else{
		//no exit message defined, send user directly to the link
		return true;
	}	
}

var selectBoxSelected=[];
function toggleSelection(selectBox){
	//checks whether the first (default/all) option is selected on the select box passed as selectBox
	//unselects all other options if so
	var unset=false;
	//loop through all options
	if(selectBox){
		for(i=0,j=selectBox.length;i<j;i++){
			if(!selectBoxSelected[i] && selectBox.options[i].selected){
				//this element is the one being selected
				if(i==0){
					//it is the first one, so unset all the others
					unset=true;
				}else{
					//it is not the first one, so unset the first one
					selectBox.options[0].selected=false;
					//record this change
					selectBoxSelected[0]=false;
				}
			}	
			//unset all options if first one is selected
			if(unset && i>0){
				selectBox.options[i].selected=false;
			}
			//record setting of each option in array
			selectBoxSelected[i]=selectBox.options[i].selected;
		}	
	}	
}

function toggleRelatedSelects(){
	//checks whether "this site only" in site select box is selected
	//if so, enables audience and area select boxes
	//if not, disables them
	var siteSelectBox=document.getElementById('rskey');
	var areaSelectBox=getNamedElementId('select','sakey');
	var audienceSelectBox=document.getElementById('saudkey');
	if(siteSelectBox.options[0].selected==true){
		if(areaSelectBox){
			areaSelectBox.disabled=false;
		}
		if(audienceSelectBox){
			audienceSelectBox.disabled=false;
		}
	}else{
		if(areaSelectBox){
			areaSelectBox.disabled=true;
		}
		if(audienceSelectBox){
			audienceSelectBox.disabled=true;
		}		
	}
	return true;
}

function showHelp(){
	//shows or hides the help popup for form field onclick
	//popup also appears on hover - this is for keyboard users
	
	//get a reference to the a tag which was clicked
	el=this;
	//switch off any other help popups
	els=getElementsByClassName(document,'inhelplink');
	already_set=false;
	if(els){
		for(var i=0,j=els.length; i<j; i++){
			//if this popup was on then don't switch it on again
			els[i].className='inhelplink_off';
			elSpans=el.getElementsByTagName('span');
			if(elSpans && elSpans[0]==els[i]){
				already_set=true;
			}
		}
	}
	if(!already_set){
		childEls=el.getElementsByTagName('span');
		if(childEls){
			childEls[0].className='inhelplink';
		}
	}
	//stop link from sending user to top of page
	return false;
}

function prepareHelpLinks(){
	if(document.links){
		linkslist=document.links;
		for(i=0;i<linkslist.length;i++){
			if(linkslist[i].className=='helplink'){
				//add the onclick event
				linkslist[i].onclick=showHelp;
				//remove the class
				linkslistSpan=linkslist[i].getElementsByTagName('span');
				if(linkslistSpan){
					linkslistSpan[0].className='inhelplink_off';
				}
			}
		}
	}
}

function popUpWindow(url,windowName,dependent,height,location,menubar,resizable,screenX,screenY,scrollbars,status,titlebar,toolbar,width){
	//fully-featured popup function
	//pass in 'yes' or 'no' for all arguments except url, windowName, height, screenX, screenY and width
	newWindow=window.open(url,name,'dependent='+dependent+',height='+height+',location='+location+',menubar='+menubar+',resizable='+resizable+',screenX='+screenX+',screenY='+screenY+',scrollbars='+scrollbars+',status='+status+',titlebar='+titlebar+',toolbar='+toolbar+',width='+width);
	return false;
}
							
function getElementsByClassName(node, classname){
	if(node.getElementsByClassName){
		//some browsers now support this
		return node.getElementsByClassName(classname);
	}else{
	    var elsOut = [];
	    var re = new RegExp('(^| )'+classname+'( |$)');
	    var els = node.getElementsByTagName('*');
	    for(var i=0,j=els.length; i<j; i++){
	        if(re.test(els[i].className))elsOut.push(els[i]);
	    }    
	    return elsOut;
	}	    
}

function getNamedElementId(elName,id){	
	//find named element in dom of given type
	//used to avoid conflict between items with same name (IE6 problem). 
	//e.g. sakey on advanced search page
	rtn=false;
	els=document.getElementsByTagName(elName);
	if(els){
		for(i=0,j=els.length;i<j;i++){
			if(els[i].id==id){
				rtn=els[i];
				break;
			}
		}
	}	
	return rtn;
}

function getAttributeCrossBrowser(element,attribute){
	//implemented to deal with IE6's inability to recognise class
	//can also set for if required
	//browser sniffing not used for forwards compatibility
	switch(attribute){
		case 'class':
			out=element.getAttribute('class')?element.getAttribute('class'):element.getAttribute('className');
		break;
		case 'for':
			out=element.getAttribute('for')?element.getAttribute('for'):element.getAttribute('htmlFor');
		break;
		default:
			out=element.getAttribute(attribute);
		break;
	}
	return out;
}

function setAttributeCrossBrowser(element,attribute,value){
	//implemented to deal with IE6's inability to recognise class
	//can also set for if required
	//browser sniffing not used for forwards compatibility
	switch(attribute){
		case 'class':
			element.setAttribute('class',value);
			element.setAttribute('className',value);
		break;
		case 'for':
			element.setAttribute('for',value);
			element.setAttribute('htmlFor',value);
		break;
		default:
			element.setAttribute(attribute,value);
		break;
	}
}

function toggleAttribute(element,attribute,oldValue,newValue){
	//if the old value is present, replace it with the new value
	//otherwise just add the new value
	//could be enhanced to check that oldValue is not a subset of an attribute (e.g. of newValue - visible and invisible are bad choices for values) 
	//will not work if this is the case
	switch(attribute){
		case 'class':
			newClass=newValue;
			//is there already a class attribute?
			currentClass=getAttributeCrossBrowser(element,'class');
			if(currentClass){				
       	    	//is there an old value?
				if(oldValue.length>0 && currentClass.indexOf(oldValue)!==-1){
					//replace it					
					newClass=currentClass.replace(oldValue,newValue);
				}else{
					if(currentClass.indexOf(newValue)==-1){
						//newValue not already in the className	
						//add it						
						newClass=currentClass+' '+newValue;
                	}else{
                		//newValue is already there so keep it as it is
                		newClass=currentClass;
                	}
                }	
			}	
			setAttributeCrossBrowser(element,'class',newClass);
		break;
		default:
			//this isn't finished - doesn't toggle at the moment, just overwrites
			setAttributeCrossBrowser(element,attribute,newValue);
		break;
	}
}

function addPrototypeEffects(){
	if(prototypeAZFunctions && prototypeAZFunctions.hasPrototype()){
		prototypeAZFunctions.addDatePickers();
		prototypeAZFunctions.addTimePickers();
		prototypeAZFunctions.addExitRamps();
		prototypeAZFunctions.addOverlayBackgroundLoader();
		prototypeAZFunctions.addPdfBasket();
		prototypeAZFunctions.applyEvents();
		
		/*$$('.blind').each(function(el){
			el.observe('click',toggleBlinds);
		});

		*/
		/*something like this
		new Effect.Move($('event_details'),{ x: 0, y: 0, mode: 'absolute' });
		replace the X and Y values with Event.pointerX(event);
		see http://www.prototypejs.org/api/event/pointerX
		maybe combine with effect.appear - move it first then make it appear 
		try to make this generic - maybe a class on the link?
		http://wiki.github.com/madrobby/scriptaculous/effect-appear
		
		also have a think about absolutise in prototype
		*/
		
	}	
	
}

var minOpacity = 0.3;
var imageTransitionBefore = 1;

var prototypeAZFunctions = function(){
	//anything here is private
	var default_container_name = 'overlay_container'; 
	
	return{
		
		//anything here is public. Call using prototypeAZFunctions.functionName();
		
		hasPrototype : function(){
			return typeof Prototype !== 'undefined';
		},
		
		addDatePickers : function(){
			$$('.datepicker').each(function(el){
				var picker = new Control.DatePicker(el, {datePicker: true,
					timePicker: false,
					locale: 'en_GB'
				});
			});
		},
		
		addTimePickers : function(){
			$$('.timepicker').each(function(el){
				var picker = new Control.DatePicker(el, {datePicker: false,
					timePicker: true,
					use24hrs:true,
					locale: 'en_GB'
				});
			});
		},
		addPdfBasket : function(){			
			
			var callBacks = [prototypeAZFunctions.addPdfBasket,prototypeAZFunctions.pdfBasket];
			$$('.ajax_pdf_basket').each(function(el){
				//this is the element where the response should be directed
				//replace the existing link with an AJAX request
				el.observe(
						'click',
						//this will add in the passed arguments to the default argument of the event
						//trouble is that the event is the last argument. 
						//Convention is that it is the first  
						prototypeAZFunctions.simpleAjaxUpdater.curry(callBacks)

						
				);
			});	
		},	
		
		addExitRamps : function(){
			var callBacks = [prototypeAZFunctions.exitRamp];
			$$('.exit_ramp').each(function(el){
				//this is the element where the response should be directed 	
				//replace the existing link with an AJAX request
				el.observe('click', prototypeAZFunctions.simpleAjaxUpdater.curry(callBacks)
				);
			});
			
		},	
		addOverlayBackgroundLoader : function(){
			//simply detects the presence of an anchor with ID loadUrl containing a URL
			//and loads it in a div named overlay_background
			//which is created on the fly
			var anchor = $('loadUrl');
			var outerDiv = document.body.firstDescendant();
			if(anchor){
				var url = anchor.href;
				if(url != ''){
					var targetName = 'overlay_background';
					anchor.remove();
					target = new Element('div');
					//native JS method here
					target.setAttribute('id',targetName);
					document.body.insertBefore(target,outerDiv);
					var updater = new Ajax.Updater(target,url,{
						method: 'get',
						parameters: {ajaxRequestFromOverlay:true}, 
						onSuccess: function(){prototypeAZFunctions.fadeOutElement(target);}
					});
				}
			}	
		},
		fadeOutElement : function(el){
			//check whether the body is already faded
			
			var fadedSelector = new Selector('.faded');
			var docBody = document.body;
			if(!fadedSelector.match(docBody)){
				el.fade({duration:0.5, from:1, to:minOpacity});
				docBody.addClassName('faded');
				$$('body div')[0].addClassName('bottomlayer');
			}	
		},		
		fadeOutBackground : function(){
			prototypeAZFunctions.fadeOutElement($$('body div')[0]);
		},
		fadeInBackground : function(){
			document.body.removeClassName('faded');
			var firstDescendant = $$('body div')[0];
			firstDescendant.fade({duration:0.5, from:minOpacity, to:1});
			firstDescendant.removeClassName('bottomlayer');
		},
		hideOverlay : function(el, event, stopEvent){
			if(stopEvent){
				event.stop();
			}	
			//fade out the link, then remove it
			$(default_container_name).fade({duration:1.0, from:1, to:0});
			$(default_container_name).remove();
			prototypeAZFunctions.fadeInBackground();	
		},
		
		exitRamp : function(){
			//make cancel button just empty the overlay
			$$('div[id="' + default_container_name + '"] .cancel').each(function(el){
				el.observe('click',function(event){
					prototypeAZFunctions.hideOverlay(el, event, true);
				});
			});
		},	
		
		simpleAjaxUpdater : function(callBacks, event){
			//event last as a result of use of curry
			//pull the necessary information from the updater
			//this format should be used for all requests which are AJAX enabled
			//first of all, kill the request
			
			if(!event.stopped){
				event.stop();
			}	
			
			var href = prototypeAZFunctions.getEventHref(event);
			//ie is returning undefined here when a stopped event is passed as an argument
			//try with a proxy object instead of an event perhaps?
			
			
			var params = {};
			params['ajaxSource'] = true;//makes webapp believe this is an AJAX request (same syntax as a Spring AJAX request)
			var target;
			if(!$(default_container_name)){
				target = new Element('div');
				//native JS method here
				target.setAttribute('id',default_container_name);
				document.body.appendChild(target);
			}else{
				target = $(default_container_name);
			}
			
			var updater = new Ajax.Updater(target,href,{
				method: 'get',
				parameters: params,
				onSuccess: function(){prototypeAZFunctions.fadeOutBackground();},
				onComplete: function(){
					//TODO refactor this
					for(j=0;j<callBacks.length;j++){
					try{
						//attempt to call the function
						callBacks[j].call();
					}catch(e){}
						//
					}
					//now move to where the overlay has appeared
					target.scrollTo();
				}	
			});
		},
		ajaxTileUpdater : function (event){
			//first of all, kill the request
			event.stop();
			//the link which was clicked
			var anchor = event.findElement('a');

			//its querystring
			var qs = anchor.search;
			//as an associative array
			var qsParams = qs.toQueryParams();
			//the desired action
			//link format
			//?itemId=7038166&action=remove&tileRefresh=true&panelItemId=8408399
			var params = {};
			
			params['tileRefresh'] = true;
			if(qsParams.tileDefinition){
				params['tileDefinition'] = qsParams.tileDefinition;
			}else{	
				params['tileDefinition'] = 'tiles.panel.decorator';
			}
			if(qsParams.panelItemId){
				params['panelItemId'] = qsParams.panelItemId;
			}
			
			params['requestItemKey'] = qsParams.itemId;
			
			//branchItemKey: "${pageHelper.branchItem.itemId}"}
			
			params['ajaxSource'] = true; //to fool app into thinking this is a Spring AJAX request
			//TODO this probably won't work on a branch so work something out here
			params['itemId'] = qsParams.itemId;
			
			//TODO get the other qs params and make sure they are on the request as well. hard-coded for now
			if(qsParams.action){
				params['action'] = qsParams.action;
			}	
			
			//try to get link's parent here? might be easier/more portable
			//target actually needs to be the parent of this panel as it will write the whole of the panel back in.
			//might be better to subclass the updater so it can replace an element rather than just replace its contents
			//this would not work if the parent item contained more than just this panel. I don't think that will happen
			var targetNode;
			if(null != qsParams.panelItemId){
				targetNode = $('panel' + qsParams.panelItemId).parentNode;
			}else{
				//TODO make this work properly
				targetNode = $('media_gallery_item_holder');
			}	
			//in the meantime
			
			var updater = new Ajax.Updater(targetNode,"",{
				onComplete: addPrototypeEffects,
				method: 'get',
				parameters: params
			}
			);
			
		},
		
		pdfBasket : function(){
			//make cancel button just empty the overlay
			$$('div[id="' + default_container_name + '"] .close').each(function(el){
				//6188 production contribution and delivery fix
				el.href = el.href.replace(':7001','');
				el.href = el.href.replace(':80','');
				el.observe('click',function(event){
					//should also refresh to PDF basket panel. How can we do this?
					//at the moment just refreshes whole page. Would be better to refresh panel only						
					prototypeAZFunctions.hideOverlay(el, event, false);
				});
			});
		},	
		applyEvents : function(){
			//find all elements whose ids begin with ajax_panel and enable Prototype AJAX calls
			$$('a[id^=ajax_panel]').each(function(el){
				el.observe('click',prototypeAZFunctions.ajaxTileUpdater);
			});	
			var callBacks = [prototypeAZFunctions.zoomedImage, prototypeAZFunctions.applyEvents];
			
			//find all zoomed media images
			$$('.media_zoom').each(function(el){
				el.observe('click',prototypeAZFunctions.simpleAjaxUpdater.curry(callBacks));
			
			});
			$$('.ajax_media').each(function(el){
				el.observe('click',prototypeAZFunctions.ajaxTileUpdater);
			});
			$$('.ajax_zoomed_media').each(function(el){
				el.observe('click',prototypeAZFunctions.imageTransition.curry(callBacks));
			});
		},
		zoomedImage : function(){
			$$('div[id="' + default_container_name + '"] .close').each(function(el){
				el.observe('click',function(event){
					prototypeAZFunctions.hideOverlay(el, event, true);
				});
			});			
		},
		imageTransition : function(callBacks, event){
			//get the image height
			//stop the link from being followed
			var proxyEvent = {
				proxyEvent: true,
				stopped: true,
				targetHref: prototypeAZFunctions.getEventHref(event)
			};
			event.stop();
			//get the event attributes and pass them through on a proxy object?
			
			
			var target;
			//TODO replace with ids 
			var imgList = $$('#media_overlay img');
			//the amount in PX to add to the image height - needs to be more for an object for some reason
			var difference = 20;
			if(imgList.length != 0){
				//overlay contains an image
				//would be easier to do this with an ID on the object/image
				target = imgList[0];
				
			}else{	
				var objList = $$('#media_overlay object');
				if(objList.length != 0){
					target = objList[0];
				}
				//difference = 50;
			}	
			if(target){
				var elementHeight = target.getHeight();
				console.log(elementHeight);
				//get a reference to the media_overlay div
				var container = $(default_container_name).firstDescendant();
				
				var containerHeight = container.getHeight();
				console.log(containerHeight);
				//var containerWidth = container.getWidth();
				//shrink to size of image
				   // scalars based on change from old to new
				//allow for padding on image... say 30px to allow for the close link
		        var yScale = ((elementHeight + difference) / containerHeight) * 100;
	        
		        //make the links and image intro disappear
		        /*
		        $('item_details').hide();
		        $$('.ajax_zoomed_media').each(function(el){
		        	el.hide();
		        });
		        */
		        if(imageTransitionBefore == 0){
			        var containerID = container.identify();
		        	//shrink the container to hide the links and description
		        	new Effect.BlindUp(containerID, yScale, {
				        	afterFinish: function(effect){
	        			prototypeAZFunctions.simpleAjaxUpdater(callBacks, proxyEvent);
	        			}
		        	});
				}
		        
		        if(imageTransitionBefore == 1){
			        new Effect.Scale(container, yScale,{scaleX: false,scaleContent: false,
			        	afterFinish: function(effect){
		        			prototypeAZFunctions.simpleAjaxUpdater(callBacks, proxyEvent);
		        		}
			        });
		        }    
		        
			}     
	        
	        
	        
	         	
	        // calculate size difference between new and old image, and resize if necessary
	        /*
	        var wDiff = widthCurrent - widthNew;
	        var hDiff = heightCurrent - heightNew;

	        if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); 
	        if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration}); 
			*/
	
		},
		getEventHref : function(event){
			if(event.proxyEvent){
				return event.targetHref;
			}else{	
				var anchor = event.findElement('a');
				return anchor.href;
			}	
		}	
		//not in use yet, untested
		/*
		function addSWFObjects(){
			if(hasPrototype){
				$$('.swf_player').each(function(el){
					swfobject.registerObject(el.id);
				});	
			}
		}
		*/
	};
}();



function expandCollapse(event){
	
	//not in use yet
	//first of all, kill the request
	event.stop();
	//the link which was clicked
	var anchor = event.element();
	//its querystring
	var qs = anchor.search;
	
	//as an associative array
	var qsParams = qs.toQueryParams();
	//the desired action
	var actionParam = qs.indexOf('expand') != -1 ? 'expand' : 'collapse';
	//the panel's itemId
	var actionParamLength=actionParam.length;
	
	var startSearch = qs.indexOf(actionParam+'Panel') + actionParamLength + 5;
	
	var panelItemId = qs.substring(startSearch,qs.indexOf('=true',startSearch));
	
	//the desired QS parameter for the server
	var firstRequestParameter = actionParam + 'Panel' + panelItemId;
	//actionParam += 'Panel' + qsParams.actionParam;
	var params = {};
	params[firstRequestParameter] = true;
	params['tileRefresh'] = true;
	params['tileDefinition'] = 'tiles.panel.decorator';
	params['panelItemId'] = panelItemId;
	params['requestItemKey'] = qsParams.requestItemKey;
	params['ajaxSource'] = true; //to fool app into thinking this is a Spring AJAX request
	//try to get link's parent here? might be easier/more portable
	var updater = new Ajax.Updater('panel' + panelItemId,"",{
		onComplete: addPrototypeEffects,
		method: 'get',
		parameters: params
	}
	);
}


function toggleBlinds(event){
	var parentEl=event.element();
	if(parentEl.id.startsWith('child')){
		//we actually want to apply the effect to the named element 
		//in the format child_elementname
		var childId=parentEl.id.split('_')[1];
		var el=$(childId);
	}
	
	if(el){
		Effect.toggle(el,'blind');
		parentEl.toggleClassName('collapsed');
		return false;
	}
}

function attachEvents(){
	//goes through the document
	//finds elements which can have enhanced JS functionality 
	//adds that functionality, if supported
	
	//find "print page" link
	linkPrint=document.getElementById('print_page');
	if(linkPrint){
		if(window.print){
			linkPrint.onclick=function(){printPage();};
		}	
	}
	//find "bookmark page" link
	linkBookmark=document.getElementById('bookmark_page');
	if(linkBookmark){
		 if(window.external || window.sidebar){
			linkBookmark.onclick=function(){bookmarkPage();};
		}	 
	}
	
	//necessary as more than one element has name sakey
	sakey=getNamedElementId('select','sakey');

	if(sakey){
		sakey.onchange=function(){toggleSelection(sakey);};
	}
	
	//find site select on advanced search
	rskey=document.getElementById('rskey');
	if(rskey){
		rskey.onchange=function(){toggleRelatedSelects();};
	}
	findExitRamps();
	prepareHelpLinks();
	//now call any additional functions which need to be executed onload
	//these are defined in site, model or sub-model specific js files 
	//in an array called toCall
	if(typeof(toCall)=='object'){
		for(j=0;j<toCall.length;j++){
			try{
				//attempt to call the function
				toCall[j].call();
			}catch(e){
				//error occurred when calling the function 
				//possibly a scope error or function name misspelled
			}
		}
	}
	addPrototypeEffects();
}

//this code always runs and adds in all the functionality if it's available	
if(document.getElementById){
	//browser supports getElementById - attempt to add js functionality
	window.onload=attachEvents;
}