/*
© Globespan PLC 2008
Developer: G Bradley

The FLYG object contains various utility functions that make dealing with common JS tasks quick and easy.
You can select multiple page elements and manipulate them easily, issue remote precedure calls and handle
user events.

The FLYG object also acts as a namespace for other JS components.
*/

/* start by implimenting 1.6 array methods for unsupported browsers, plus some extras */

if (!Array.prototype.indexOf){
Array.prototype.indexOf=function(elt,from){
    var len = this.length;
	from = from ? from : 0;
    for (; from < len; from++){
		if (from in this && this[from]===elt) return from;
		}
    return -1;
	};
}

if (!Array.prototype.lastIndexOf){
Array.prototype.lastIndexOf=function(elt,from){
    var len = this.length;
	from=from ? from : 0;
    for (; from > -1; from--){
		if (from in this && this[from]===elt) return from;
		}
    return -1;
	};
}

if (!Array.prototype.every){
Array.prototype.every=function(fun){
    var len = this.length;
	var	thisp = arguments[1];
    for (var i = 0; i < len; i++){
		if (i in this && !fun.call(thisp, this[i], i, this)) return false;
		}
	return true;
	};
}

if (!Array.prototype.filter){
Array.prototype.filter=function(fun){
    var len = this.length;
    var res = new Array();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++){
		if (i in this){
			var val = this[i];
			if (fun.call(thisp, val, i, this)) res.push(val);
			}
		}
	return res;
	};
}

if (!Array.prototype.forEach){
Array.prototype.forEach=function(fun){
    var len = this.length;
    var thisp = arguments[1];
    for (var i = 0; i < len; i++){
		if (i in this) fun.call(thisp, this[i], i, this);
		}
	};
}

if (!Array.prototype.map){
Array.prototype.map=function(fun){
    var len = this.length;
    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++){
		if (i in this) res[i] = fun.call(thisp, this[i], i, this);
		}
    return res;
	};
}

if (!Array.prototype.some){
Array.prototype.some=function(fun){
    var len = this.length;
    var thisp = arguments[1];
    for (var i = 0; i < len; i++){
		if (i in this && fun.call(thisp, this[i], i, this)) return true;
		}
    return false;
	};
}

Array.prototype.unique=function(){
var a=[];
this.forEach(function(x){
	if (a.indexOf(x)==-1) a.push(x);
	});
return a;
};

Array.prototype.hash=function(index){
var len=this.length;
for (var i=len-1;i>=0;i--) this[this[i][index]]=this[i];
};

String.prototype.trim=function(){
return this.replace(/^(\s*)|(\s*)$/g,'');
};

/* Now define everything inside the FLYG namsepace */

