/* JLVCL
Library of things
(c) Kieran Martin 2006
Email: kizz32@gmail.com*/

var
	CompDrag, OnStartDrag, OnEndDrag, PixelsPerMM,
	_InputContext, //object to watch events on
	JVCLComponents = new Array(0),
	JVCLClasses = new Array(0),
	JVCLElementKind = new Array(0),
	IE = navigator.userAgent.indexOf('MSIE') > 0,
	KHTML = navigator.userAgent.indexOf('KHTML') > 0,
	Gecko = navigator.userAgent.indexOf('Gecko') > 0;

function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}
 /*
function $(ID){
	if(typeof(ID) == 'string')
		return document.getElementById(ID);
	return ID;
}
 */

function GetInputContext(){
	if(!_InputContext) _InputContext = (IE)? document.body: window;
	return _InputContext;
}
function ResizeElement(Element, Width, Height){
	Element.style.width = Width + 'px'; Element.style.height = Height + 'px';
}

function GetWidth(Element){
	return Element.clientWidth? Element.clientWidth: Element.widthOverride;
}

function GetHeight(Element){
	return Element.clientHeight? Element.clientHeight : Element.heightOverride;
}

function GetX(Element){
	var border = (Element.offsetWidth && Element.clientWidth)? (Element.offsetWidth - Element.clientWidth)/2 : 0;
	return Element.offsetLeft + ((KHTML)? ((border>0)?-border:0): border);
}
function GetY(Element){
	var border = (Element.offsetHeight && Element.clientHeight)? ((Element.offsetHeight - Element.clientHeight)/2) : 0;
	return Element.offsetTop + ((KHTML)? ((border>0)?-border:0): border);
}

function ResolveX(Element){
	var result = 0;
	//Element = Element.offsetNode;
	while(Element && (Element != document.body)){
		result += GetX(Element);
		Element = Element.offsetParent;
	}
	return result;
}

function ResolveY(Element){
	var result = 0;
	//Element = Element.offsetNode;
	while(Element && (Element != document.body)){
		result += GetY(Element);
		Element = Element.offsetParent;
	}
	return (KHTML && (result < 0))? -result : result;
}

function GetEventX(e){ return (e.pageX)? e.pageX : e.clientX + document.body.scrollLeft;}
function GetEventY(e){ return (e.pageY)? e.pageY : e.clientY + document.body.scrollTop;}

function GetEventTarget(e){
	return (typeof e.target != 'undefined')? e.target : (e.srcElement)? e.srcElement : null;
}

function GetEventDest(e){
	return (typeof e.relatedTarget != 'undefined')? e.relatedTarget : (e.toElement)? e.toElement : null;
}

function GetRelativeEventX(Event){ return (typeof(Event.layerX) != 'undefined')? Event.layerX: Event.offsetX;}
function GetRelativeEventY(Event){ return (typeof(Event.layerY) != 'undefined')? Event.layerY: Event.offsetY;}

function CancelEvent(Event){
	if(Event.stopPropagation) Event.stopPropagation();
	if(Event.preventDefault) Event.preventDefault(); Event.cancel = true;
	Event.returnValue = false;
	Event.cancelBubble = true;
	return false;
}

function HideElement(Element){
	if(typeof(Element.style) == 'undefined') return;
	Element.displayMode = (Element.style.display != 'none')? Element.style.display : false;
	Element.style.display = 'none';
	Element.showing = false;
}
function ShowElement(Element){
	if(typeof(Element.style) == 'undefined') return;
	Element.style.display = (Element.displayMode)? Element.displayMode : 'block';
	Element.showing = true;
}

function DescendsFrom(Parent, Child){
	while(Child && (Child != document.body)){
		if(Child === Parent) return true;
		Child = Child.parentNode;
	}
	return false;
}

function EventListen(Element, Event, Listener){
	if(Element.addEventListener){
		Element.addEventListener(Event, Listener, false);
	}else{
		if(Element.attachEvent) Element.attachEvent('on' + Event, Listener);
	}
}

function EventRemove(Element, Event, Listener){
	if(Element.removeEventListener){
		Element.removeEventListener(Event, Listener, false);
	}else{
		if(Element.detachEvent) Element.detachEvent('on' + Event, Listener);
	}
}

