
var is_opera = /opera/.test(navigator.userAgent.toLowerCase());

// drag
var drag_current_obj = null;
var drag_current_event = null;
var drag_mouse_down = false;
var drag_lastMouseX = 0;
var drag_lastMouseY = 0;
var drag_maxMouseX = 0;
var drag_maxMouseY = 0;
var drag_minMouseX = 0;
var drag_minMouseY = 0;

// border
var border_last = '';
var corner_last = '';

var highestZindex = 0;

Array.prototype.toString = function () {
	result = "";
	for (i=0;i<this.length;i++) {
		result += this[i] +", ";
	}
	if (result !== "") {
		result = result.slice(0, -2);
	}	return result;
};

/***************************************************************
            DECLARE FUNCTIONS
****************************************************************/

/**
 * Creates IFrame for receiving data
 */
function getIFrame() {
	doc = document.getElementById('ifr_loader');
	if (!doc) {
		var div = document.createElement('div');
		div.innerHTML = '<iframe style="display:none" src="about:blank" id="ifr_loader" name="ifr_loader" onload="sendComplete(\'ifr_loader\')"></iframe>';
		document.body.appendChild(div);
		doc = document.getElementById('ifr_loader');
	}
	return doc;
}

function getForm(data) {
	doc = document.getElementById('form_sender');
	if (!doc) {
		var frm = document.createElement("form");
		frm.id = 'form_sender';
		frm.name = 'form_sender';
		frm.method = "post";
		frm.enctype = "multipart/form-data";
frm.target = 'ifr_loader'; //!!!
		frm.action = SERVER_URL;
		document.body.appendChild(frm);
		doc = document.getElementById('form_sender');
		dataField = document.createElement("div");
		dataField.innerHTML = '<input type="hidden" name="datafield" value="'+data+'">';
		doc.appendChild(dataField);
	}
	return doc;
}

/**
 * send form with data
 * @data - a string to send
 * @func - call back function, called when answer received
 */
function sendForm(data, func) {
	if (!document.createElement) return; // not supported
	if (typeof(form)=="string") form = document.getElementById(form);
    var frame = getIFrame();
	var form = getForm(data);
	frame.onSendComplete = function() { func(getIFrameXML(frame)); };
//	form.setAttribute('target', frame.id);
	form.submit();
	document.body.removeChild(form);
}

/**
 * function linked to onload even of IFrame
 */
function sendComplete(id) {
	var iframe=document.getElementById(id);
	if (iframe.onSendComplete && typeof(iframe.onSendComplete) == 'function') iframe.onSendComplete();
}

/**
 * returns a reference to received document
 */
function getIFrameXML(iframe) {
	//var doc = iframe.contentWindow.document;
	var doc = iframe.contentDocument;
	if (!doc && iframe.contentWindow) doc = iframe.contentWindow.document;
	if (!doc) doc=window.frames[iframe.id].document;
	if (!doc) return null;
	if (doc.location=="about:blank") return null;
	if (doc.XMLDocument) doc = doc.XMLDocument;
	return doc;
}

/**
 * binds a function to context object
 * used for sending a DOM element as a context to event function
 */
function bind (obj, func){
	return function(){return func.apply(obj, arguments)}
};

/**
 * Alerts the properties of the given object (for debug)
 */
function show_props(obj, count)
{
	if (obj == null) {
		alert('show_props: the object is null');
        return;
	} else {
		var result = "";
		var cnt = 1;
		var num = 1;
		count = count || -1;
		for (var i in obj) {
			result += num+". "+i + " = " + obj[i] + "\n";
			cnt++;
			num++;
			if (cnt == count) {
				alert(result);
				cnt = 1;
				result = "";
			}
		}
		if (result != "") alert(result);
	}
};

/**
 * vdomRegisterEventListener
 * attaches an event listener function to DOM object
 * @vdomObject      reference to a DOM object
 * @eventType       string, representing an event(onload, onmousedown, etc)
 * @eventListener   function to be attached
 * @useCapture      events must be captured at descending phase
 */
