// 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;

/**
 * DECLARE FUNCTIONS
 */

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

/**
 * 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;
}

/**
 * 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;
}

/**
 * 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
  var frame = getIFrame();
  var form = getForm(data);
  if (typeof(form)=="string") { form = document.getElementById(form); }
  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(); }
}

/**
 * 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 i, result = "", cnt = 1, num = 1;
    count = count || -1;
    for (i in obj) {
      if (obj.hasOwnProperty(i)) {
        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
 * @vdom            reference to a VDOM object
 * @eType           string, representing an event(onload, onmousedown, etc)
 * @eListener       function to be attached
 * @useCapture      events must be captured at descending phase
 */
function vdomRegisterEventListener(vdom, eType, eListener, useCapture)
{
  obj = vdom.domCont;
  eType = eType.toLowerCase();
/*
  if ( /opera/.test(navigator.userAgent.toLowerCase()) ) {
    obj.addEventListener(eType, bind(vdom, eListener), false);
  } else if (obj.attachEvent) { //ie
    obj.attachEvent('on'+eType, bind(vdom, eListener));
  } else if (obj.addEventListener) { //true browsers
    obj.addEventListener(eType, bind(vdom, eListener), useCapture);
  }
*/
//  jQuery(obj).bind( eType, bind(vdom, eListener) );
  jQuery(obj).bind(eType, bind(vdom, eListener) );

}

/**
 * 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();
  this.eventArray = [];
}

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(eSrc)
{
//console.info('getActionList for:');
//console.info(eSrc);
  var actList = [];
  for (var i = 0; i < this.eventArray.length; i++) {
    if (this.eventArray[i].eventSrc == eSrc) {
      actList.push(this.eventArray[i].actionTgt);
    }
  }
  return actList;
};

/**
 * 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)
{
console.info('sendToServer envt = '+evnt.name);
  //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.processEvent = function(evnt)
{
  //evnt has type of VDOM_Event
  if (!this.Active) { return false; }
//  var actList = new Array();
  var actList = this.eventDispatcher.getActionList(evnt.getEventStr());
//console.info('processEvent: actList len = '+actList.length);
  for (var i = 0; i < actList.length; i++) {
    act_str = actList[i];
    drag_current_event = evnt;
    switch (act_str) {
      case "server":
console.info('processEvent: sendToServer');
        this.sendToServer(evnt);
        break;
      default:
console.info('processEvent: executeAction');
        this.executeAction(act_str, evnt);
        break;
    }
  }
};

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

/**
 * 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
  this.parameters = [];
}

VDOM_Event.prototype.addParameter = function(name, value)
{
  var param = new VDOM_Param(name, value);
  this.parameters.push(param);
};

/**
 * return a name of event in ":" notation
 * event dispatcher should store events in this notation
 */
VDOM_Event.prototype.getEventStr = function()
{
  var a = this.srcObj.id + ':' + this.name;
  return a;
};

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;
};

/**
 * 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 generateErrorEvent(msg)
{
  var prm = { msg: msg };
  execEventCustom('erroreventengine', this, prm, this);
}

VDOM_EventEngine.prototype.executeAction = function(act_str, evnt)
{
console.info('executeAction: '+act_str);
  //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");
//  var re = /^(\w+):(\w+)\((.*)\)$/g;
  var m = /^(\w+):(\w+)\((.*)\)$/g.exec(act_str);
  if (m !== null) {
    vdomObj = typeof m[1] === 'undefined' ? null : eval(m[1]);
    if (vdomObj === null) {
//      alert("Object '"+m[1]+"' does not exist !");
      generateErrorEvent("Object '"+m[1]+"' does not exist !");
      return;
    }
    actName = m[2];
//    var params = new Array();
    var params = [];
    this.parseParams(evnt, m[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_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 = [];
    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(e)
{
  if (this.eventEngine !== null) {
    this.eventEngine.processEvent(e, this);
  } else {
console.info('execEvent: ERROR');
    window.status = 'ERROR['+this.name+'.'+e.name+']: eventEngine - bad object reference';
  }
};

function defPosition(event)
{
  var x = 0, 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(eName, eParams, eEngine)
{
console.info('riseEvent: '+eName);
  var newEvent = new VDOM_Event();
  newEvent.srcObj = this.domCont;
  newEvent.name = eName;
  for (var i = 0; i < eParams.length; i++) {
    newEvent.addParameter(eParams[i].Name, eParams[i].Value);
  }
  eEngine.processEvent(newEvent);
};

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

//function vdomRegisterEventListener(vdomObject, eventType, eventListener, useCapture)
// c r@Sç82c9…5cP
customRegisterEvents = function(pa,ob,ev,ac)
{
  var o=false,os='Container_'+pa+'_Dispatcher';
  eval("if (typeof "+os+" != 'undefined') o=true;");
  if (o) {
    eval('os.addDispatchEvent("o_'+ob+':'+ev+'","server");');
  }
/*
Container_aa1bc2f5_adf3_4b5d_8678_feb130980f43_Dispatcher=new VDOM_EventDispatcher();
Container_aa1bc2f5_adf3_4b5d_8678_feb130980f43_Dispatcher.addDispatchEvent("o_e62ff902_5b1b_4ee2_9286_3a8397ec666b:click", "server")
*/
};


/**
 * VDOM_EventQueue declaration
 */

function VDOM_EventQueue()
{
//  this.eventQueue = new Array();
  this.eventQueue = [];
  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
//console.info('sendRequest: ?');
  if (req_str != "") {
console.info('sendRequest: sendForm');
    this.sendAvailable = false;
    sendForm(req_str, bind(this, this.receiveAnswer));
  }
};


