document.observe('dom:loaded',InitializePage);

var Webtec = {};

var varargs = $H({});

Class.singleton = function(){
	var properties = $A(arguments);
	var klass;
	
	if(Object.isFunction(properties[0]))
		klass = Class.create(properties.shift(),properties.shift());
	else
		klass = Class.create(properties.shift());
	
	var v = varargs.get(properties.size());
	if(!v){

		var args = "";
		for(var i = 0; i < properties.size(); i++){
			if(args != "")
				args += ",";
			args = args + "p["+i+"]";
		}


		var s = "<script>varargs.set("+ properties.size() + ",function(k,p){return new k\(" + args + "\)})</script>";
		s.evalScripts();
		//console.log("script=" + s);
		//console.log("result= " + s.evalScripts());

		v = varargs.get(properties.size());
	}

	var singleton = v(klass,properties);

	
	

	return singleton;

}


Webtec.AjaxObject = Class.create({
	initialize : function(attrs){
		this.path = '/json' + attrs.path;
		this.namespace = attrs.namespace || attrs.path;
	},
	setPath : function(path){
		this.path = '/json' + path;
	},
	bindAjaxCB : function(func,msg,cb){
		return function(m,cb,t){
			func(t,m,cb);
		}.bind(this,msg,cb)
	},
	request   : function(req){
		
		req = $H(req||{});
		var action  = req.unset('action') || 'noaction'; 
		var cb = req.unset('successCB');
		var success = req.unset('onSuccess') || this.bindAjaxCB(this.HandleAjaxSuccess,undefined,cb);
		if(!Object.isFunction(success))
			success = this.bindAjaxCB(this.HandleAjaxSuccess,success,cb);
		
		cb = req.unset('failureCB');
		var failure = req.unset('onFailure') || this.bindAjaxCB(this.HandleAjaxFailure,undefined,cb);
		if(!Object.isFunction(failure))
			failure = this.bindAjaxCB(this.HandleAjaxFailure,failure,cb);

		//Allow overide of path as some object will talk to more than one controller
		//eg FormDialog
		var path = req.get('path') || this.path;
		req.unset('path');
		var path = path + "/" + action;

		var request = {
			method    : req.unset('method') || 'POST',
			onSuccess : success,
			onFailure  : failure
		};
		var params = Object.isUndefined(req.get('params'))?req : $H(req.get('params'));
	
		params.set('action', action);
		try {
			params = Object.toJSON(params);
		}catch(e){
		}
		
		request.parameters = {request : params};

		var r = new Ajax.Request(path,request);
		//r.request = req;
		return r;
	},
	HandleAjaxSuccess : function(transport,msg,cb){
		var res;
		try {
			res = transport.responseText.evalJSON();
		}catch(e){
		}
		res = res || {};
		res = res.response;
		if(Object.isUndefined(res) || Object.isUndefined(res.result)||(res.result != 'success'))
			return transport.request.options.onFailure(transport);

		msg = msg || res.msg || transport.request.msg;
	        if(msg){
			alert(msg);
		}
		if(cb)
			cb(res,transport);
		return res;
	},
	HandleAjaxFailure : function(transport,msg,cb){
		var res;
		try {
			res = transport.responseText.evalJSON();
		}catch(e){
		}
		res = res || {};
		res = res.response || {};

		if(!(Object.isUndefined(msg) || Object.isArray(msg))){
			msg = $A([ msg ]);
		}

		msg = msg || res.error;

		$A(msg).each(function(m){
			alert(m);
		});

		if(cb){
			cb(res,transport);
		}


	}
});

Webtec.Basket = Class.create(Webtec.AjaxObject,{
	initialize : function($super){
		this.size = 0;
		this.items = [];
		this.callback = $A([]);

		$super({path:'/basket'});
	},
	basketAction : function(action,attrs){
		attrs = attrs || {};
		attrs.action = action;
		attrs.successCB = attrs.successCB || this.updateInfo.bind(this);
		return this.request(attrs);
	},
	addToBasket : function(item,attrs){
		attrs = attrs || {};
		if(this.inBasket(item))
			return;//error already in basket
		attrs.item = item;
		attrs.successCB = attrs.successCB || this.showAddedToBasketDialog.bind(this);
		return this.basketAction('add',attrs);
	},
	removeFromBasket : function(item,attrs){
		attrs = attrs || {};
		if(!this.inBasket(item))
			return;//Not in basket
		attrs.item = item;
		attrs.successCB = attrs.successCB || this.showRemovedFromBasketDialog.bind(this);
		return this.basketAction('remove',attrs);
	},
	updateItemQuantity : function(item,quantity,attrs){
		attrs = attrs || {};
		var item = this.getItem(item);
		if(Object.isUndefined(item))
			return;//error item on in basket
		if(Object.isNumber(item.quantity) && (item.quantity == quantity))
			return;//Nothing to change
		attrs.item     = item.id || item;
		attrs.quantity = quantity; 
		return this.basketAction('updateItemQuantity',attrs);
	},
	getInfo : function(attrs){
		return this.basketAction('info',attrs);
	},
	findCallback : function(cb){
		var found = 0;
		this.callback.each(function(cb1){
			if(cb1 == cb)
				found = 1;
		});
		return found ? cb : 0;
	},
	addCallback : function(cb){
		if(!this.findCallback(cb))
			this.callback.push(cb);

		if(this.updated)
			cb(this);
	},
	removeCallback : function(cb){
		if(this.findCallback(cb))
			this.callback = this.callback.without(cb);
	},
	getItem : function(item){
		item = item || -1;
		var id = item.id || item;
		
		var i = undefined;
		this.items.each(function(item){
			if(item.id == id)
				i = item;
		});
		return i;
	},
	inBasket : function(item){
		return Object.isUndefined(this.getItem(item))?false:true;
	},
	updateInfo : function(response,transport){
		this.size     = response.size;
		this.size_msg = response.size_msg;
		this.items    = response.items;

		this.callback.each(function(cb){cb(this);}.bind(this));
	},
	showAddedToBasketDialog : function(response,transport){
		this.updateInfo(response,transport);
		var dlg = Webtec.Dialog.Mgr.createAjaxDialog("basket_add",{});
		dlg.show();
	},
	showRemovedFromBasketDialog : function(response,transport){
		this.updateInfo(response,transport);
		var dlg = Webtec.Dialog.Mgr.createAjaxDialog("basket_remove",{});
		dlg.show();
	}
});

Webtec.basket = new Webtec.Basket();

Webtec.Form = {};