function vdomRegisterEventListener(vdomObject, eventType, eventListener, useCapture)
{
    dom_obj = vdomObject.domCont;
	eventType = eventType.toLowerCase();

    if (is_opera) { //opera
        dom_obj.addEventListener(eventType, bind(vdomObject, eventListener), false);
    } else if (dom_obj.attachEvent) { //ie
		dom_obj.attachEvent('on'+eventType, bind(vdomObject, eventListener));
    } else if (dom_obj.addEventListener) { //true browsers
		dom_obj.addEventListener(eventType, bind(vdomObject, eventListener), useCapture);
	}
}

/***************************************************************
            DECLARE CLASSES
****************************************************************/

/**
 * VDOM_EventLink declaration
 */
function VDOM_EventLink(evtSrc, actTgt)
{
	this.eventSrc = evtSrc;
	this.actionTgt = actTgt;
}

/**
 * VDOM_EventDispatcher declaration
 */
function VDOM_EventDispatcher()
{
	this.eventArray = new Array();
}

VDOM_EventDispatcher.prototype.addDispatchEvent = function(eventSrc, actionTgt) {
  //eventSrc must be in ":" notation like objectname:eventname - (i.e vdomobj1:mouseup)
  //actionTgt must be in ":" notation also
	for (var i=0;i<this.eventArray.length;i++) {
		if (this.eventArray[i].eventSrc == eventSrc && this.eventArray[i].actionTgt == actionTgt) {
			return;
		}
	}
	var evtLink = new VDOM_EventLink(eventSrc, actionTgt);
	this.eventArray.push(evtLink);
}

//Puts all the actions, associated with the given eventSrc into actList array
VDOM_EventDispatcher.prototype.getActionList = function(eventSrc, actList) {
	for (var i=0;i<this.eventArray.length;i++) {
		if (this.eventArray[i].eventSrc == eventSrc) {
			actList.push(this.eventArray[i].actionTgt);
		}
	}
}

/**
 * VDOM_EventEngine declaration
 */
function VDOM_EventEngine(ADispatcher, AQueue)
{
	this.eventDispatcher = ADispatcher;
	this.Active = false;
	this.EvtQueue = AQueue;
}
VDOM_EventEngine.prototype.start = function() {
	this.Active = true;
}
VDOM_EventEngine.prototype.stop = function() {
	this.Active = false;
}
VDOM_EventEngine.prototype.sendToServer = function(evnt) {
	//evnt - VDOM_event object
	if (!this.Active) return false;
	if (!this.EvtQueue) return false;
	this.EvtQueue.addEvent(evnt);
}

VDOM_EventEngine.prototype.parseParams = function(vdomEvent, paramStr, paramArray) {
	if (paramStr == "") return ;
	if (paramStr == "()") return ;
	paramStr = paramStr.replace(/^\(/g, "");
	paramStr = paramStr.replace(/\)$/g, "");
	tempArray = paramStr.split(',');
	for (i=0;i<tempArray.length;i++) {
		cur_param = tempArray[i]
		cur_param = cur_param.replace(/^\s+|\s+$/g, "");//trim spaces
		evt_param = function (param_name) {
			if (param_name == "evt_name") {
				return vdomEvent.name;
			} else if (param_name == "evt_src") {
				return vdomEvent.srcObj;
			} else if (param_name == "evt_ref") {
				return vdomEvent;
			} else {
				return vdomEvent.paramByName(param_name);
			}
		};
        if (cur_param != '()') {
    		paramArray.push(eval(cur_param));
        }
	}
}