function clearSelection(){
	if(window.getSelection){
		var sel = window.getSelection(); 
		if(sel) sel.removeAllRanges();
	}else
		if(document.selection) document.selection.empty();
}

function MoveElement(Element, Left, Top, Bottom, Right){
	if(Left!=-1) Element.style.left = Left + 'px';
	if(Top!=-1) Element.style.top = Top + 'px';
	if(Bottom!=-1) Element.style.bottom = Bottom + 'px';
	if(Right!=-1) Element.style.right = Right + 'px';
}

function GetDockZone(Element){
	while(!Element.dockZone && (Element.parentNode != Element.ownerDocument)){
		Element = Element.parentNode;
	}
	if((Element.parentNode == Element.ownerDocument) && !Element.dockZone) return null;
	return Element;
}

function GetMovable(Element){
	while(!Element.movable && (Element.parentNode != document.body)){
		Element = Element.parentNode;
	}
	if((Element.parentNode == document.body) || !Element.movable) return null;
	return Element;	
}

function FindDock(Docks, X, Y){
	for(var t=0;t<Docks.length;t++){
		var DockX = GetX(Docks[t]);
		if((X > DockX) && (X < DockX + GetWidth(Docks[t]))){
			var DockY = GetY(Docks[t]);
			if((Y > DockY) && (Y < DockY + GetHeight(Docks[t]))) return Docks[t];
		}
	}
}

function DockElement(Element, Into){
	var DockZone = GetDockZone(Into);
	if(!Dockzone) DockZone = Element;
	if(Element.parentNode) Element.parentNode.removeChild(Element);
	DockZone.appendChild(Element);
	ResizeElement(Element, GetWidth(Element), GetHeight(Element));
	if(Into.onDockedInto) Into.onDockedInto(Element);
	if(Element.onDock) Element.onDock(Info);
}

var StartX, StartY, ElementX, ElementY;

function _MovOnMouse(event){
	if(!event) event = window.event;
	clearSelection();
	MoveElement(CompDrag, ElementX + (GetEventX(event) - StartX), ElementY + (GetEventY(event) - StartY), -1, -1);
	return true;
}

function _EndMovOnMouse(event){
	if(!event) event = window.event;
	var InputContext = GetInputContext();
	EventRemove(InputContext, 'mousemove', _MovOnMouse);
	EventRemove(InputContext, 'mouseup', _EndMovOnMouse);
	if(OnEndDrag && (OnEndDrag(Element) === false)) return;
	if(CompDrag.onEndDrag) CompDrag.onEndDrag(CompDrag, event);
	Movable = null;
}

function StartMovingElement(event, Element, MoveOther, Origin){
	if(!event) event = window.event;
	
	var Movable = (MoveOther)? MoveOther : GetMovable(Element);
	if(!Movable){
		Movable = Element;
		WndSubX = (Origin)? GetX(Origin) : 0;
		WndSubY = (Origin)? GetY(Origin) : 0;
	}else{
		WndSubX = GetX(Movable);
		WndSubY = GetY(Movable);
	}
	if(OnStartDrag && (OnStartDrag(Element) === false)) return;
	
	ElementX = GetX(Element);
	ElementY = GetY(Element);
	
	StartX = GetRelativeEventX(event);
	StartY = GetRelativeEventY(event);
	
	CompDrag = Movable;
	var InputContext = GetInputContext();
	EventListen(InputContext, 'mousemove', _MovOnMouse);
	EventListen(InputContext, 'mouseup', _EndMovOnMouse);
}

function AppendElement(elementKind, parent, before, className, doAppend){
	var result = document.createElement(elementKind);
	if(!parent) parent = document.body;
	if(className) result.className = className;
	
	if((typeof(before) != 'undefined') && (!doAppend))
		parent.insertBefore(result, before)
	else
		parent.appendChild(result);
			
	return result;
}

function AppendText(element, text){
	var textnode = document.createTextNode(text);
	element.appendChild(textnode);
	return textnode;
}

function AppendInput(parent, inputKind, before){
	var result = document.createElement('input');
	result.type = inputKind;
	if(!parent) parent = document.body;
	if(typeof(before) != 'undefined')
	parent.insertBefore(result, before)
	else
		parent.appendChild(result);
	return result;
}

function getHead(){
	if(!document.head){
		document.head = document.getElementsByTagName('head')[0];
	}
	return document.head;
}