Webtec.Form.Base = Class.create({
	initialize : function (form,attrs){
		this.elem = form;
		this.error = $H({});
		this.errorCount = 0;
		this.validateOnChange = attrs.validateOnChange || 1;
		this.fieldErrorDisplay = attrs.fieldErrorDisplay || 
			this.elem.select('.form-item .error-display').size() > 0;

		//Setup submit
		var submit = attrs.submit || this.elem.select('[type=submit]');
		if(Object.isArray(submit) && ! submit.size())
			submit = this.elem.select('.submit');
		if(!submit.size()){
			;//throw('Could not find submit button(s)');
		}else{
			if(!Object.isArray(submit))
				submit = $A([submit]);

			var action = attrs.submitAction || this.handleSubmit.bindAsEventListener(this);
			submit.each(function(s){
				s.observe('click',action);
			}.bind(this));
		}

		
		if(this.validateOnChange)
			this.setupItemValidation();

		if(this.fieldErrorDisplay){
			this.peError = new PeriodicalExecuter(this.cycleFieldErrors.bind(this),1);
		}
	},
	setupItemValidation : function(){
		this.getValidationTests().each(function(test){
			this.elem.select('.form-item.' + test.key).each(function(item){
				var elem = this.findElement(item);
				elem.observe('change',
					this.handleValidation.bindAsEventListener(this,test.key,test.value));
			}.bind(this));
		}.bind(this));
	},
	validate   : function(){
		if(this.errorCount)
			return false;

		this.getValidationTests().each(function(test){
			this.elem.select('.form-item.' + test.key).each(function(item){
				var elem = this.findElement(item);
				this.do_validation(elem,test.key,test.value);
			}.bind(this));
		}.bind(this));
		
		if(this.errorCount)
			return false;
		return true;
	},
	getValidationTests : function(){
		if(!Object.isUndefined(this._validation_tests))
			return this._validation_tests; //Assume we won't add any tests during life time of form
		var tests = $H({});
		for(k in this){
			if(Object.isFunction(this[k]) && k.startsWith('validate_')){
				tests.set(k.substr('validate_'.length),this[k].bind(this));
			}
		}
		this._validation_tests = tests;
		return tests;
	},
	setValidationTest : function(test,func){
		this.getValidationTests();
		this._validation_tests.set(test,func);//Can override or set new
	},
	//Event interface for handling changes to individual fields
	handleValidation : function(event,test,func){
		var elem = event.element();
		//var valid = func(elem);
		var valid = this.do_validation(elem,test,func);
		if(!valid && (this.displayErrorOnChange || this.fieldErrorDisplay)){
			this.displayError(this.findItem(elem),test);
		}

		if(valid && this.fieldErrorDisplay && this.error.get(elem.name) &&
			! this.error.get(elem.name).keys().size())
			this.clearFieldErrorDisplay(this.findItem(elem));
	},
	//Base validation function
	do_validation   : function(elem,test,func){
		var item = this.findItem(elem);

		func = func || this['validate_' + test].bind(this);
		
		var valid = func(elem);
		if(valid){
			this.clearFieldError(item,test);
		}else{
			this.setFieldError(item,test);
		}
		return valid;

	},
	displayError    : function(item,test){
		var elem = this.findElement(item);

		if(!this.error.get(elem.name).get(test))
			return;

		
		if(this.fieldErrorDisplay){
			this.setFieldErrorDisplay(item,test);
		}else{
			var tmpl = new Template(Webtec.Form.ValidationErrorMsg[test].field);
			var msg = tmpl.evaluate({field : item.down('label').innerHTML});

			this.showError(item,msg);
		}
		
	},
	showError : function(item,msg){
		alert(msg);
	},
	setFieldErrorDisplay : function(item,error){
		var tmpl = new Template(Webtec.Form.ValidationErrorMsg[error].field);
		var msg = tmpl.evaluate({field : item.down('label').innerHTML});
		var disp = item.down('.error-display');

		if(Object.isUndefined(disp))
			return;
		disp.update(msg);
		disp.show();
	},
	clearFieldErrorDisplay : function(item){
		var disp = item.down('.error-display');
		if(Object.isUndefined(disp))
			return;
		disp.update();
	},
	validate_required : function(elem){
		var item = this.findItem(elem);
		if(!item.hasClassName('required'))
			return true;
		if(!item.visible()) //Hidden required fields are not required
			return true;

		return elem.value != '';
	},
	validate_captcha : function(elem){
		return true;//If capture changed then ok to submit again
	},
	validate_fred : function(elem){
		return elem.value.indexOf('fred')>=0;
	},
	validate_email : function(elem){
		if(elem.value == "")
			return true;

		return elem.value.indexOf('@') > 0;
	},
	submit 	   : function(){
		if(!this.validate())
			return;

		this.do_submit();
	},
	setFieldError : function(item,error){
		this.errorCount++;
		var elem = this.findElement(item);
		var itemError = this.error.get(elem.name);
		if(Object.isUndefined(itemError)){
			itemError = $H({});
			this.error.set(elem.name,itemError);
		}
		itemError.set(error,1);
		item.addClassName('error');
	},
	clearFieldError   : function(item,error){
		var elem = this.findElement(item);
		var itemError = this.error.get(elem.name)||$H({});
		if(itemError.get(error)){
			this.errorCount--;
			itemError.unset(error);
		}
		if(itemError.keys().size() == 0)
			item.removeClassName('error');
	},
	findElement  : function(item){
		var elem = item.down('input');
		if(!Object.isElement(elem))
			elem = item.down('select');
		if(!Object.isElement(elem))
			elem = item.down('textarea');
		return elem;
	},
	findItem     : function(elem){
		return elem.up('.form-item');
	},
	handleSubmit : function(event){
		Event.stop(event);
		if(this.errorCount){
			return;
		}
		if(!this.validate())
			return;
		this.submit();
	},
	do_submit : function(){
		this.elem.submit();
	},
	cycleFieldErrors : function(pe){
		this.elem.select('.form-item.error').each(function(item){
			var elem = this.findElement(item);
			this.errorCycleIndex = this.errorCycleIndex || $H({});
			var index = this.errorCycleIndex.get(elem.name);
			if(Object.isUndefined(index))
				index = -1;
			index++;
			if(index >= this.error.get(elem.name).keys().size())
				index = 0;
			this.errorCycleIndex.set(elem.name,index);
			var error = this.error.get(elem.name).keys()[index];
			this.setFieldErrorDisplay(item,error);
		}.bind(this));
	}

});

Webtec.Form.AjaxForm = Class.create(Webtec.Form.Base,{
	initialize : function($super,form,attrs){
		attrs = attrs || {};

		$super(form,attrs);

		var path = attrs.path || form.action;
		this.form_fields = attrs.form_fields;
		this.successCB = attrs.successCB;
		this.failureCB = attrs.failureCB;
		

		var path = form.action;
		if(form.action.indexOf(document.domain) >= 0){
			path = form.action.substr(form.action.indexOf(document.domain)+document.domain.length);
			if(path.match('^:')){
				path = path.substr(path.indexOf('/'));
			}
		}
		this.action = attrs.action || path.substr(path.lastIndexOf('/')+1);

		//Strip action from path
		if(path.endsWith(this.action)){
			path = path.substr(0,path.length - this.action.length - 1);
		}

		var ajaxAttrs = attrs.ajax || {};
		ajaxAttrs.path = ajaxAttrs.path || attrs.path || path;
		this.msg = attrs.msg || ajaxAttrs.msg;
		
		this.ajax = new Webtec.AjaxObject(ajaxAttrs);
	},
	do_submit : function(){
		var action = this.action || 'submit';
		var data = this.elem.serialize(true);
		//data = Object.toJSON(data);
		
		var req = {
			action : action,
			form   : data,
			onSuccess : this.msg,
			successCB : this.handleFormSuccess.bind(this),
			failureCB : this.handleFormFailure.bind(this)
		};
		
		var form_fields = this.form_fields;
		if(Object.isFunction(form_fields))
			form_fields = form_fields(this);
		if(!Object.isUndefined(form_fields)){
			$H(form_fields).each(function(pair){
				req[pair.key] = pair.value;
			});
		}

		this.ajax.request(req);
	},
	handleFormSuccess : function(response,transport){
		if(this.successCB)
			return this.successCB(response,transport);
		return true;
	},
	handleFormFailure : function(response,transport){
		if(Object.isUndefined(response.form) || Object.isUndefined(response.form.error)){
			alert('Form submission failed');
		}else{
			$H(response.form.error).each(function(e){
				var elem = this.elem.select('.form-item [name=' + e.key + ']').first();
				var item = this.findItem(elem);
				$H(e.value).each(function(test){
					this.setFieldError(item,test.key);
					if(this.displayErrorOnChange || this.fieldErrorDisplay){
						this.displayError(this.findItem(elem),test.key);
					}
				}.bind(this));
			}.bind(this));
		}
		if(this.failureCB)
			return this.failureCB(response,transport);
		return true; 
	}
});