VDOM_EventEngine.prototype.executeAction = function(act_str, evnt) {
	//act_str = action string in ":" notation from dispatcher, like object:action(params)
	//evnt - VDOM_event object
    if (!this.Active) return false;
//	re = /^(\w+):(\w+)\(([^\$]*)\)$/g;
//	var re = /^(\w+):(\w+)\((.*)\)$/g;
    var re = new RegExp("^(\\w+):(\\w+)\((.*)\)$","g");
    if (matchArray = re.exec(act_str)) {
		vdomObj = eval(matchArray[1]);
		if (vdomObj == null) {
//			alert("Object '"+matchArray[1]+"' does not exist !");
            generateErrorEvent("Object '"+matchArray[1]+"' does not exist !");
			return;
		}
		actName = matchArray[2];
		var params = new Array();
        this.parseParams(evnt, matchArray[3], params);
		//executing action with parsed params
        vdomObj[actName].apply(vdomObj, params);
	} else {
//		alert("Invalid action name: "+act_str);
        generateErrorEvent("Invalid action name: "+act_str);
		return ;
	}
}

VDOM_EventEngine.prototype.processEvent = function(evnt) {
	//evnt has type of VDOM_Event
	if (!this.Active) return false;
    var actList = new Array();
	this.eventDispatcher.getActionList(evnt.getEventStr(), actList);
    for (var i=0;i<actList.length;i++) {
		act_str = actList[i];
drag_current_event = evnt;
        switch(act_str) {
			case "server":
				this.sendToServer(evnt);
				break;
			default :
				this.executeAction(act_str, evnt);
				break;
		}
	}
}

/**
 * VDOM_Event declaration
 */
function VDOM_Event()
{
	this.srcObj = "";           		//Field contains a reference to DOM object (not id)
	this.name = "";            			//Field contains a string - name of event
	this.parameters = new Array();  //Obviously this is array of parameters
}

VDOM_Event.prototype.addParameter = function(name, value) {
	var param = new VDOM_Param(name, value);
	this.parameters.push(param);
}
VDOM_Event.prototype.getEventStr = function() {
	var a = this.srcObj.id + ':'+this.name; //so we return a name of event in ":" notation,
	return a;                               //event dispatcher should store events in this notation
}
VDOM_Event.prototype.paramByName = function (AName) {
	for (var i=0;i<this.parameters.length;i++){
		if (this.parameters[i].Name == AName) {
			return this.parameters[i].Value;
		}
	}
	return null;
}

/**
 * VDOM_Param declaration
 */
function VDOM_Param(name, value)
{
	this.Name = name;
	this.Value = value;
}

/**
 * VDOM_Object declaration
 */
function VDOM_Object(contId, eventEngine)
{
	var domElement = document.getElementById(contId); //Searching for DOM elemnt by id
	if (domElement != null) {
		this.domCont = domElement;
		this.eventEngine = eventEngine;
		this.name = contId;
		this.evtAssociation = new Array();
		this.evtAssociation['mousemove'] = {evtname:'mousemove', evtfunc:this.mousemove, evttyp:'mousemove'};
		this.evtAssociation['mousedown'] = {evtname:'mousedown', evtfunc:this.mousedown, evttyp:'mousedown'};
		this.evtAssociation['mouseup'] = {evtname:'mouseup', evtfunc:this.mouseup, evttyp:'mouseup'};
		this.evtAssociation['mouseover'] = {evtname:'mouseover', evtfunc:this.mouseover, evttyp:'mouseover'};
		this.evtAssociation['mouseout'] = {evtname:'mouseout', evtfunc:this.mouseout, evttyp:'mouseout'};
		this.evtAssociation['click'] = {evtname:'click', evtfunc:this.click, evttyp:'click'};
		this.evtAssociation['dblclick'] = {evtname:'dblclick', evtfunc:this.dblclick, evttyp:'dblclick'};
		this.evtAssociation['keydown'] = {evtname:'keydown', evtfunc:this.keydown, evttyp:'keydown'};
		this.evtAssociation['keyup'] = {evtname:'keyup', evtfunc:this.keyup, evttyp:'keyup'};
		this.evtAssociation['keypress'] = {evtname:'keypress', evtfunc:this.keypress, evttyp:'keypress'};
		this.evtAssociation['ctrlclick'] = {evtname:'ctrlclick', evtfunc:this.ctrlclick, evttyp:'click'};
		this.evtAssociation['border'] = {evtname:'border', evtfunc:this.border, evttyp:'mousemove'};
		this.evtAssociation['corner'] = {evtname:'corner', evtfunc:this.border, evttyp:'mousemove'};
		this.evtAssociation['dragstart'] = {evtname:'dragstart', evtfunc:this.mousemove, evttyp:'mousemove'};
		this.evtAssociation['dragstop'] = {evtname:'dragstop', evtfunc:this.mouseup, evttyp:'mouseup'};
		this.evtAssociation['change'] = {evtname:'change', evtfunc:this.change, evttyp:'change'};
		this.evtAssociation['changecolor'] = {evtname:'change', evtfunc:this.change, evttyp:'change'};
		this.evtAssociation['select'] = {evtname:'select', evtfunc:this.change, evttyp:'change'};
		this.evtAssociation['unselect'] = {evtname:'unselect', evtfunc:this.change, evttyp:'change'};
		this.evtAssociation['valuechange'] = {evtname:'valuechange', evtfunc:this.change, evttyp:'change'};
		this.evtAssociation['timechange'] = {evtname:'timechange', evtfunc:this.timechange, evttyp:'change'};
		this.evtAssociation['load'] = {evtname:'load', evtfunc:this.timechange, evttyp:'change'};
	}
}