function AppendStyleSheet(URL){
	var CSS = document.createElement('link');
	CSS.rel = 'stylesheet';
	CSS.href = URL;
	CSS.type = 'text/css';
	getHead().appendChild(CSS);
}

function AppendScript(URL){
	var Script = document.createElement('script');
	Script.type = 'text/javascript';
	Script.src = URL;
	getHead().appendChild(Script);
}

function JLVCLComputeLocation(element, exp){
	var parentNode = element.parentNode;
	var widthMM = GetWidth(element)/PixelsPerMM;
	var heightMM = GetHeight(element)/PixelsPerMM;
	var leftMM = GetX(element)/PixelsPerMM;
	var topMM = GetY(element)/PixelsPerMM;
	parentNode.widthMM = GetWidth(parentNode)/PixelsPerMM;
	parentNode.heightMM = GetHeight(parentNode)/PixelsPerMM;
	parentNode.leftMM = GetX(parentNode)/PixelsPerMM;
	parentNode.topMM = GetY(parentNode)/PixelsPerMM;
	return eval(exp);
}

function CreateJLVCLObject(parent, VCLObject, idprefix, idspace){
	var elementKind = (VCLObject.el)? VCLObject.el : (JVCLElementKind[VCLObject.construct])? JVCLElementKind[VCLObject.construct] : 'div';
	var result = AppendElement(elementKind, parent);
	
	result.className = '';
	
	if(VCLObject.id)
		result.id = ((idprefix)? idprefix : '') + VCLObject.id;
	
	parent[result.id] = result;
	if(idspace)
		idspace[result.id] = result;
	
	if (parent.childClass)
		result.className += ' ' + parent.childClass;
	
	if(VCLObject.construct){
		if(JVCLComponents[VCLObject.construct])
			JVCLComponents[VCLObject.construct](result, VCLObject);
		
		if(JVCLClasses[VCLObject.construct] && (result.className.indexOf(JVCLClasses[VCLObject.construct]) == -1))
			if(result.className)
				result.className += ' ' + JVCLClasses[VCLObject.construct]
			else
				result.className = JVCLClasses[VCLObject.construct];
	}
	
	if(VCLObject.Class)
		result.className += ' ' + VCLObject.Class;

	if(VCLObject.tag)
		result.tag = VCLObject.tag;

	if(VCLObject.caption && !VCLObject.noCaption)
		result.text = AppendText(result, VCLObject.caption);
	
	if(VCLObject.idprefex) idprefix = idprefix + VCLObject.idprefix;
		
	if(VCLObject.movable === true) result.movable = true;
	if(VCLObject.dockZone === true) result.dockZone = true;
	
	//position according to expressions
	if(VCLObject.widthExp){
		result.style.width = JLVCLComputeLocation(result, VCLObject.widthExp);
		result.widthOverride = Math.round(parseInt(result.style.width)*PixelsPerMM);
	}
	
	if(VCLObject.heightExp){
		result.style.height = JLVCLComputeLocation(result, VCLObject.heightExp);
		result.heightOverride = Math.round(parseInt(result.style.height)*PixelsPerMM);
	}
		
	if(VCLObject.leftExp){
		result.style.left = JLVCLComputeLocation(result, VCLObject.leftExp);
		result.leftOverride = Math.round(parseInt(result.style.left)*PixelsPerMM);
	}
	
	if(VCLObject.topExp){
		result.style.top = JLVCLComputeLocation(result, VCLObject.topExp);
		result.topOverride = Math.round(parseInt(result.style.top)*PixelsPerMM);
	}
	
	if(VCLObject.children)
		for(var t=0;t<VCLObject.children.length;t++)
			CreateJLVCLObject(result, VCLObject.children[t], idprefix, idspace? idspace: result);
	
	return result;
}

function NullConstructor(Element, JSONObject){}

function RemoveElement(element){element.parentNode.removeChild(element);}

function GetChildByProperty(parent, property, match, recursive){
	for(var t=0;t<parent.childNodes.length;t++)
		if((typeof(parent.childNodes[t][property]) != 'undefined') && (parent.childNodes[t][property] == match)) return parent.childNodes[t];
		
	
	if(recursive)
		for(var t=0;t<parent.childNodes.length;t++){
			var result = GetChildByProperty(parent.childNodes[t], property, match, true);
			if(result) return result;
		}
		
	return false;
}