Webtec.Dialog = {};
Webtec.Dialog.Mgr = Class.singleton(Webtec.AjaxObject,{
	initialize : function($super){
		var attrs = {
			path : '/dialog'
		};
		$super(attrs);
		this.dialogs = new $H({});
		this.dialogsByElem = new $H({});
		this.overlay = new $H({});
	},
	createAjaxDialog : function(name,attrs){
		attrs = attrs || {};
		var dc = attrs.delete_cache;
		delete attrs.delete_cache;
		if(dc){
			delete this.dialogs.unset(name);
		}

		var dialog = this.dialogs.get(name);

		if(Object.isUndefined(dialog)){
			dialog = new Webtec.Dialog.AjaxDialog(name,attrs);
			this.dialogs.set(name,dialog);
			
			if(Object.isElement(dialog.dialog))
				this.dialogsByElem.set(dialog.dialog,dialog);
		}

		return dialog;
	},
	default_overlayStyle  : {
		opacity : 0.5,
		position : 'fixed',
		top : 0,
		left : 0,
		width  : '100%',
		height : '100%',
		backgroundColor : '#666',
		marginLeft : 0,
		zIndex : 1
	},
	createOverlay : function(zIndex){
		zIndex = zIndex || 1;
		if(Object.isUndefined(this.overlay.get(zIndex))){
			var overlay = new Element('div');
			var pos = document.viewport.getDimensions();
			overlay.setStyle(this.default_overlayStyle);
			overlay.setStyle({zIndex:zIndex});
			overlay.hide();
			$(document.body).appendChild(overlay);
			this.overlay.set(zIndex,overlay);
			
		}
		return this.overlay.get(zIndex);
	},
	showOverlay : function(attrs,dialog){
		var zIndex = 1;
		if((!Object.isUndefined(dialog))&&(!Object.isUndefined(dialog.dialog))){
			zIndex = dialog.dialog.getStyle('zIndex')-1;
		}
		if(Object.isUndefined(this.overlay.get(zIndex))){
			this.createOverlay(zIndex);
		}
		var overlay = this.overlay.get(zIndex);
		if(!Object.isUndefined(overlay)){
			if(attrs){
				var style = {};
				var def = $H(this.default_overlayStyle);
				def.each(function(p){
					style[p.key] = Object.isUndefined(attrs[p.key])?p.value:attrs[p.key];
				});
				overlay.setStyle(style);
			}
			overlay.show();
		}
	},
	hideOverlay : function(dialog){
		var zIndex = 1;
		if((!Object.isUndefined(dialog))&&(!Object.isUndefined(dialog.dialog))){
			zIndex = dialog.dialog.getStyle('zIndex')-1;
		}
		var overlay = this.overlay.get(zIndex);
		if(!Object.isUndefined(overlay)){
			overlay.hide();
		}
	},
	findDialogFromElem  : function(elem){
		if(elem.hasClassName('dialog')){
			return this.dialogsByElem.get(elem);
		}
		var e = elem.up('.dialog');
		if(Object.isUndefined(e)){
			e = elem.down('.dialog');
		}
		if(!Object.isUndefined(e)){
			e = this.dialogsByElem.get(e);
		}

		return e;
	},
	registerDialogElem : function(dialog,elem){
		this.dialogsByElem.set(elem,dialog);
	}
});
//Webtec.Dialog.Mgr = new Webtec.Dialog._Mgr();