/**
 * execEvent function prototype
 */
VDOM_Object.prototype.execEvent = function(evnt) {
    if (this.eventEngine != null) {
		this.eventEngine.processEvent(evnt, this);
	} else {
		window.status = 'ERROR['+this.name + '.'+evnt.name+']: eventEngine - bad object reference';
	}
}

function defPosition(event) {
    var x = y = 0;
    if (document.attachEvent != null) { // ie & Opera
        x = window.event.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
        y = window.event.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
    } else if (!document.attachEvent && document.addEventListener) { // Gecko
        x = event.clientX + window.scrollX;
        y = event.clientY + window.scrollY;
    } else {
    }
    return {x:x, y:y};
}

//Mouse move event prototype
VDOM_Object.prototype.timechange = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'timechange';
    var t = new Date;
	vdomEvent.addParameter('time', t);
	this.execEvent(vdomEvent);
}

//Mouse move event prototype
VDOM_Object.prototype.mousemove = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'mousemove';
    var x = evt.layerX ? evt.layerX : evt.offsetX;
    var y = evt.layerY ? evt.layerY : evt.offsetY;
	vdomEvent.addParameter('x', x);
	vdomEvent.addParameter('y', y);
	this.execEvent(vdomEvent);

    // drag
    if (drag_current_obj != null && drag_mouse_down == true) {
        drag_current_event = evt;
    }
}

// Mouse down event prototype
VDOM_Object.prototype.mousedown = function(evnt) {
	var evt = evnt || window.event;
    var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'mousedown';
    var x = evt.layerX ? evt.layerX : evt.offsetX;
    var y = evt.layerY ? evt.layerY : evt.offsetY;
	vdomEvent.addParameter('x', x);
	vdomEvent.addParameter('y', y);
	vdomEvent.addParameter('button', evt.button);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);

    drag_current_event = evt;
}

// Mouse up event prototype
VDOM_Object.prototype.mouseup = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'mouseup';
    var x = evt.layerX ? evt.layerX : evt.offsetX;
    var y = evt.layerY ? evt.layerY : evt.offsetY;
	vdomEvent.addParameter('x', x);
	vdomEvent.addParameter('y', y);
	vdomEvent.addParameter('button', evt.button);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);

    drag_mouse_down = false;
}