var FLYG=(function(){

	var self={};
	
	var _apply=function(fn,args){		// a private function to help create collections
		var all=[];
		this.forEach(function(x){
			fn.apply(x,args).forEach(function(y){
				if (all.indexOf(y)<0) all.push(y);
				});
			});
		return new _Collection(all);
		};
	
	var _Collection=function(args){			// private collection constructor
		var self=this, i=0, j=0;
		for (;i<args.length;i++){
			self[j++]=args[i];
			}
		self.length=j;
		};
		
	_Collection.method=function(name,fn){	// private static method to chain method additions
		this.prototype[name]=fn;
		return this;
		}
		
	_Collection.method('forEach',function(fn){			// runs forEach() on collection
		Array.prototype.forEach.call(this,fn);
		}).method('map',function(fn){					// runs map() on collection
		var x=Array.prototype.map.call(this,fn);
		if (Array.prototype.every.call(x,function(y){
			return (!!y.nodeType);
			})) return new _Collection(x);
		else return Array.prototype.slice.call(x);
		}).method('filter',function(fn){				// runs filter() on collection
		return new _Collection(Array.prototype.filter.call(this,fn));
		}).method('unique',function(){
		return new _Collection(Array.prototype.unique.call(this));
		}).method('addEvent',(function(){				// adds an event listener
		if (window.addEventListener) return function(type,fn){
			this.forEach(function(x){
				x.addEventListener(type,fn,false);
				});
			return this;
			}
		else return function(type,fn){
			this.forEach(function(x){
				x.attachEvent('on'+type,function(){
					fn.call(x);
					});
				});
			return this;
			}
		})()).method('removeEvent',(function(){			// remove event listener
		if (window.removeEventListener) return function(type,fn){
			this.forEach(function(x){
				x.removeEventListener(type,fn,false);
				});
			return this;
			}
		else return function(type,fn){
			this.forEach(function(x){
				x.detachEvent('on'+type,fn);
				});
			return this;
			}
		})()).method('addClass',function(){				// add class strings to collection
		var c=Array.prototype.slice.call(arguments).join(" ");
		this.forEach(function(x){
			x.className=x.className+" "+c;
			});
		return this;
		}).method('removeClass',function(){				// remove class strings from collection
		var c=Array.prototype.slice.call(arguments);
		this.forEach(function(x){
			if (!c.length) x.className="";
			else x.className=x.className.split(" ").filter(function(y){
				return c.indexOf(y)<0;
				}).join(" ");
			});
		return this;
		}).method('setStyle',function(o){				// set CSS styles on collection
		this.forEach(function(x){
			for (p in o) x.style[p]=o[p];
			});
		return this;
		}).method('getStyle',(function(){				// get CSS styles from collection
		var fn=window.getComputedStyle ? function(n,p){
			p=p || false;
			var comp=window.getComputedStyle(n,'');
			if (p) return comp[p];
			var x={};
			for (var y in comp){
				if (comp[y] && (typeof comp[y]=='string')) x[y]=comp[y];	// try to match the computed property
				}
			return x;
			} : function(n,p){
			if (n.currentStyle) return p ? n.currentStyle[p] : n.currentStyle;
			return "";
			};
		return function(p){
			return this.map(function(x){
				return fn(x,p);
				});
			}
		})()).method('show',function(t){
		t=t || 'block';
		this.forEach(function(x){
			x.style.display=t;
			});
		return this;
		}).method('hide',function(){
		this.forEach(function(x){
			x.style.display='none';
			});
		return this;
		}).method('getCoord',function(p){
		return this.map(function(x){
			var z={x:0,y:0};
			if (x.offsetParent){
				z={x:x.offsetLeft,y:x.offsetTop};
				while (x=x.offsetParent){
					if (p){
						var ps=new _Collection([x]).getStyle('position')[0];
						if (ps=='absolute' || ps=='relative') break;
						}
					z={x:z.x+=x.offsetLeft,y:z.y+=x.offsetTop};
					}
				}
			return z;
			});
		}).method('setCoord',function(z){
		return this.setStyle({top:z.y+'px',left:z.x+'px'});
		}).method('$byClass',function(){				// impliment $byClass on a collections descendants
			return _apply.call(this,self.$byClass,arguments);
		}).method('$byTag',function(){					// impliment $byTag on a collections descendants
			return _apply.call(this,self.$byTag,arguments);
		}).method('next',function(){
		return new _Collection(this.map(function(x){
			if (x.nextSibling) x=x.nextSibling;
			while (x.nodeType!=1) x=x.nextSibling
			return x;
			}));
		}).method('previous',function(){
		return new _Collection(this.map(function(x){
			if (x.previousSibling) x=x.previousSibling;
			while (x.previousSibling && x.nodeType!=1) x=x.previousSibling
			return x;
			}));
		}).method('parent',function(){
		return new _Collection(this.map(function(x){
			return x.parentNode;
			})).unique();
		}).method('children',function(){
		var a=[];
		this.forEach(function(x){
			var c=x.childNodes;
			for (var i=0;i<c.length;i++){
				if (c[i].nodeType==1) a.push(c[i]);
				}
			});
		return new _Collection(a.unique());
		});
		
	['load','unload','click','dblclick','mouseover','mouseout','keydown','keypress','keyup','change','focus','blur'].forEach(function(x){
		_Collection.prototype[x]=function(fn){return this.addEvent(x,fn);};
		_Collection.prototype['remove'+x.substring(0,1).toUpperCase()+x.substring(1,x.length)]=function(fn){return this.removeEvent(x,fn);};
		});

	self.Info={
		querystring:(function(){
			var str=window.location.href.replace(/.+\?/,"").split("&"), data={};
			for (i=0;i<str.length;i++){
				str[i]=str[i].split("=");
				data[str[i][0]]=(!isNaN(str[i][1]) ? str[i][1]*1 : str[i][1]);
				}
			return function(key){
				return data[key] || '';
				}
			})(),
		browser:(function(){
			var b;
			if (/firefox/i.test(navigator.userAgent)) b="FF";
			else if (/msie/i.test(navigator.userAgent)) b="IE";
			else if (/safari/i.test(navigator.userAgent)) b="SF";
			else if (/opera/i.test(navigator.userAgent)) b="OP";
			else b="";
			return function(){
				return b;
				}
			})(),
		windowSize:function(){
			return document.all ? {x:document.body.clientWidth,y:document.body.clientHeight} : {x:innerWidth,y:innerHeight};
			},
		standardsMode:function(){
			return function(){return document.compatMode!='BackCompat'}
			}
		};
	
	self.$=function(){
		var args=Array.prototype.slice.call(arguments);
		if (args[0].forEach) args=args[0];
		return new _Collection(args.map(function(x){
			return x==window? window : (typeof x=="string" ? document.getElementById(x) : x);
			}).filter(function(x){
			return !!x;
			}));
		};
		
	self.$byClass=function(){
		var base=this==self ? document : this;
		var args=Array.prototype.slice.call(arguments);
		
		var tagtype="*";
		if (typeof (args[args.length-1])!="string" && args[args.length-1].tagtype){
			tagtype=args[args.length-1].tagtype;
			args.pop();
			}
		
		var all=base.getElementsByTagName(tagtype), copy=[], results=[];
		for (var i=0;i<all.length;i++) copy[i]=all[i];
		var classes=copy.map(function(x){
			return x.className.split(" ");
			});
		if (args[0].constructor==Array) args=args[0];
		args.forEach(function(c){
			copy.forEach(function(x,j){
				if (classes[j].indexOf(c)>=0 && results.indexOf(x)<0) results.push(x);
				});
			});
		return new _Collection(results);
		};
		
	self.$byTag=function(){
		var base=this==self ? document : this;
		var args=Array.prototype.slice.call(arguments);
		var all=[];
		args.forEach(function(x){
			x=base.getElementsByTagName(x);
			for (var i=0;i<x.length;i++){
				if (all.indexOf(x[i])<0) all.push(x[i]);
				}
			});
		return new _Collection(all);
		}
		
	self.Http={
		xhr:function(url,callback,method,postdata){
			var http=(function(){
				if (window.XMLHttpRequest) return function(){
					return new window.XMLHttpRequest;
					};
				else return function(){
					return new ActiveXObject("Microsoft.XMLHttp")
					};
				})();
			var req=new http();
			req.onreadystatechange=function(){
				if (callback && req.readyState==4 && req.status==200){
					callback(req.responseText,req.responseXML);
					}
				};
			if (method=='post'){
				req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
				req.setRequestHeader("Content-length",postdata.length);
				req.setRequestHeader("Connection","Close");
				}
			req.open(method || 'get',url,true);
			req.send(postdata || '');
			},
		script:function(url){
			var script=document.createElement("script");
			script.type='text/javascript';
			script.src=url;
			document.getElementsByTagName("head")[0].appendChild(script);
			}
		};
		
	self.Event={
		target:function(e){
			e=(e) ? e : ((window.event) ? event : null);
			return e ? (e.target ? e.target : ((e.srcElement) ? e.srcElement : null)) : false;
			},
		handleBubble:function(e,bubble){
			e=(e) ? e : ((window.event) ? event : null);
			if (bubble) return true;
			if (e.stopProgagation) e.stopPropagation();
			else e.cancelBubble=true;
			if (e.preventDefault) e.preventDefault();
			else e.returnValue=false;
			return false;
			},
		coord:function(e){
			var e=e||window.event, c={x:0,y:0};
			if (e.pageX) c={x:e.pageX,y:e.pageY};
			else if (e.clientX){
				c.x=e.clientX+document.body.scrollLeft-document.body.clientLeft;
				c.y=e.clientY+document.body.scrollTop-document.body.clientTop;
				if (document.body.parentElement && document.body.parentElement.clientLeft){
					var bP=document.body.parentElement;
					c.x+=bP.scrollLeft-bP.clientLeft;
					c.y+=bP.scrollTop-bP.clientTop;
					}
				}
			return c;
			}
		};
		
	self.Cookie={
		set:function(name,value,days){
			if (days){
				var date=new Date();
				date.setTime(date.getTime()+(days*24*60*60*1000));
				var expires="; expires="+date.toGMTString();
				}
			else var expires="";
			document.cookie=name+"="+value+expires+"; path=/";
			},
		get:function(name){
			var nameEQ=name+"=", ca=document.cookie.split(';');
			for(var i=0;i < ca.length;i++){
				var c=ca[i];
				while (c.charAt(0)==' ') c=c.substring(1,c.length);
				if (c.indexOf(nameEQ)==0) return c.substring(nameEQ.length,c.length);
				}
			return "";
			},
		destroy:function(name){
			self.Cookie.set(name,"",-1);
			}
		};
		
	self.Date=(function(){

		var jd=function(dt,i,o){
			this.version=1;
			this.formats={input:i || _defaults.input, output:i || _defaults.output};
			if (!dt) this.date=new Date();
			else if (typeof dt=='string') this.date=_parse(dt,this.formats.input);
			else if (typeof dt=='number'){
				this.date=new Date();
				this.date.setTime(dt);
				}
			else this.date=dt;
			};
		
		jd.prototype={
			toString:function(o){
				return _serialize(this.date,o || this.formats.output);
				},
			add:function(i,n){
				var d=this.date;
				i=i=="d" ? "Date" : (i=="m" ? "Month" : "FullYear");
				d['set'+i](d['get'+i]()+n);
				return this;
				},
			compare:function(dt){
				if (typeof dt=='string') dt=new jd(dt);
				var a=this.toString('yyyymmdd')*1, b=dt.toString('yyyymmdd')*1;
				return a==b ? 0 : (a<b ? 1 : -1);
				},
			getDate:function(){ return this.date.getDate(); },
			getDay:function(){ return this.date.getDay(); },
			getDayName:function(){ return jd.days[_defaults.lang][this.date.getDay()]; },
			getMonth:function(){ return this.date.getMonth(); },
			getMonthName:function(){ return jd.months[_defaults.lang][this.date.getMonth()]; },
			getFullYear:function(){ return this.date.getFullYear(); },
			isLeapYear:function(){ return !(this.date.getFullYear() % 4) },
			daysInMonth:function(){ return _daysInMonths[this.getMonth()] || (this.isLeapYear() ? 29 : 28);},
			timestamp:function(){ return this.date.getTime();}
			};
		
		jd.setInputFormat=function(f){ _defaults.input=f; };
		jd.setOuputFormat=function(f){ _defaults.output=f; };
		jd.setLanguage=function(lang){
			if (jd.months[lang] && jd.days[lang]) _defaults.lang=lang;
			else throw new Error('JDate.setLanguage: data not specified for language \''+lang+'\'');
			return me;
			};
		jd.addMonthNames=function(lang,names){
			jd.months[lang]=names;
			return me;
			};
		jd.addDayNames=function(lang,names){
			jd.days[lang]=names;
			return me;
			};
		
		var _defaults={
			input:'dd/mm/yyyy',
			output:'dd/mm/yyyy',
			lang:'EN'
			};
		jd.months={
			EN:["January","February","March","April","May","June","July","August","September","October","November","December"]
			};
		jd.days={
			EN:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
			};

		var _pad=function(n){ return n<10 ? "0"+n : n; };
		var _daysInMonths=[31,false,31,30,31,30,31,31,30,31,30,31];
		var _parse=function(str,fmt){
			var mask='('+ (fmt || _defaults.input)+')';
			mask=mask.replace(/\//g,')\\/(').replace(/-/g,')-(').replace(/\s/g,') (');
			var escape=['d','m','y','Y'];
			for (var i=0;i<escape.length;i++) mask=esc(mask,escape[i],'d');
			var escape=['D','M'];
			for (var i=0;i<escape.length;i++) mask=esc(mask,escape[i],'w');

			function esc(mask,chr,r){
			return mask.replace(new RegExp(chr,'g'),'\\'+r);
			};

			var m=str.match(new RegExp(mask));
			if (!m) throw new Error("JDate: cannot match date '"+str+"' against format '"+(fmt || _defaults.input)+"'");
			var d=new Date();
			d.setFullYear((m[3]*1)<2000 ? 2000+(m[3]*1) : m[3],((m[2]*1)-1),m[1]*1);
			//d.setMonth(((m[2]*1)-1));
			//d.setDate(m[1]);
			return d;
			};
		var _serialize=function(dt,o){
			var mask=o || _defaults.output, y=dt.getFullYear()+"", m=dt.getMonth()+1, d=dt.getDay()+1, dd=dt.getDate();
			mask=mask.replace(/yyyy/g,y).replace(/yy/g,y.substring(2,4)).replace(/y/g,y.substring(2,4)*1).replace(/mm/g,_pad(m)).replace(/m/g,m).replace(/MM/g,jd.months[_defaults.lang][m-1]);
			var z=mask.match(/M\{(\d)\}/);
			if (z) mask=mask.replace(/M\{(\d)\}/,jd.months[_defaults.lang][m-1].substring(0,z[1]));
			mask=mask.replace(/dd/g,_pad(dd)).replace(/d/g,dd).replace(/DD/g,jd.days[_defaults.lang][d-1]);
			var z=mask.match(/D\{(\d)\}/);
			if (z) mask=mask.replace(/D\{(\d)\}/,jd.days[_defaults.lang][d-1].substring(0,z[1]));
			return mask;
			};

		return jd;
		})();
		
	var _ready=[];
	var _readyComplete=false;
	self.ready=function(f){
		if (!_readyComplete) _ready.push(f);
		else f();
		};
	self.readyNow=function(){
		_ready.forEach(function(f){ f(); });
		_readyComplete=true;
		};
		
	if (navigator.userAgent.match(/firefox|opera/i)) document.addEventListener("DOMContentLoaded",self.readyNow,false);
	else{
		var loadTest=document.createElement("document:loadtest"); // if no DOMContentLoaded use a version of Hedger Wang's load testing script
			(function(){
			try {
				if(document.readyState!="complete") return setTimeout(arguments.callee,10);
				if (navigator.userAgent.match(/msie/i)) loadTest.doScroll('left');
				self.readyNow();
				loadTest = null;
				}
			catch (e){ setTimeout(arguments.callee, 10); }
			})(); 
		}
		
	self.extend=function(sub,base){	// allow classical inheritance
		var Inherit=function(){};
		Inherit.prototype=base.prototype;
		sub.prototype=new Inherit();
		sub.prototype.constructor=sub;
		sub.baseClass=base;
		};

	return self;

	})();