Webtec.Dialog.Dialog = Class.create(/*Webtec.AjaxObject,*/{
	initialize : function(/*$super,*/attrs){
		/*$super(attrs);*/

		this.attrs = attrs || {};
		this.showOverlay = Object.isUndefined(attrs.showOverlay) ? 1 : attrs.showOverlay;
		this.showHeader  = attrs.showHeader  || 1;
		this.title = attrs.title;
		this.subTitle = attrs.subTitle;
		this.content = attrs.content;
		this.scrollTo = attrs.scrollTo || this.showOverlay;
		
		//Save button info
		this.buttons = attrs.buttons; 
		this.action  = attrs.action;

		//Maybe in an Object base class
		this.listeners = $H({});
		//Maybe overriden, but need it for header cancel btn
		this.listeners.set('cancel',this.handleDialogCancel.bindAsEventListener(this,attrs));
		
		
		this.formPrototype = Webtec.Form.Base;
		this.formAttrs = attrs.form || {};
	},
	create     : function(attrs){
		attrs = attrs || {};	
		var dlg = new Element('div');
		dlg.addClassName('dialog');
 
		if(this.showHeader){
			var header = Builder.node('div',{className:'dialog-header'},[
				Builder.node('span',{className:'title'},this.title),
				' - ',
				Builder.node('span',{className:'sub-title'},this.subTitle),
				Builder.node('div',{className:'toolbar'},[
					Builder.node('div',{className:'icon-button small hidden'},'X')
				])
			]);
			dlg.appendChild(header);
		}
		
		
		var content = new Element('div');
		content.addClassName('dialog-content');
		var tb  = Builder.node('div',{id:'button-pane'},[Builder.node('ul')]);
		
		//Put into document so we can add observers
		dlg.appendChild(content);
		dlg.appendChild(tb);
		$(document.body).appendChild(dlg);
		

/*
		if(this.buttons.ok){
			var ok  = new Element('input');
			ok.type = 'button';
			ok.name  = 'ok';
			ok.value = 'ok';
			ok.addClassName('ok-button');
			tb.appendChild(ok);
			action = attrs.action || this.handleDialogOk;

			//Should store listeners for stopObserving

			ok.observe('click',action.bindAsEventListener(this,attrs));
		}
		
		if(this.buttons.cancel){
			var cancel = new Element('input');
			cancel.type = 'button';
			cancel.name = 'cancel';
			cancel.value = 'cancel';
			cancel.addClassName('cancel-button');
			tb.appendChild(cancel);
			cancel.observe('click',this.listeners.get('cancel'));
		}
*/
		if(this.showHeader){
			dlg.down(
					'.dialog-header .icon-button'
				).observe('click',this.listeners.get('cancel'));
		}

		this.dialog = dlg;
		Webtec.Dialog.Mgr.registerDialogElem(this,this.dialog);

		if(Object.isUndefined(this.content)){
			this.content = this.createContent(attrs);
		}
		if(!Object.isUndefined(this.content))
			this.setContent(this.content);

		return dlg;
	},
	setupButtons : function(){
		var tb = this.dialog.childElements().last().down();
		tb.update(""); //Clear existing buttons - should unobserve!!!

		this.buttons = this.buttons || {ok:1,cancel:1};
		
		if(!Object.isUndefined(this.buttons.ok)){
			if(Object.isString(this.buttons.ok) || Object.isNumber(this.buttons.ok)){
				this.buttons.ok = {};
			}
			//Set defaults for Ok button
			this.buttons.ok.action = this.buttons.ok.action || this.action || this.handleDialogOk;
			this.buttons.ok.title  = this.buttons.ok.title || 'Ok';
		}
		if(!Object.isUndefined(this.buttons.cancel)){
			if(Object.isString(this.buttons.cancel) || Object.isNumber(this.buttons.cancel)){
				this.buttons.cancel = {};
			}
			//Set defaults for Cancel button
			this.buttons.cancel.action = this.buttons.cancel.action || this.handleDialogCancel;
			this.buttons.cancel.title  = this.buttons.cancel.title || 'Cancel'; //Translate???
			//Will replace with new listener
			this.dialog.down(
					'.dialog-header .icon-button'
				).stopObserving('click',this.listeners.get('cancel'));

		}
		
		$H(this.buttons).each(function(btn){
			var b = new Element('a');
			//b.type  = 'button'
			b.href="javascript:void()";
			b.id  = btn.key;
			b.update(btn.value.title || btn.key.capitalize());
			var c = btn.value.className || btn.key + "-button";
			b.addClassName(c);
			tb.appendChild(Builder.node('li',[b]));
			if(Object.isFunction(btn.value.action)){
				var a = btn.value.attrs || this.attrs;
				this.listeners.set(btn.key,btn.value.action.bindAsEventListener(this,a));
				b.observe('click',this.listeners.get(btn.key));
			}
		}.bind(this));
		this.dialog.down(
				'.dialog-header .icon-button'
			).observe('click',this.listeners.get('cancel'));
	},
	setContent : function(content){
		if(Object.isUndefined(this.dialog))
			return;

		this.dialog.down('.dialog-content').update(content);
		
		//Setup Buttons now the content is in place.  In sub classes, this process may have this.buttons
		this.setupButtons();

		var form = this.getForm();
	
		if(!Object.isElement(form))
			return;
		
		this.formAttrs.successCB = this.handleFormSuccess.bind(this,this.formAttrs.successCB);

		this.form = new this.formPrototype(form,this.formAttrs);
		//Webtec.Form.Mgr.createForm(form,this.FormAttrs);


	},
	handleFormSuccess : function(cb){
		var properties = $A(arguments);
		properties.shift();
		if(cb && !cb.apply(this.form,properties))
			return;
		this.hide();
	},
	getForm : function(){
		var f = this.dialog.down('form');
		if(Object.isUndefined(f))
			return;
		return f;
	},
	handleDialogOk : function(event){
		if(Object.isUndefined(this.form))
			return this.handleDialogCancel(event);
		this.form.submit();
		Event.stop(event); //Maybe async or an actual form submit will handle elsewhere if there is more todo
	},
	handleDialogCancel : function(event){
		this.hide();
	},
	show : function(attrs){
		attrs = attrs || {};
		if(Object.isUndefined(this.dialog))
			this.create(attrs);

		var t = attrs.top 	|| this.top;
		var l = attrs.left 	|| this.left;
		var w = attrs.width 	|| this.width;
		var h = attrs.height    || this.height;
		var c = attrs.colour    || this.colour || '#CCC';
		var z = attrs.zIndex    || this.zIndex || 2;

		//kiss for now
		if(Object.isUndefined(t)||Object.isUndefined(l)||Object.isUndefined(w)||Object.isUndefined(h)){
			//Not set to create sensible default of middle of screen
			var pos = document.viewport.getDimensions();
			t = (pos.height / 4);
			l = (pos.width / 4);
			w = (pos.width / 2);
		}
		t = t + "px";
		l = l + "px";
		w = w + "px";
		if(!Object.isUndefined(h))
			h = h + "px";
		h = h || 'auto';
		this.dialog.setStyle({position:'absolute',zIndex:z,width:w,height:h,left:l,top:t,opacity:1,backgroundColor:c});
		
		if(this.showOverlay)
			Webtec.Dialog.Mgr.showOverlay(this.attrs.overlay,this);

		this.dialog.show();
		if(this.scrollTo)
			this.dialog.scrollTo();
		if(!Object.isUndefined(this.peTextArea)){
			this.peTextArea.stop();
		}
		peTextArea = new PeriodicalExecuter(this.checkTextAreaSize.bind(this),0.1);
	},
	hide : function(){
		Webtec.Dialog.Mgr.hideOverlay(this);
		this.dialog.hide();
		if(!Object.isUndefined(this.peTextArea)){
			this.peTextArea.stop();
			this.peTextArea = undefined;
		}
	},
	visible : function(){
		if(Object.isUndefined(this.dialog))
			return false;
		return this.dialog.visible();
	},
	checkTextAreaSize : function(){
		this.dialog.select('textarea').each(function(te){
			te.setStyle({height:'0px'});
			te.setStyle({height:te.scrollHeight + 'px'});
		});
	},
	enableOkIfSet 	  : function(event){
		var elem = event.element();
		var ok  =  elem.up('.dialog').down('.ok-button');
		ok.disabled = elem.value == "";
	}
});