// Mouse over event prototype
VDOM_Object.prototype.mouseover = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;;
	vdomEvent.name = 'mouseover';
	vdomEvent.addParameter('x', evt.layerX ? evt.layerX : evt.offsetX);
	vdomEvent.addParameter('y', evt.layerY ? evt.layerY : evt.offsetY);
	this.execEvent(vdomEvent);
}
// Mouse out event prototype
VDOM_Object.prototype.mouseout = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'mouseout';
	vdomEvent.addParameter('x', evt.layerX ? evt.layerX : evt.offsetX);
	vdomEvent.addParameter('y', evt.layerY ? evt.layerY : evt.offsetY);
	this.execEvent(vdomEvent);
}
// Click event prototype
VDOM_Object.prototype.click = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'click';
	vdomEvent.addParameter('x', evt.layerX ? evt.layerX : evt.offsetX);
	vdomEvent.addParameter('y', evt.layerY ? evt.layerY : evt.offsetY);
	vdomEvent.addParameter('button', evt.button);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);
}
// Double click event prototype
VDOM_Object.prototype.dblclick = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'dblclick';
	vdomEvent.addParameter('x', evt.layerX ? evt.layerX : evt.offsetX);
	vdomEvent.addParameter('y', evt.layerY ? evt.layerY : evt.offsetY);
	vdomEvent.addParameter('button', evt.button);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);
}
// key down event prototype
VDOM_Object.prototype.keydown = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'keydown';
	vdomEvent.addParameter('keyCode', evt.keyCode);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);
}
// key up event prototype
VDOM_Object.prototype.keyup = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'keyup';
	vdomEvent.addParameter('keyCode', evt.keyCode);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);
}
// key press event prototype
VDOM_Object.prototype.keypress = function(evnt) {
    var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'keypress';
	vdomEvent.addParameter('keyCode', evt.keyCode);
	vdomEvent.addParameter('altKey', evt.altKey);
	vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
	vdomEvent.addParameter('shiftKey', evt.shiftKey);
	this.execEvent(vdomEvent);
}

// change (input, select, textarea) event prototype
VDOM_Object.prototype.change = function(evnt) {
    var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
	vdomEvent.srcObj = this.domCont;
	vdomEvent.name = 'change';
	this.execEvent(vdomEvent);
    if (this.domCont.firstChild && this.domCont.firstChild.type == 'checkbox') {
    	var vdomEvent = new VDOM_Event();
    	vdomEvent.srcObj = this.domCont;
    	vdomEvent.name = this.domCont.firstChild.checked ? 'select' : 'unselect';
    	this.execEvent(vdomEvent);
    } else
    if (this.domCont.tagName == 'SELECT') {
    	var vdomEvent = new VDOM_Event();
    	vdomEvent.srcObj = this.domCont;
    	vdomEvent.name = 'valuechange';
    	vdomEvent.addParameter('item', '');                               //!!
    	vdomEvent.addParameter('itemValue', this.domCont.value);
    	this.execEvent(vdomEvent);
    } else {
    	var vdomEvent = new VDOM_Event();
    	vdomEvent.srcObj = this.domCont;
    	vdomEvent.name = 'valuechange';
    	vdomEvent.addParameter('itemValue', this.domCont.value);
    	this.execEvent(vdomEvent);
    }
}

//CUSTOM EVENTS

//control+click event
VDOM_Object.prototype.ctrlclick = function(evnt) {
	var evt = evnt || window.event;
	if (evt.ctrlKey == 1) {
    	var vdomEvent = new VDOM_Event();
		vdomEvent.srcObj = this.domCont;
		vdomEvent.name = 'ctrlclick';
		vdomEvent.addParameter('x', evt.layerX ? evt.layerX : evt.offsetX);
		vdomEvent.addParameter('y', evt.layerY ? evt.layerY : evt.offsetY);
		vdomEvent.addParameter('keyCode', evt.keyCode);
		vdomEvent.addParameter('altKey', evt.altKey);
		vdomEvent.addParameter('ctrlKey', evt.ctrlKey);
		vdomEvent.addParameter('shiftKey', evt.shiftKey);
		this.execEvent(vdomEvent);
	}
}