function GetChildByClass(parent, className, recursive){
	for(var t=0;t<parent.childNodes.length;t++){
		var eClassName = parent.childNodes[t].className;
		if(eClassName){
			var offset = eClassName.indexOf(className);
			if(offset >= 0){
				if((offset + className.length) >= eClassName.length) return parent.childNodes[t];
				if(eClassName.charCodeAt(offset+className.length) == 32) return parent.childNodes[t];
			}
		 }
	}
	
	if(recursive)
		for(var t=0;t<parent.childNodes.length;t++){
			var result = GetChildByClass(parent.childNodes[t], className, true);
			if(result) return result;
		}
		
	return false;
}

function GetChildrenByClass(parent, className, results, recursive){
	for(var t=0;t<parent.childNodes.length;t++){
		var eClassName = parent.childNodes[t].className;
		if(eClassName){
			var offset = eClassName.indexOf(className);
			if(offset >= 0){
				if((offset + className.length) >= eClassName.length){
					results.push(parent.childNodes[t]);
					continue;	
				}
				if(eClassName.charCodeAt(offset+className.length) == 32) results.push(parent.childNodes[t]);
			}
		 }
	}
	
	if(recursive)
		for(var t=0;t<parent.childNodes.length;t++)
			GetChildrenByClass(parent.childNodes[t], className, results, true);
}

function GetParentByProperty(parent, property, match){
	while(parent){
		if(typeof(parent[property]) != 'undefined')
			if((typeof(match) == 'undefined')||(match == parent[property])) return parent;
		parent = parent.parentNode;
	}
}

function GetParentWithClass(item, className){
	while(item){
		item = item.parentNode;
		if(!item) break;
		var eClassName = item.className;
		if(eClassName){
			var offset = eClassName.indexOf(className);
			if(offset >= 0){
				if((offset + className.length) >= eClassName.length) return item;
				if(eClassName.charCodeAt(offset+className.length) == 32) return item;
			}
		 }
	}
}

function getStyle(oElm, strCssRule){
	if(document.defaultView && document.defaultView.getComputedStyle){
		return document.defaultView.getComputedStyle(oElm, '').getPropertyValue(strCssRule);
	}else if(window.getComputedStyle){
		return window.getComputedStyle(oElm, '').getPropertyValue(strCssRule);
	}else if(oElm.currentStyle){
		strCssRule = strCssRule.replace(/-(w)/g, function (strMatch, p1){
			return p1.toUpperCase();
		});
		return oElm.currentStyle[strCssRule];
	}
	return '';
}

function GetEventKeyPress(event){
	return (event.charCode)? event.charCode : event.keyCode;
}

function ApplyKeyPressToStr(event, str){
	var key = GetEventKeyPress(event);
	switch(key){
		case 8:{
			if(str == '') return '';
			return str.substr(0, str.length-1);
		}
		default:
			return str + String.fromCharCode(key);
	}
}

//get object property
function prop(obj, field, def){
	if(typeof(obj[field]) == 'undefined') return def;
	return obj[field];
}

//create DOM node from JSON node
function $e(params){
	var nodeName = prop(params, 'nodeName', 'div'); params.nodeName = false;
	var parent = prop(params, 'parentNode', document.body); params.parentNode = false;
	var style = prop(params, 'style', null); params.style = false;

	var result = document.createElement(nodeName);
	
	for(var t in params)
		if(params[t]) result[t] = params[t];
	
	for(var t in style)
		if(style[t]) result.style[t] = style[t];
	
	parent.appendChild(result);
	return result;
}

function dupChildren(from, to){
	var children = from.childNodes;
	for(var t=0;t<children.length;t++){
		var clone = children[t].cloneNode(true);
		to.appendChild(clone);
	}
}

function propertyArray(Objects, prop){
	var result = new Array();
	for(var t=0;t<Objects.length;t++)
		if(typeof(Objects[t][prop]) != 'undefined')
			result.push(Objects[t][prop]);
	return result;
}

function parentWithProperty(object, property){
	while(object && (typeof(object[property]) == 'undefined')) object = object.parentNode;
	return object;
}

function templateInto(text, values){
	for(variable in values)
		text = text.replace(new RegExp('@' + variable, 'gi'), values[variable]);
	return text;
}