function attachScript(inner)
{
  var s = document.createElement('script');
  s.type = "text/javascript";
  s.innerHTML = inner;
  document.getElementsByTagName("body")[0].appendChild(s);
}

/**
 * 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+");");
  }
}

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');

  var i = 0;

  for (i = 0; i < objList.length; i++) {
    objItem = objList[i];
  //        z = 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 oa = jQuery(objList[i]);
    objID = oa.attr('ID');
    objType = oa.attr('TYPE');
    objParent = oa.attr('PARENT');
    objContainer = oa.attr('CONTAINER');

    var elem = document.getElementById('o_'+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);
        jQuery(elem).remove();
//                var newElem = document.createElement('div');
//                newElem.innerHTML = objValue;
//                papa.appendChild(newElem);

//        var s = new Array();
        var s = [];
        jQuery('script',objValue).each(function(){
          s.push(jQuery(this).html());
        });
        jQuery('script',objValue).remove();
/* recreate vdom obj
Object_2e1bb65c_5af3_4da7_ae85_091c8458284e=new VDOM_Type_91a12281_c9a8_430a_8a2d_93903b4a264f("o_2e1bb65c_5af3_4da7_ae85_091c8458284e", Container_f2fa4240_e7dd_4bfb_a183_197953af6cdb_EventEngine);
*/
/*
        if (objParent != '') {
            if (objContainer == '1') {
                eval('Object_'+objID+'=new VDOM_Type_'+objType+'("o_'+objID+'",Container_'+objParent+'_EventEngine);');
            } else {
                eval('Object_'+objID+'=new VDOM_Type_'+objType+'("o_'+objID+'",Container_'+objParent+'_EventEngine);');
            }
        }
*/
        jQuery(papa).append(objValue);

//        if (s.length>0) {
//            jQuery.each(s,function(){
//                attachScript(this);
//            });
//        }
      }

      // todo: try update parameters for objects
    }
  }

  //processing EXECUTE from server answer
  var a, aname, apars, adest;
  var objList2 = jQuery('EXECUTE', doc);
  for (i = 0; i < objList2.length; i++) {
    a = jQuery(objList2[i]);
    aname = a.attr('ACT_NAME');
    adest = a.attr('DST_ID');
    apars = a.attr('PARAM');
    execActionDirect(aname, apars, adest);
  }

  //processing LISTENER from server answer
  /*
  <LISTENER
    CONTAINER   = "aa1bc2f5_adf3_4b5d_8678_feb130980f43"
    SRC_ID      = "4a4450c9_12eb_48b2_8ea2_f408525de209"
    EVENT_NAME  = "click"
    DST_ID      = "7085bd26_e653_490b_908f_61208c260a86"
    ACT_NAME    = "client_action_function_name"
    PARAMS      = "1,true,'stringstring'"
  />*/
  var objList3 = jQuery('LISTENER', doc);
  for (i = 0; i < objList3.length; i++) {
    a = jQuery(objList3[i]);
    acnt = a.attr('CONTAINER');
    asrc = a.attr('SRC_ID');
    aevt = a.attr('EVENT_NAME');
    adst = a.attr('DST_ID');
    aact = a.attr('ACT_NAME')||'';
    apar = a.attr('PARAMS');
    se = (aact=='server') ? true : false;

    var o=false, os='Container_'+acnt+'_Dispatcher';
    eval("if (typeof "+os+" != 'undefined') o=true;");
    if (o) {
      act = se ? 'server' : 'Object_'+adst+':'+aact+'('+apar+')';
      eval(os+'.addDispatchEvent("o_'+asrc+':'+aevt+'","'+act+'");');
    }

//Container_f2fa4240_e7dd_4bfb_a183_197953af6cdb_Dispatcher.addDispatchEvent("o_95182681_c165_43f6_a36c_6892f1c80cd2:click", "Object_b008a8e6_64a1_40d2_9a8e_9741f65cc798:setHTML('coucou')");

//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

  }

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

VDOM_EventQueue.prototype.addEvent = function(ve)
{
console.info('addEvent');
  this.eventQueue.push(ve);
  this.checkForSending();
};

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

/**
 * DRAG/DROP
 */

/**
 * 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;
}

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

  var y = parseInt(drag_current_obj.style.top, 10);
  var x = parseInt(drag_current_obj.style.left, 10);
  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, 10);
  var x = parseInt(drag_current_obj.style.left, 10);

  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;
}

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_;
}

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

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)
{
  var o = eval("Object_"+srcID+" || null;");
  var ee = eval("Object_"+srcID+".eventEngine || null;");

  if (o && ee) {

    for (var i = 0; i < o.eventEngine.eventDispatcher.eventArray.length; i++) {
      if (o.eventEngine.eventDispatcher.eventArray[i].eventSrc == "o_"+srcID+":"+evtName) {
        var nev = new VDOM_Event();
        nev.srcObj = document.getElementById("o_"+srcID);
        nev.name = evtName;
        if (params !== 'undefined') {
          for (var k in params) {
            if (params.hasOwnProperty(k)) {
              nev.addParameter(k, params[k]);
            }
          }
//                    for (var i=0;i<params.length;i++) {
//                        nev.addParameter(params[i].Name, params[i].Value);
//                    };
        }
        o.eventEngine.processEvent(nev);
      }
    }
  } else {
console.info('# send event: ERROR');
  }
}

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());
}