//border event
VDOM_Object.prototype.border = function(evnt) {
	var evt = evnt || window.event;
	var vdomEvent = new VDOM_Event();
    vdomEvent.srcObj = this.domCont;
    var x = evt.layerX ? evt.layerX : evt.offsetX;
    var y = evt.layerY ? evt.layerY : evt.offsetY;
    var right  = (x <= this.domCont.clientWidth) && (x > this.domCont.clientWidth - 4);
    var left   = (x >= 0) && (x < 4);
    var top    = (y >= 0) && (y < 4);
    var bottom = (y <= this.domCont.clientHeight) && (y > this.domCont.clientHeight - 4);
    if (top || bottom || left || right) {
        var corner1 = left && top;
        var corner2 = right && top;
        var corner3 = right && bottom;
        var corner4 = left && bottom;
        if (corner1 || corner2 || corner3 || corner4) {
            pos = corner1 ? 1 : (corner2 ? 2 : (corner3 ? 3 : (corner4 ? 4 : 0)));
            if (pos > 0) {
                if (corner_last != pos) {
                    corner_last = pos;
                    vdomEvent.name = 'corner';
                    vdomEvent.addParameter('pos', pos);
                    vdomEvent.addParameter('x', x);
                    vdomEvent.addParameter('y', y);
                    this.execEvent(vdomEvent);
                }
            }
        } else {
            pos = right ? 'right' : (left ? 'left' : (top ? 'top' : (bottom ? 'bottom' : '')));
            if (pos != '' && border_last != pos) {
                border_last = pos;
                vdomEvent.name = 'border';
                vdomEvent.addParameter('pos', pos);
                vdomEvent.addParameter('x', x);
                vdomEvent.addParameter('y', y);
                this.execEvent(vdomEvent);
            }
        }
    }
}


VDOM_Object.prototype.riseEvent = function(evtName, evtParams, evntEngine) {
	var newEvent = new VDOM_Event();
	newEvent.srcObj = this.domCont;
	newEvent.name = evtName;
	for (var i=0;i<evtParams.length;i++) {
		newEvent.addParameter(evtParams[i].Name, evtParams[i].Value);
	};
	evntEngine.processEvent(newEvent);
}

/**
 * registerEvents procedure prototype
 */
VDOM_Object.prototype.registerEvents = function(eventSupported) {
	for (var i=0;i<eventSupported.length;i++) {
		var evtname = eventSupported[i];
        if (this.evtAssociation === undefined) {
//console.info('evtAssociation is undefined! (evtname='+evtname+', obj='+this.name+')');
        } else {
            if (this.evtAssociation[evtname] === undefined) {
//console.info('Event "'+evtname+'" is undefined!');
            } else {
                var evtObj = this.evtAssociation[evtname];
                if (typeof(evtObj) == "object") {
                    vdomRegisterEventListener(this, evtObj.evttyp, evtObj.evtfunc, true);
                }
            }
        }
	}
}

/**
 * VDOM_EventQueue declaration
 */

function VDOM_EventQueue() {
	this.eventQueue = new Array();
	this.sendAvailable = true; // Shows if the queue is ready to send events
}

VDOM_EventQueue.prototype.serialize = function() {
	if (this.eventQueue.length == 0) return "";
    var resultStr = "<EVENTS><APPLICATION ID='"+APPLICATION_ID+"'/><SESSION ID='"+SESSION_ID+"'/>";
	for (var i=0;i<this.eventQueue.length;i++) {
		var evnt = this.eventQueue[i];
		var str = "<EVENT objSrcID='"+evnt.srcObj.id+"' name='"+evnt.name+"'>";
		for (var j=0;j<evnt.parameters.length;j++) {
			var param = evnt.parameters[j];
			str += "<PARAMETER name='"+param.Name+"'>"+param.Value+"</PARAMETER>";
		}
		str+="</EVENT>";
		resultStr += str;
	}
	resultStr += "</EVENTS>";
	this.eventQueue.length = 0; //clean the queue;
	return resultStr;
}