Webtec.Dialog.AjaxDialog = Class.create(Webtec.Dialog.Dialog,{
	initialize : function($super,name,attrs){
		this.name = name;	
		this.ajaxAttrs = attrs.ajax || {};
		delete attrs.ajax;
		$super(attrs);

		this.ajaxAttrs.path = this.ajaxAttrs.path || '/dialog';
		this.ajax = new Webtec.AjaxObject(this.ajaxAttrs);
		this.formPrototype = Webtec.Form.AjaxForm;

	},
	/*
	create : function($super,attrs){
		attrs = attrs || {};
		
		var action = attrs.action || this.formAttrs.action || this.default_submitForm.bind(this);
		delete attrs.action;
		$super(action,attrs);
	},
	*/
	createContent : function(attrs){
		attrs = attrs || {};
		if($H(attrs).keys().size() == 0){
			attrs = this.attrs || {};
		}
		var action = attrs.action || 'get';
		delete attrs.action;

		var req = {
			action : action,
			form   : this.name,
			args   : attrs,
			successCB : this.displayDialogContent.bind(this),
			failureCB : this.hide.bind(this)
		};
		//this.dialogRequest(req);
		this.ajax.request(req);
		return undefined;//Not created yet
	},
	/*
	dialogRequest : function(req){
		//Change to dialog controller
		req.path = req.path || '/json/dialog';
		this.request(req);
	},
	*/
	displayDialogContent : function(res, transport){
		var scripts = res.dialog.extractScripts();
		//this.dialog.select('.dialog-content').first().update(res.dialog.stripScripts());
		
		//Do buttons first as they are processed during setContent
		if(res.buttons){
			this.buttons = res.buttons;

			$H(this.buttons).each(function(b){
				if(!Object.isUndefined(b.value.action)){
					var tmp;
					eval(" tmp = " + b.value.action);	
					b.value.action = tmp;
				}
			}.bind(this));
		}

		this.setContent(res.dialog.stripScripts());
		scripts.each(function(s){eval(s)});
		if(res.title){
			this.dialog.down('.dialog-header').down('.title').update(res.title);
		}
		if(res.subTitle){
			this.dialog.down('.dialog-header').down('.sub-title').update(res.subTitle);
		}
	}
	/*
	default_submitForm : function(event,attrs){
		var form = this.getForm();
		if(Object.isUndefined(form))
			return this.handleDialogOk(event);

		this.checkAndSubmitForm(form,attrs);
	},
	checkAndSubmitForm : function(form,attrs){
		attrs = attrs || {};
		validate = attrs.validate || this.default_validateForm.bind(this);

		if(validate(form,attrs)){
			this.submitForm(form,attrs);
		}
	},
	default_validateForm : function(form,attrs){
		return true;
	},
	submitForm : function(form,attrs){
		var req = form.serialize(true);
		req.action = attrs.action || req._action || this.formAttrs.action;// || "form-action";
		delete req._action;
		var form_fields = attrs.form_fields || this.formAttrs.form_fields;
		if(Object.isFunction(form_fields))
			form_fields = form_fields(this);
		if(!Object.isUndefined(form_fields)){
			$H(form_fields).each(function(pair){
				req[pair.key] = pair.value;
			});
		}

		var path = form.action;
		if(form.action.indexOf(document.domain) >= 0){
			path = form.action.substr(form.action.indexOf(document.domain)+document.domain.length);
			if(path.match('^:')){
				path = path.substr(path.indexOf('/'));
			}
		}
		if(Object.isUndefined(req.action)){
		 	req.action = path.substr(path.lastIndexOf('/')+1);
		}

		//Strip action from path
		if(path.endsWith(req.action)){
			path = path.substr(0,path.length - req.action.length - 1);
		}
		
		req.path = "/json" + path;
		var onSuccess = attrs.onSuccess || this.formAttrs.onSuccess;
		if(Object.isString(onSuccess)){
			req.onSuccess = onSuccess;
			req.successCB = this.formSubmitSuccess.bind(this,undefined);
		}else{
			req.successCB = this.formSubmitSuccess.bind(this,onSuccess);
		}
		var onFailure = attrs.onSuccess || this.formAttrs.onSuccess;
		if(Object.isString(onFailure)){
			req.onFailure = onFailure
			req.failureCB = this.formSubmitFailure.bind(this,undefined);
		}else{
			req.failureCB = this.formSubmitFailure.bind(this,onFailure);
		}

		this.request(req);
	},
	formSubmitSuccess : function(cb,req,transport){
		if(cb && !cb(req,transport))
			return;
		this.hide();
	},
	formSubmitFailure : function(cb,req,transport){
		if(cb && !cb(req,transport))
			this.hide();
	}
	*/

});



function SendToAFriend(item){
	var attrs = {
		form : {
			form_fields : {item : item},
			ajax : {
	//			msg   : 'Your message has been sent'
			}
		}
	};
	var dialog = Webtec.Dialog.Mgr.createAjaxDialog('sendto',attrs);
	dialog.show();
}



function InitializePage(){

	if(Webtec.postponeInitializePage){
		Webtec.postponeInitializePage--;
		return;
	}

	//Initialize basket Model & UI
	var bc = $('basket-count');
	if(Object.isElement(bc)){
		Webtec.basket.addCallback(function(){
			var bc = $('basket-count');
			bc.update(Webtec.basket.size);
		});
	}
	Webtec.basket.getInfo();

	//Hide elements of init-hidden class and remove class
	$$('.init-hidden').each(function(elem){
		elem.hide();
		elem.removeClassName('init-hidden');
	});

	//Initialize Search
	

	//Autosize text
	$$('.fit-height').each(function(elem){
		var h;
		var v = 0;
		var a = 0;
		$w(elem.className).each(function(c){
			if(c.startsWith("height-")){
				h =  c.substr(7) * 1;
			}
			if(c == "novalign")
				v = 1;
			if(c == "auto_height")
				a = 1;
		});

		fitTextToHeight(elem,h,v,a);	
	});
}


	


Webtec.Search = {};
Webtec.Search.Mgr = Class.singleton({
	initialize : function(){
		this.boxes = $A([]);
		this.boxesByName = $H({});
		this.pe = new PeriodicalExecuter(this.checkSearchBoxes.bind(this),0.5);
	},
	createSearchBox : function(name,input,display,attrs){
		attrs = attrs || {};
		attrs.name = name;
		var box = new Webtec.Search.Box(input,display,attrs);
		this.boxes.push(box)
		this.boxesByName.set(name,box);

		return box;
	},
	checkSearchBoxes : function(pe){
		this.boxes.each(function(box){box.checkSearchString()});
	}
});