VDOM_EventQueue.prototype.sendRequest = function(req_str) {
  //sending of the serialized queue to the server
	if (req_str != "") {
		this.sendAvailable = false;
		sendForm(req_str, bind(this, this.receiveAnswer));
	}
}

VDOM_EventQueue.prototype.receiveAnswer = function(doc)
{
    if (!doc) return;

    var sio = doc.documentElement.getElementsByTagName('SESSIONISOVER');
    if (sio.length > 0) {
        window.location.reload();
        return;
    }
    
    //processing the server answer
    var objList = doc.documentElement.getElementsByTagName('OBJECT');

    for (var i=0;i<objList.length;i++) {
		objItem = objList[i];
//        objID = objItem.attributes.getNamedItem('ID').nodeValue;
		if (objItem.text) {
			objValue = objItem.text;
		} else {
			objValue = objItem.textContent;
		}
        var objIDa = /id=[\"\']?([^\'^\"]+)/i.exec(objValue);
        var objID = objIDa[1] ? objIDa[1] : '';
        var elem = document.getElementById(objID);
        if (elem) {

//			elem.innerHTML = objValue; // wrong, imho - tag must be replaced /Leo

            // other way, but this kills events links for object
            papa = elem.parentNode;
            if (papa) {
                papa.removeChild(elem);
                var newElem = document.createElement('div');
                newElem.innerHTML = objValue;
                papa.appendChild(newElem);
            }

            // todo: try update parameters for objects

		}

	}
	//end of processing the server answer
	//trying to send a queue
	this.sendAvailable = true;
	this.checkForSending();
}

VDOM_EventQueue.prototype.addEvent = function(vdom_evnt) {
	this.eventQueue.push(vdom_evnt);
	this.checkForSending();
}

VDOM_EventQueue.prototype.checkForSending = function() {
	if (this.sendAvailable && this.eventQueue.length > 0) {
		var req_str = this.serialize();
		this.sendRequest(req_str);
	};
}

/**
 * DRAG/DROP
 */

function dragInit_(o, evt)
{
    drag_current_obj = o;
    var oRoot = document;//.getElementById("container");
    o.root = oRoot != null ? oRoot : o;

//    o.root.onDragStart = new Function();
//    o.root.onDragStop	= new Function();
//    o.root.onDrag		= new Function();

    dragStart_();

    document.onmousemove = dragDrag_;
    document.onmouseup = dragStop_;
}

function dragStart_()
{
    var e = drag_current_event;
    e = dragFixE_(e);

    var y = parseInt(drag_current_obj.style.top);
    var x = parseInt(drag_current_obj.style.left);
    drag_current_obj.style.zIndex = ++highestZindex;

    drag_lastMouseX = defPosition(e).x;
    drag_lastMouseY = defPosition(e).y;

    drag_maxMouseX = e.clientX + x;
    drag_maxMouseY = e.clientX + x;
    drag_minMouseX = e.clientY + y;
    drag_minMouseY = e.clientY + y;

    return false;
}

function dragDrag_(e)
{
    e = dragFixE_(e);

    var ey = defPosition(e).y;
    var ex = defPosition(e).x;

    var y = parseInt(drag_current_obj.style.top);
    var x = parseInt(drag_current_obj.style.left);

    var nx = x - (ex - drag_lastMouseX) * (-1);
    var ny = y - (ey - drag_lastMouseY) * (-1);

    drag_current_obj.style.top = ny + "px";
    drag_current_obj.style.left = nx + "px";
    drag_lastMouseX	= ex;
    drag_lastMouseY	= ey;

    return false;
}

function dragStop_()
{
    document.onmousemove = null;
    document.onmouseup   = null;
    drag_current_obj = null;
    drag_mouse_down = false;
    drag_lastMouseX = drag_lastMouseY = 0;
}

/**
 * we respect every individual, we understand their traits..
 */
function dragFixE_(e)
{
    if (typeof e == 'undefined') e = window.event;
    if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
    if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
    return e;
}

/**
 * find div with max zIndex.
 * this info needed in drag'n'drop
 */
var a = document.getElementsByTagName('div');
for(i=0; i<a.length; i++) {
    if (a[i].style.zIndex) {
        if (a[i].style.zIndex > highestZindex) {
            highestZindex = a[i].style.zIndex;
        }
    }
}

/**
 * generate single event
 */
function execEventCustom(evtName, srcp, params, target)
{
    if (srcp.domCont) {
        src = srcp.domCont;
    } else {
        src = srcp;
    }
    var nev = new VDOM_Event();
	nev.srcObj = src;
	nev.name = evtName;
	for (var i=0;i<params.length;i++) {
		nev.addParameter(params[i].Name, params[i].Value);
	};
    if (target.eventEngine) {
    	target.eventEngine.processEvent(nev);
    }
}

function substr( f_string, f_start, f_length ) {
    if(f_start < 0) { f_start += f_string.length; }
 
    if(f_length == undefined) { f_length = f_string.length;
    } else if(f_length < 0){  f_length += f_string.length;
    } else { f_length += f_start; }

    if(f_length < f_start) { f_length = f_start; }
 
    return f_string.substring(f_start, f_length);
}

/**
 * call binded event
 */
function execEventBinded(srcID, evtName, params)
{
console.info('#-----> execEventBinded for: '+srcID);
console.info('# evtName: '+evtName);
console.info('# params: ');
console.info(params);

console.info('# Object_: ');
    var o = eval("Object_"+srcID+" || null;");
console.info(o);

console.info('# Object_.eventEngine: ');
    var ee = eval("Object_"+srcID+".eventEngine || null;");
console.info(ee);

    if (o && ee) {
console.info('# obj & evt ok');
console.info('# search evt in array for ['+"o_"+srcID+":"+evtName+']');
        for (var i=0; i<o.eventEngine.eventDispatcher.eventArray.length; i++) {
            if (o.eventEngine.eventDispatcher.eventArray[i].eventSrc == "o_"+srcID+":"+evtName) {
console.info('# find:');
                var nev = new VDOM_Event();
                nev.srcObj = document.getElementById("o_"+srcID);
                nev.name = evtName;
                if (params != undefined) {
console.info(params);
console.info('# event params:');
                    for (key in params) {
                        params[key] = params[key].replace(/\&/g, "&amp;");
console.info('# > event param ['+key+']: '+params[key]);
//                        nev.addParameter(key, params[key]);
                        nev.addParameter(key, params[key]);
                    }
//                    for (var i=0;i<params.length;i++) {
//                        nev.addParameter(params[i].Name, params[i].Value);
//                    };
                } else {
console.info('# no params (undefined).');
                }
                o.eventEngine.processEvent(nev);
console.info('# send event: OK');
            }
console.info('# ..search done');
        }
    } else {
console.info('# send event: ERROR');
    }
console.info('#-----> END execEventBinded ');
}

/**
 * execute single action directly
 */
function execActionDirect(actName, params, target)
{
    var f = "Object_"+target+"."+actName;
    var n = false;
    eval("n = "+f+" ? true : false;");
    if (n) {
        var p = (params instanceof Array) ? params.join(",") : params;
        eval(f+"("+p+");");
    }
}

function generateErrorEvent(msg)
{
    var prm = { msg: msg };
    execEventCustom('erroreventengine', this, prm, this);
}

function explode(delimiter, string)
{
    var emptyArray = { 0: '' };
    if (arguments.length != 2 || typeof arguments[0] == 'undefined' || typeof arguments[1] == 'undefined') { return null; }
    if (delimiter === '' || delimiter === false || delimiter === null) { return false; }
    if (typeof delimiter == 'function' || typeof delimiter == 'object' || typeof string == 'function' || typeof string == 'object') { return emptyArray; }
    if (delimiter === true) { delimiter = '1'; }
    return string.toString().split(delimiter.toString());
}