Webtec.Search.Box = Class.create(Webtec.AjaxObject,{
	initialize : function($super,input,display,attrs){
		attrs = attrs || {};
		attrs.path = attrs.path || '/search';
		$super(attrs);

		this.name = attrs.name || 'search';
		this.action = attrs.action || 'get';
		this.setupInput(input);
		this.setupDisplayElem(display);

		this.lastSrch = '';
		this.input_initialized = false;
		this.helpAttrs = attrs.help;

	},
	setupDisplayElem : function(elem){
		elem = elem || new Element('div').hide();
		this.display_elem = elem.remove();
		$(document.body).down('div.container').appendChild(elem);
	},
	setupInput 	 : function(elem){
		elem.writeAttribute('autocomplete','off');
		elem.observe('focus',this.initInput.bindAsEventListener(this));
		elem.observe('keydown',this.handleKeyPress.bindAsEventListener(this));
		//srch.observe('blur', function(){new PeriodicalExecuter(function(pe){$('srch-display').hide();pe.stop();},0.3);});
		elem.observe('blur',this.handleBlur.bindAsEventListener(this));
		this.elem = elem;
	},
	initInput : function(){
		this.elem.clear();
		this.input_initialized = true;
		this.elem.removeClassName('init-srch');
	},
	checkSearchString : function(){
		if(!this.input_initialized)
			return;

		if(this.elem.value == this.lastSrch)
			return;

		this.lastSrch = this.elem.value;

		if(this.elem.value.length > 1){
			var attrs = {
				action    : this.action,
				srch 	  : this.elem.value,
				successCB : this.handleSrchSuccess.bind(this),
				failureCB : this.handleSrchFailure.bind(this)
			};
			var req = this.request(attrs);
		}else if(this.elem.value == '?'){
			this.elem.value = '';
			this.toggleHelp();
		}else{
			var disp = this.display_elem;
			disp.update('');
			disp.hide();
			this.selectedItem = undefined;
		}
	},
	processSearchResults : function(results){
		this.results = results;
		//send signal, if we move to MVC
		return this.results;
	},
	setupSearchItem    : function(attrs){
		var li = new Element('li',{'class' : 'srch-type-' + attrs.type}).update(
			new Element('a',{href : attrs.url}).update(attrs.display)
		);
		return li;
	},
	setupSearchDisplay : function(results,ul){
		ul = ul || new Element('ul');
		$A(results).each(function(r){
			var item = this.setupSearchItem(r);
			ul.appendChild(item);
			if(!Object.isUndefined(r.sub)){
				item.appendChild(this.setupSearchDisplay(r.sub));
			}
		}.bind(this));
		return ul;
	},
	handleSrchSuccess : function(response, transport){
		//Clear display
		this.display_elem.update('');
		this.selectedItem = undefined;
		
		if(response.results.size() <= 0){//No results so hide display
			this.display_elem.hide();
		}else{
			this.display_elem.update(
				this.setupSearchDisplay(
					this.processSearchResults(response.results)
				)
			);
			this.display_elem.show();
		}
	},
	handleSrchFailure : function(response, transport){
		this.display_elem.hide();
		this.display_elem.update();
		this.selectedItem = undefined;
	},

	handleBlur : function(event){
		this.display_elem.hide.bind(this.display_elem).delay(0.3);
	},
	handleKeyPress    : function(event){
		var elem = event.element();
		var srch = elem.value;

		var disp = this.display_elem;

		switch(event.keyCode){

			case Event.KEY_RETURN:
				if(Object.isUndefined(this.selectedItem)){
					this.submitForm();
					return;
				}
			case Event.KEY_TAB:
				if(Object.isUndefined(this.selectedItem)){
					return; //Just tab away from control as normal
				}
				var anchor = this.selectedItem.down('a');
				if(!Object.isUndefined(anchor)){
					document.location.href = anchor.href;
				}else{
				//Non link list item
				//Assume not contain ul for now
					elem.up('form').down('input').value = elem.innerHTML
					//elem.up('form').submit();
					this.submitForm();
				}
				Event.stop(event);
				return;			
				break;
			case Event.KEY_ESC:
				disp.innerHTML = "";
				disp.hide();
				this.selectedItem = undefined;
				return;
				break;
			case Event.KEY_DOWN:
				var item = undefined;
				if(Object.isUndefined(this.selectedItem)){
					item = disp.down('li');
					if(Object.isUndefined(item)){
						this.lastSrch = ""; 
					}
				}else{
					var list = disp.select('li');
					var last = undefined;
					list.each(function(li){
						if(last == this.selectedItem){
							item = li;
						}
						last = li;
					}.bind(this));
				}

			//	if(!Object.isUndefined(item)){
					if(!Object.isUndefined(this.selectedItem)){
						var anchor = this.selectedItem.down('a') || this.selectedItem;
						anchor.removeClassName("selected");
					}
					this.selectedItem = item;
					if(!Object.isUndefined(item)){
						item = item.down('a') || item;
						item.addClassName("selected");
					}
			//	}
				Event.stop(event);
				return;
			case Event.KEY_UP:
				var item = undefined;
				var list  = disp.select('li');
				if(Object.isUndefined(this.selectedItem)){
					//item = disp.down('li');
					
					item = list.last();
					if(Object.isUndefined(item)){
						this.lastSrch = ""; 
					}
				}else{
					
					var last = undefined;
					list.each(function(li){
						if(li == this.selectedItem){
							item = last;
						}
						last = li;
					}.bind(this));

				}

			//	if(!Object.isUndefined(item)){
					if(!Object.isUndefined(this.selectedItem)){
						var anchor = this.selectedItem.down('a') || this.selectedItem;
						anchor.removeClassName("selected");
					}
					this.selectedItem = item;
					if(!Object.isUndefined(item)){
						item = item.down('a') || item;
						item.addClassName("selected");
					}
			//	}
				Event.stop(event);
				return;
		}

	},
	toggleHelp 	  : function(){
		Webtec.Help.Mgr.toggleHelpContext(this.name,this.helpAttrs);	
	},
	submitForm : function(){
		if(!this.input_initialized)
			return;
		var form = this.elem.up('form');
		if(Object.isElement(form))
			form.submit();
	}

});

Webtec.Help = {};
//For now a simple 1:1 manager and dialog
Webtec.Help.Mgr = Class.singleton({
	initialize : function(attrs){
		this.context = undefined;
		this.dialog  = undefined;
	},
	getCurrentDisplayContext : function(){
		return this.context;
	},
	hideHelp : function(){
		this.dialog.hide();
	},
	showHelp : function(context,attrs){
		if(this.context != context){
			this.context = context;
			if(Object.isUndefined(this.dialog)){
				attrs = attrs || {};
				attrs.context = this.context;
				this.dialog = new Webtec.Help.Dialog(attrs);
			}else
				this.dialog.setContext(this.context,attrs);
		}
		
		if(!Object.isUndefined(this.dialog))
			this.dialog.show();
	},
	toggleHelpContext : function(context,attrs){
		if(this.context == context){
			if(this.dialog.visible()){	
				this.hideHelp();
			}else{
				this.showHelp(context,attrs);
			}
		}else{
			this.showHelp(context,attrs);
		}
	}

});

Webtec.Help.Dialog = Class.create(Webtec.Dialog.AjaxDialog,{
	initialize : function($super,attrs){
		attrs = attrs || {};
		attrs.path = '/help';

		attrs.title    = attrs.title || 'Help';
		attrs.showOverlay = attrs.showOverlay || false;
		attrs.buttons = attrs.buttons || {ok : 1};
		this.context  = attrs.context;
		
		$super('help',attrs);
	},
	createContent : function($super,attrs){
		attrs = attrs || {};
		attrs.form_fields = attrs.form_fields || {};
		attrs.form_fields.context = attrs.form_fields.context || this.context;
		attrs.action = attrs.action || 'get'; 
		$super(attrs);
	},
	dialogRequest : function(req){//Skip the path change for form fetch
		return this.request(req);
	},
	setContext : function(context,attrs){
		if(this.context == context){
			this.show();
			return;
		}
			
		this.context = context;
		if(attrs.content){
			this.setContent(attrs.content);
		}else{
			this.createContent();
		}
	}
	
});


Webtec.Language = {};
Webtec.Language.SelectBar = Class.create(Webtec.AjaxObject,{
	initialize : function($super,input,attrs){
		attrs = attrs || {};
		attrs.path = "/lang";
		$super(attrs);
		this.elem = input;
		input.observe('change',this.handleChangeLanguage.bindAsEventListener(this));
	},
	handleChangeLanguage : function(event){
		var req = {
			action : 'set',
			language : this.elem.value,
			successCB : this.changeLanguageSuccess.bind(this)
		};
		this.request(req);
	},
	changeLanguageSuccess : function(response){
		//Assume that input has same value as request
		window.location.href = Webtec.Language.languages[this.elem.value].url;
	}

});


Webtec.Control = {};
Webtec.Control.VerticalScrollingListNav = Class.create({
	initialize : function(list,attrs){
		attrs = attrs || {};
		this.list = $(list);
		if(!Object.isElement(this.list))
			throw("not a valid element:" + list);
		this.elem = undefined;
		this.button_height = 28;
		this.waitInitScroll = attrs.waitInitScroll;
	},
	createControl : function(){
		this.elem = Builder.node('div',{id:'nb-type-nav',className:'literature-list'},[
					Builder.node('div',{id:'scroll-up-btn',className:"icon-button button-scroll-up"}),
					Builder.node('div',{className : 'scroll-container'},[
						Builder.node('div',{className : 'outer-container'},[
							Builder.node('div',{id:'lit-image-container',className:'inner-container'}),
						]),
						Builder.node('div',{className:"position-display"})
					]),
					Builder.node('div',{id:'scroll-down-btn',className:"icon-button button-scroll-down"})
				]);

		this.elem.hide();
		document.body.appendChild(this.elem);

		this.elem.down('.button-scroll-down').observe('click',this.handleButtonClick.bindAsEventListener(this,"scrollDown"));
		this.elem.down('.button-scroll-up').observe('click',this.handleButtonClick.bindAsEventListener(this,"scrollUp"));



	},
	getElement : function(){
		if(Object.isUndefined(this.elem))
			this.createControl();
		return this.elem;
	},
	show : function() {
		
		if(Object.isUndefined(this.elem)){
			this.createControl();
		}else if(this.elem.visible()){
			return;//Already showing
		}

		this.list_parent = this.list.up();
		this.elem.down('.inner-container').appendChild(this.list);
		this.elem.show();

		//Should create a event supported function, but for now this should work
		var ev = Prototype.Browser.Gecko ?  'DOMMouseScroll' : 'mousewheel';
		//var ev = window.addEventListener ?  'DOMMouseScroll' : 'mousewheel';

		//Handle Scroll wheel
	//	this.elem.observe(ev,function(){console.log('scroll')});
		/*
		this.elem.select('*').each(
			function(e){
			//	console.log('child scroll');
				e.observe(ev,
				function(err){
					if(this.working)
						return;
					var delta = err.detail ? err.detail : err.wheelDelta / -40;
					delta = delta * -1.0;
			//		console.log("delta = " + delta);
					this.scrollDelta(delta,0);
				}.bind(this));
			}.bind(this));
		*/
		this.elem.observe(ev,function(e){
			if(this.working)
				return;
			var delta = e.detail ? e.detail : e.wheelDelta / -40;
			delta = delta * 10.0;
			this.scrollDelta(delta,0);
		}.bind(this));
	
		
		//Bring selected item into view on nav bar
		var sel = this.elem.down('.selected');
		var off = sel.positionedOffset();
		if(this.waitInitScroll)
			this.pendingInitScroll = off.top;
		else
			this.scrollTo(off.top,0);
	},
	initialScroll : function(){
		if(Object.isUndefined(this.pendingInitScroll))
			return;
		this.scrollTo(this.pendingInitScroll,0);
		delete this.pendingInitScroll;
	},
	hide : function(){
		if(Object.isUndefined(this.elem))
			return;//Not shown yet
		if(!this.elem.visible())
			return;

		this.list_parent.appendChild(this.list);
		this.elem.hide();
	},
	handleButtonClick : function(event,func){
		Event.stop(event);
		if(event.element().hasClassName('disabled'))
			return;

		this[func]();
	},
	setHeight : function(height){
		height = height - 2 * this.button_height;
		var elem = this.elem.down('.outer-container');
		var old = elem.getHeight();
		if(old == height){
			return;
		}
		elem.setStyle({height:height+'px'});
		this.checkScrollControls(old);
	},
	scrollDown  : function(){
		/*
		//var elem = $('lit-image-container');
		var elem = this.elem.down('.inner-container');
		var pos  = elem.getStyle('marginTop') || "0px";
		pos = pos.substring(0,pos.length - 2) * 1;

		var h = elem.up().getHeight();
		var sh = elem.up().scrollHeight;
		var delta = sh - h;// + pos; 
		if(delta <= 0)
			return;
		
		if(delta > (h - 20)){
			delta = h - 20;
		}
		pos = pos - delta;
		new Effect.Morph(elem,{style : {marginTop : pos + 'px'},queue:{position : 'end',scope:'myscroll'},afterFinish : function(effect){this.checkScrollControls()}.bind(this)});
		*/
		var h = this.elem.down('.inner-container').up().getHeight();
		this.scrollDelta(h);
	},
	scrollUp : function(){
	//	if(event.element().hasClassName('disabled'))
	//		return;
		
	//	var elem = $('lit-image-container');
	/*
		var elem = this.elem.down('.inner-container');
		var pos  = elem.getStyle('marginTop') || "0px";
		pos = pos.substring(0,pos.length - 2) * 1;

		if(pos >= 0)
			return;

		var h = elem.up().getHeight();

		delta = -pos;
		
		if(delta > (h - 20)){
			delta = h - 20;
		}
		pos = pos + delta;
		new Effect.Morph(elem,{style : {marginTop : pos + 'px'},queue:{position : 'end',scope:'myscroll'},afterFinish:function(effect){this.checkScrollControls()}.bind(this)});
	*/
		var h = this.elem.down('.inner-container').up().getHeight();
		this.scrollDelta(-h);
	},
	scrollDelta : function (pos,effect){
		var elem = this.elem.down('.inner-container');
		var cur  = elem.up().scrollTop;
		//cur = cur.substring(0,cur.length - 2) * 1;

		this.scrollTo(cur + pos,effect);
	},
	scrollTo : function(pos,effect){
		if(Object.isUndefined(effect))
			effect = 1;
		if(pos < 0)
			pos = 0;

		var elem = this.elem.down('.inner-container');
		var p  = elem.getStyle('scrollTop') || "0px";
		p = p.substring(0,p.length - 2) * 1;

		//var h = p + elem.up().getHeight() - elem.up().scrollHeight;
		/*
		var h = elem.getHeight();
		if(h == 0)//Firefox etc
			h = elem.up().scrollHeight - p;
		h = elem.up().getHeight() - h;
		*/
		h = elem.up().scrollHeight - elem.up().getHeight();

		if(pos > h)
			pos = h;

		var duration = 1.0;
		var delta = Math.abs(p-pos);
		var norm = elem.up().getHeight() - 20;
		if(delta < norm){
			duration = delta/norm;
		}
		effect = 0;
		if(effect){
			this.working = 1;
			new Effect.Morph(elem,{duration : duration,style : {marginTop : pos + 'px'},queue:{position : 'end',scope:'myscroll'},afterFinish:function(effect){this.checkScrollControls()}.bind(this)});
		}else{
			//elem.setStyle({marginTop : pos+'px'});
			elem.up().scrollTop = pos;
			this.checkScrollControls();
		}
	},
	checkScrollControls : function(oldHeight){
		//var elem = $('lit-image-container');
		var elem = this.elem.down('.inner-container');
		var pos  = elem.up().scrollTop || 0;
		//pos = pos.substring(0,pos.length - 2) * 1;
		var h = elem.up().getHeight();

		if(Object.isNumber(oldHeight) && (oldHeight < h)){
			var scr = elem.up().scrollHeight;
			if(pos + h > scr)
				pos = scr - h;
			//pos = pos + oldHeight - h;
			//if (pos < 0)
			//	pos = 0;
			Effect.Queues.get('myscroll').invoke('cancel');
			//elem.setStyle({marginTop : pos + 'px'});
			//new Effect.Morph(elem,{style : {marginTop : pos + 'px'},queue:{position : 'end',scope:'myscroll'}});
			elem.up().scrollTop = pos;
		}

		

		var down = this.elem.down('.button-scroll-down');
		var up = this.elem.down('.button-scroll-up');
		if(pos > 0)
			up.removeClassName('disabled');
		else
			up.addClassName('disabled');

		var sh = elem.up().scrollHeight;
		var delta = sh - h - pos;// + pos; 
		if(delta > 0)
			down.removeClassName('disabled');
		else
			down.addClassName('disabled');
		this.working = 0;


		//Setup position display
		var scr = elem.up().scrollHeight;
		var disp = elem.up('.scroll-container').down('.position-display');
	
		var styles = {};
		styles.height = (h * h / (scr)) + "px";
		styles.top    =  (pos * h  * 1/ (scr)) + "px" ;
		disp.setStyle(styles);
	}

});


Webtec.Control.LiteratureNavBar = Class.create({
	initialize : function(list,object,attrs){
		if(Object.isElement(list))
			this.nav    = new Webtec.Control.VerticalScrollingListNav(list,{waitInitScroll : 1});		
		this.object = $(object);
		if(Object.isUndefined(this.object))
			throw('Not a valid Element ' + object);
		this.img = attrs.img;
		this.href = attrs.href;
		this.logo = attrs.logo;
		this.back_msg = attrs.back_msg||"";

	},
	createControl : function(){
		if(!Object.isUndefined(this.elem))
			return this.elem;

		this.elem = Builder.node('div',{id:'literature-nav-bar'},[
				Builder.node('a',{id:'nb-pg-link',href:this.href},[
					Builder.node('img',{id:'nb-logo',src:this.logo}),
					Builder.node('img',{src:this.img}),
					Builder.node('br'),
					this.back_msg
				]),
			]);
		if(!Object.isUndefined(this.nav)){
			this.elem.appendChild(this.nav.getElement());
		}
		document.body.appendChild(this.elem);
	},
	show : function(){
		if(!Object.isElement($(this.object)))
			return;

		if(Object.isUndefined(this.elem)){
			this.createControl();
		}
		if(!Object.isUndefined(this.nav))
			this.nav.show();
		this.elem.appear({queue:'end'});
		
		$$('html').first().setStyle({overflowY:'hidden'});
		$$('body').first().setStyle({width : 'auto',margin : '0 0 0 85px'});
		$$('.container').first().setStyle({width : '100%'});
		$$('.content-pane').first().setStyle({width : '100%'});

		$$('.header-pane').first().hide();
		$$('.footer-pane').first().hide();
		if(Object.isElement($('left-pane'))){
			$('left-pane').hide();
			$$('.content-pane').first().removeClassName('has-left-pane');
		}
		$$('.content-pane').first().setStyle({position : 'relative'});
		$(this.object).setStyle({
			width:'100%',
			position : 'absolute',
			top : '0px',
			left : '0px'
		});
		$('centre-pane').setStyle({width : '100%', height : '0px',overflow:'hidden'});

		
		this.pe = new PeriodicalExecuter(this.checkPageSize.bind(this),0.2);
	/*	

		if(this.object.visible()){
			var f = function(){
				try{
					this.object.focus();
				}catch(e){
				
				}
			};

			f.bind(this).defer();
		}
	*/
		//Handle getting focus off embedded object and onto something else which doesn't stop mousewheel 
		//events reaching nav bar
		this.nav.elem.select('*').each(
			function(e){
				e.observe('mouseover',function(){
					//Cludge explorer doesn't like the a firefox doesn't like the body
					//this.nav.elem.down('a[href]').focus();
					$('nb-pg-link').focus();
					document.body.focus();
				}.bind(this));
		}.bind(this));
	},
	hide : function(){
		if(Object.isUndefined(this.elem)){
			return;
		}else if(!this.elem.visible()){
			return;
		}
		if(!Object.isUndefined(this.nav))
			this.nav.hide();
		$$('html').first().setStyle({overflowY : ''});
		$$('body').first().setStyle({width : '',margin:''});
		$$('.container').first().setStyle({width : ''});
		$$('.content-pane').first().setStyle({width : ''});
		$$('.header-pane').first().show();
		$$('.footer-pane').first().show();
		$('centre-pane').setStyle({width : '', height : '',overflow:''});
		if(Object.isElement($('left-pane'))){
			$('left-pane').show();
			$$('.content-pane').first().addClassName('has-left-pane');
			
		}
		this.elem.fade({queue:'end'});

		if(!Object.isUndefined(this.pe)){
			this.pe.stop();
			this.pe = undefined;
		}

		if(!Object.isElement(this.object))
			return;

		this.object.setStyle({
			position : 'static'
		});

	},
	togglePageDecoration : function(){
		if(Object.isElement(this.elem) && this.elem.visible()){
			this.hide();
		}else{
			this.show();
		}
	},
	checkPageSize : function(pe){
		var height = document.viewport.getHeight();
		var h = height - 4;
	
		if(this.object.getHeight() != h)
			this.object.setStyle({height : h + 'px'});
		
		if(!Object.isUndefined(this.nav)){
			var elem = this.nav.getElement();
			if(Object.isUndefined(elem))
				return;

			var top = elem.cumulativeOffset().top;
			h = height - top;
			this.nav.setHeight(h);

			if(Object.isNumber(this.nav.pendingInitScroll)){
				this.nav.initialScroll();
			}
		}
	}
});






function fitTextToHeight(elem,height,noVAlign,auto_height){
	elem = $(elem);

	var content = elem.down() || elem;
	var height = height || elem.up().getHeight();

	var size = content.getStyle('font-size');
	var pos = size.search(/\D+$/);
	var ending =  size.substring(pos);
	var size = size.substring(0,pos);


	content.setStyle({paddingTop : '0px',paddingBottom : '0px', height : 'auto'});
	


	var h = content.getHeight();
	while(h > height){
		size = size - 1;
		content.setStyle({'fontSize' : size + ending});
		h = content.getHeight();
	}

	if(Object.isUndefined(auto_height) || ! auto_height)
		content.setStyle({height : ""}); //Clear the auto height style

	if((!Object.isUndefined(noVAlign)) && noVAlign)
		return;

	var t = Math.floor((height - h)/2);
	var b = height - h - t;

	content.setStyle({paddingTop : t + 'px',paddingBottom : b + 'px'});
}


function setupIconBackground(){
	$$('.icon-button[class~=small]').each(function(btn){
		var action = undefined;
		$w(btn.className).each(function(name){
			var i;

			if(name == "icon-button")
				return;
			if((i = name.search('-button')) >= 0){
				if(!Object.isUndefined(action)){
					throw("Button has multple button classes");
				}

				action = name.substr(0,i);
			}
		});
		if(!Object.isUndefined(action))
			btn.setStyle({backgroundImage : "url('/images/icons/" + action + "_small.png')"});
	});
}


Hash.addMethods({
	sortBy1 : function(iterator, sorter, context) {
		return this.map(function(value, index) {
			return {
				value: value,
				criteria: iterator.call(context, value, index)
			};
		}).sort(function(left, right) {
			var a = left.criteria, b = right.criteria;
			return sorter ? sorter(a,b) : (a < b ? -1 : a > b ? 1 : 0);
		}).pluck('value');
	},
	sortForLocale : function(iterator,context){
		if(!Object.isFunction(iterator)){
			var k = iterator;
			iterator = function(item){return item.value[k]}; 
		}
		return this.sortBy1(iterator,function(a,b){return a.toString().localeCompare(b.toString())},context);
	}
});


Array.prototype.sortBy1 = function(iterator, sorter, context) {
	return this.map(function(value, index) {
		return {
			value: value,
			criteria: iterator.call(context, value, index)
		};
	}).sort(function(left, right) {
		var a = left.criteria, b = right.criteria;
		return sorter ? sorter(a,b) : (a < b ? -1 : a > b ? 1 : 0);
	}).pluck('value');
};
Array.prototype.sortForLocale = function(iterator,context){
	if(!Object.isFunction(iterator)){
		var k = iterator;
		iterator = function(item){return item[k]}; 
	}
	return this.sortBy1(iterator,function(a,b){return a.toString().localeCompare(b.toString())},context);
};


	



