/*--------------------------------------------------------------------------
 *  UI JavaScript Components
 *
 *  ---- Based on Prototype JavaScript framework ----
 *
 *  (c) 2007 Jean Nack <jean@nack.com.br>
 *
/*--------------------------------------------------------------------------*/

var UI = document.UI = {
  dirBase: '.',
  dirImagens: '~/Desktop/Data/images/',
  arqStyles: '~/Desktop/Data/styles/componentes.css',

  pgLookup: '/Desktop/MTM/lookup.aspx',
  pgLookupWindow: '/Desktop/MTM/lookup_window.aspx',
  pgReqPacket: '/Desktop/MTM/req_packet.aspx',
  pgEdition: '/Desktop/MTM/edicao.aspx',
  pgPing: '/Desktop/MTM/ping.aspx',
  pgExecMethod: '/Desktop/MTM/exec_metodo.aspx',
  pgReport: '/Desktop/MTM/report.aspx',
  pgPreview: '/Desktop/MTM/preview.aspx',
  pgData: '/Desktop/MTM/data.aspx',
  pgExecReport: '/Desktop/MTM/exec_report.aspx',

  descLkpSelected: '(Selecionados)',
  isIE: navigator.userAgent.toLowerCase().indexOf("msie") >= 0,
  isFirefox: navigator.userAgent.toLowerCase().indexOf("firefox") >= 0,
  isNetscape: navigator.userAgent.toLowerCase().indexOf("netscape") >= 0,
  isOpera: navigator.userAgent.toLowerCase().indexOf("opera") >= 0,

  key_search: 113, //F2

  defaultDisplay: (navigator.userAgent.toLowerCase().indexOf("msie") >= 0) ? 'inline' : null,
  xmlHeader: '<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>',
  Comps: {},
  Attributes: new Array(),
  Controls: new Array(),

  dateMask: 'dd/mm/yyyy',
  timeMask: 'hh:nn',
  months: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
  
  onResize: null,

  setClipboard: function(data) {
    window.clipboardData.setData("Text", data);
  },

  checkBodyValidKeys: function(ev) {
    var ev = ev || window.event;
    var keyCode = ev.keyCode || ev.charCode || ev.which;
    var obj = ev.target || document.activeElement;

    if (obj && (obj.tagName.toUpperCase() == 'INPUT'))
      return true;

    return (keyCode != 8) && (keyCode != 27);
  },

  parseXML: function(text) {
    var doc = null;

    if (window.ActiveXObject) {
      doc = new ActiveXObject("Microsoft.XMLDOM");
      doc.async = false;
      doc.loadXML(text);
    } else
      doc = (new DOMParser()).parseFromString(text, "text/xml");

    return doc;
  },

  readXML: function(doc) {
    if (window.ActiveXObject)
      return doc.xml;
    else
      return (new XMLSerializer()).serializeToString(doc);
  },

  getMessageErro: function(xmldoc) {
    var elements = xmldoc.documentElement.getElementsByTagName('err');
    var details = xmldoc.documentElement.getElementsByTagName('det');

    if (elements.length == 0)
      return true;

    var s = '';
    var dets = '';

    for (var i = 0; i < elements.length; i++)
      s += elements[i].getAttribute('msg') + UI.chr(13);

    for (var i = 0; i < details.length; i++)
      dets += details[i].getAttribute('msg');

    if (dets != '')
      s += UI.chr(13) + 'Detalhes:' + UI.chr(13) + dets;

    if (s != '')
      alert(s);

    return (s == '');
  },

  getActiveElement: function(doc) {
    var wnd = doc.parentWindow || doc.defaultView;

    if (wnd.UI)
      for (var i = 0; i < wnd.UI.Attributes.length; i++) {
        var att = wnd.UI.Attributes[i];

        if (att.controls) {
          for (var j = 0; j < att.controls.length; j++)
            if (att._getControl(j).focused)
              return att._getControl(j).edit;
        } else
          if (att.control && att.control.focused)
            return att.control.edit;
      }

    var frames = doc.getElementsByTagName('iframe');

    for (var i = 0; i < frames.length; i++) {
      var cmp = UI.getActiveElement(UI.getDocumentFromIframe(frames[i]));
      if (cmp)
        return cmp;
    }

    return null;
  },

  getLanguageTag: function(tagName) {
    switch(tagName) {
      case 'first'    : return 'Primeiro';
      case 'prev'     : return 'Anterior';
      case 'next'     : return 'Próximo';
      case 'last'     : return 'Último';
      case 'clear'    : return 'Limpar';
      case 'find'     : return 'Localizar';
      case 'close'    : return 'Fechar';
      case 'login'    : return 'Entrar';
      case 'reset'    : return 'Limpar';
      case 'loading'  : return 'Carregando, aguarde...';
      case 'search'   : return 'Pesquisar';
      case 'select'   : return 'Selecionar';
      case 'today'    : return 'Hoje';
      case 'combo_all': return '[ Diversos ]';
    }
    return '';
  },

  getDataset: function(id) {
    var wnd = UI.getFirstWindow();

    if (wnd.datasets)
      for (var i = 0; i < wnd.datasets.length; i++)
        if (wnd.datasets[i].id == id)
          return wnd.datasets[i];

    return null;
  },

  padl: function(str, len, ch) {
    ch = ch || ' ';

    while (str.length < len)
      str = ch + str;

    return str;
  },

  chr: function() {
    var s = '';

    for (var i = 0; i < arguments.length; i++)
      s += String.fromCharCode(arguments[i]);

    return s;
  },

  dateToStr: function(date, bdDate) {
    if (!isNaN(date.getDate()) && !isNaN(date.getMonth()) && !isNaN(date.getYear())) {
        var d = UI.padl(date.getDate()+'', 2, '0');
        var m = UI.padl((date.getMonth()+1)+'', 2, '0');
        var y = date.getYear();
        if ((y >= 100) && (y <= 1000))
          y += 1900;

        var y = y+'';

        if (y.length <= 2)
          y = '19' + UI.padl(y, 2, '0');

        if (bdDate)
          return y + '-' + m + '-' + d;
        else
          return UI.dateMask.replace('dd', d).replace('mm', m).replace('yyyy', y);
    } else
      return '';
  },

  strToDate: function(value, defaultDate) {
    var d = value.substring(UI.dateMask.indexOf('dd'), UI.dateMask.indexOf('dd') + 2);
    var m = value.substring(UI.dateMask.indexOf('mm'), UI.dateMask.indexOf('mm') + 2);
    var y = value.substring(UI.dateMask.indexOf('yyyy'), UI.dateMask.indexOf('yyyy') + 4);
    var dt = new Date(y, m-1, d);

    var validDate = (value != '') && !isNaN(dt.getDate()) && !isNaN(dt.getMonth()) && !isNaN(dt.getYear());

    return validDate ? dt : (defaultDate || dt);
  },

  timeToStr: function(time, bdTime) {
    if (!isNaN(time.getHours()) && !isNaN(time.getMinutes())) {
        var h = UI.padl(time.getHours()+'', 2, '0');
        var m = UI.padl(time.getMinutes()+'', 2, '0');

        if (bdTime)
          return h + ':' + m;
        else
          return UI.timeMask.replace('hh', h).replace('nn', m);
    } else
      return '';
  },

  strToTime: function(value, defaultTime) {
    var h = value.substring(UI.timeMask.indexOf('hh'), UI.timeMask.indexOf('hh') + 2);
    var m = value.substring(UI.timeMask.indexOf('nn'), UI.timeMask.indexOf('nn') + 2);
    var dt = new Date(1899, 0, 1, h, m, 0);

    var validTime = (value != '') && !isNaN(dt.getHours()) && !isNaN(dt.getMinutes());

    return validTime ? dt : (defaultTime || dt);
  },

  enableAttributes: function() {
    for (var i = 0; i < UI.Attributes.length; i++)
      UI.Attributes[i].setFixedEnabled(true);
  },

  disableAttributes: function() {
    for (var i = 0; i < UI.Attributes.length; i++)
      UI.Attributes[i].setFixedEnabled(false);
  },

  enableControls: function() {
    for (var i = 0; i < UI.Controls.length; i++)
      UI.Controls[i].setFixedEnabled(true);
  },

  disableControls: function() {
    for (var i = 0; i < UI.Controls.length; i++)
      UI.Controls[i].setFixedEnabled(false);
  },

  enableWindow: function(flag) {
    if (flag)
      UI.enableControls();
    else
      UI.disableControls();

    var ifrms = document.getElementsByTagName('iframe');

    for (var i = 0; i < ifrms.length; i++) {
      var doc = UI.getDocumentFromIframe(ifrms[i]);

      if (doc && doc.UI && doc.UI.enableWindow)
        doc.UI.enableWindow.call(doc, flag);
    }
  },

  _seed: (new Date()).getTime() % 0xffffffff,

  random: function(n) {
    if (n == undefined)
      n = 65536;

    UI._seed = (0x015a4e35 * UI._seed) % 0x7fffffff;
    return (UI._seed >> 16) % n;
  },

  createTable: function(options) {
    var doc = options.doc || document;

    var table = doc.createElement('table');
    var tbody = doc.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';

    if (options && options.tableLayout)
      table.style.tableLayout = options.tableLayout;

    if (options && options.width)
      table.style.width = options.width;

    if (options && options.height)
      table.style.height = options.height;

    return table;
  },

  createTableElement: function(owner, element, qtd, doc) {
    doc = doc || document;

    if (typeof qtd != 'number')
      qtd = 1;

    var el = new Array();
    while (qtd-- > 0)
      el[el.length] = doc.createElement(element);

    for (var i = 0; i < el.length; i++)
      if ((el[i].tagName.toLowerCase() == 'tr') && (owner.tagName.toLowerCase() == 'table'))
        owner.childNodes[0].appendChild(el[i]);
      else
        owner.appendChild(el[i]);

    return (el.length > 1) ? el : el[0];
  },

  getParentForm: function(element) {
    var form = element;

    while (form && (form.tagName.toLowerCase() != 'form') && form.parentNode && form.parentNode.tagName)
      form = form.parentNode;

    return (form && (form.tagName.toLowerCase() == 'form')) ? form : null;
  },

  getFirstWindow: function(pass_opener) {
    var wnd = window;

    pass_opener = (typeof pass_opener == 'boolean') ? pass_opener : true;

    try {
    while ((wnd.parent && (wnd.parent != wnd)) || (pass_opener && (wnd.opener) && (wnd.opener.document) && (wnd.opener != wnd)))
      if (wnd.opener)
        wnd = wnd.opener;
      else
        wnd = wnd.parent;
    } catch(e) {
    }

    return wnd;
  },

  showModalFrame: function(options) {
    var wnd = UI.getFirstWindow(false);

    if (!wnd.document.modalFrame)
      wnd.document.modalFrame = new wnd.UI.Comps.ModalFrame(wnd);

    wnd.document.modalFrame.show(options);
  },

  closeModalFrame: function(modalResult) {
    wnd = UI.getFirstWindow(false);

    if (wnd && wnd.document.modalFrame) {
      var args = [];
      for (var i = 0; i < arguments.length; i++)
        args = args.concat(arguments[i]);

      wnd.document.modalFrame.close.apply(wnd.document.modalFrame, args);
    }
  },

  showingModalFrame: function() {
    wnd = UI.getFirstWindow();
    return (wnd && wnd.document.modalFrame && wnd.document.modalFrame.showing);
  },

  formatNumber: function(value, decimals) {
    if (typeof value == 'string')
      value = parseFloat(value) || 0;

    value = UI.roundTo(value, decimals).toString().replace('.', ',');
    negative = value.indexOf('-') > -1;
    value = value.replace('-', '');

    if ((decimals > 0) && (value.indexOf(',') == -1))
      value += ',';

    while (value.length-decimals <= value.indexOf(','))
      value += '0';

    var init = (decimals > 0) ? value.indexOf(',') : value.length;
    while (init > 0) {
      init -= 3;

      if (init > 0)
        value = value.substr(0, init) + '.' + value.substr(init);
    }

    return (negative ? '-' : '') + value;
  },

  getNextTabIndex: function() {
    var max = -1;

    for (var i = 0; i < document.all.length; i++)
      max = Math.max(document.all[i].tabIndex, max);

    return max+1;
  },

  roundTo: function(value, decimals) {
    var n = 1;
    for (var i = 0; i < decimals; i++)
      n *= 10;

//    return Math.abs(Math.round(value*n))/n;
    return Math.round(value*n)/n;
  },

  disableSelection: function(element) {
    element.onselectstart = function() {
        return false;
    };
    element.unselectable = "on";
    element.style.MozUserSelect = "none";
    element.style.cursor = "default";
  },

  getInputSelection: function(input) {
    if (document.selection) {
      var range = document.selection.createRange();
      return (range.parentElement() == input) ? range.text : '';
    } else if (typeof(input.selectionStart) != undefined)
      return input.value.substring(input.selectionStart, input.selectionEnd);
    else
      return null;
  },

  getElementsComputedStyle: function (htmlElement, cssProperty, mozillaEquivalentCSS) {
    if (arguments.length == 2)
      mozillaEquivalentCSS = cssProperty;

    var el = $(htmlElement);
    if (el.currentStyle)
      return el.currentStyle[cssProperty];
    else
      return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
   },

  getCaretPos: function(element) {
    if (typeof(element.selectionStart) == 'number')
      return element.selectionStart;

    var currentRange = document.selection.createRange();
    var workRange = currentRange.duplicate();

    element.select();
    var allRange = document.selection.createRange();
    var len = 0;

    while(workRange.compareEndPoints("StartToStart", allRange) > 0) {
      workRange.moveStart("character", -1);
      len++;
    }

    currentRange.select();
    return len;
  },

  setCaretPos: function(element, position) {
    if (typeof element.selectionStart == 'number') {
      element.selectionStart = position;
      element.selectionEnd = position;
    } else {
      element.select();
      var range = document.selection.createRange();
      range.moveStart("character", position);
      range.collapse();
      range.select();
    }
  },

  registerAjaxRequest: function(url, func, params) {
    var funcs = {
      method: 'get',
      onSuccess: function(request) {
        func(request.responseText, params);
      },
      onException: function(req, exception) {
        return true;
      },
      onFailure: function() {
        return true;
      }
    }

    if (params && params.postBody) {
      funcs.postBody = params.postBody;
      params.postBody = null;
    }

    if (params && params.parameters) {
      funcs.parameters = params.parameters;
      params.parameters = null;
    }

    if (params && (typeof params.method == 'string')) {
      funcs.method = params.method;
      params.method = null;
    }

    if (params && params.onException) {
      funcs.onException = params.onException;
      params.onException = null;
    }

    if (params && params.onFailure) {
      funcs.onFailure = params.onFailure;
      params.onFailure = null;
    }

    new Ajax.Request(url, funcs);
  },

  ajaxPostXml: function(xmldoc, func, param, param2) {
    var url = UI.dirBase + UI.pgData;

    UI.ajaxPostXmlToURL(url, xmldoc, func, param, param2);
  },

  ajaxPostXmlToURL: function(url, xmldoc, func, param, param2) {
    var opt = {
      method     : 'post',
      postBody   : xmldoc,
      onException: function(req, exception) {
        func(param, param2, true);
      },
      onFailure  : function() {
        func(param, param2, true);
      }
    };

    UI.registerAjaxRequest(url, func.bind(null, param, param2, false), opt);
  },

  extend: function(superclass, prot) {
    function dummy(){};
    dummy.prototype = superclass.prototype;

    for (property in superclass.prototype)
      dummy[property] = superclass.prototype[property];

    for (property in prot)
      dummy[property] = prot[property];

    if (typeof dummy.superclass == 'object') {
      var i = 1;
      while (typeof eval('dummy.superclass' + ++i) == 'object') {}
      eval('dummy.superclass'+i+' = superclass.prototype;');
    } else
      dummy.superclass = superclass.prototype;

    return dummy;
  },

  attachEvent: function(obj, evt, func, arg) {
    if (obj.addEventListener) {
      obj.addEventListener(evt, func.bind(arg), true);
    } else if (obj.attachEvent) {
      obj.attachEvent('on'+evt, func.bind(arg));
    }
  },

  getAbsolutePosition: function(obj) {
    var o = new Object();
    o.x = 0;
    o.y = 0;

    do {
      o.x += obj.offsetLeft;
      o.y += obj.offsetTop;

    } while (obj = obj.offsetParent);

    return o;
  },

  getDocumentFromIframe: function(ifrm) {
    var doc = null;

    if (ifrm.contentDocument)
      doc = ifrm.contentDocument;
    else if (ifrm.contentWindow)
      doc = ifrm.contentWindow.document;
    else if (window.frames) {
      var nm = ifrm.name;
      if (ifrm.name == '')
        ifrm.name = '_getDocIframeName';

      doc = window.frames[ifrm.name].document;
      ifrm.name = nm;
    }

    return doc;
  },

  getChildNodes: function(container, parent, tagName) {
    var ret = new Array();
    var nodeParent = null;

    if (this.isIE) {
      for (var i = 0; i < container.childNodes.length; i++) {
        var node = container.childNodes[i];

        if (node.nodeName.toLowerCase() == tagName.toLowerCase()) {
          if (nodeParent == parent)
            ret.push(node);

          node.parent = nodeParent;
          nodeParent = node;
        }

        if (node.nodeName.toLowerCase() == '/'+tagName.toLowerCase())
          if (nodeParent != null)
            nodeParent = nodeParent.parent;
      }
    } else {
      nodeParent = parent || container;

      for (var i = 0; i < nodeParent.childNodes.length; i++)
        if (nodeParent.childNodes[i].nodeName.toLowerCase() == tagName.toLowerCase())
          ret.push(nodeParent.childNodes[i]);
    }

    return ret;
  },

  getStringWidth: function(caption, cssClassName) {
    var owner = document.createElement('div');
    owner.display = 'none';

    document.body.appendChild(owner);
    if (caption)
      var w = UI.getTextWidth(caption, owner, cssClassName || 'edit');
    else
      var w = UI.getTextWidth('AxBz', owner, cssClassName || 'edit') / 4;

    document.body.removeChild(owner);

    return w;
  },

  getTextWidth: function(text, owner, cssClassName) {
    var span = document.createElement('span');

    span.innerHTML = text;
    span.display = 'none';

    if (cssClassName)
      span.className = cssClassName;

    owner.appendChild(span);
    var width = span.offsetWidth;
    owner.removeChild(span);

    return width;
  },

  setEvent: function(eventName, evt, eventObject) {
    UI.attachEvent(document, eventName, evt, eventObject);
    UI.attachEvent(window, eventName, evt, eventObject);

    if (eventObject.container)
      UI.attachEvent(eventObject.container, eventName, evt, eventObject);
  },

  clearEvent: function(eventName, event, eventObject) {
    if (document.detachEvent)
      document.detachEvent(eventName, event);

    if (window.detachEvent)
      window.detachEvent(eventName, event);

    if (eventObject.container && eventObject.container.detachEvent)
      eventObject.container.detachEvent(eventName, event);
  },

  resize: function(obj) {
    if (this.isFirefox || this.isNetscape) {
      var sv = obj.style.width;
      var w = obj.offsetWidth;

      obj.style.width = (w-1) + 'px';
      obj.style.width = (sv) ? sv : w + 'px';
    }
  },

  getScrollSize: function(owner) {
    var div = document.createElement('div');
    div.style.position = 'absolute';
    div.style.visibility = 'hidden';

    if ((div.style.overflowX != undefined) && !UI.isFirefox)
      div.style.overflowX = 'scroll';
    else
      div.style.overflow = 'scroll';

    div.style.width = '5px';
    div.style.height = '40px';

    owner.appendChild(div);

    if (UI.isFirefox) {
      for (var i = 10; i < 20; i++) {
        div.style.width = i + 'px';

        if (div.clientWidth == 0)
          break;
      }
      var ret = div.offsetWidth - div.clientWidth;
    } else
      var ret = div.offsetHeight - div.clientHeight;

    owner.removeChild(div);

    return ret;
  },

  getImage: function(componentClass, index) {
    return this.dirImagens + componentClass.SubDir + componentClass.Images[index];
  },

  onloadPage: function() {
    if (UI.isFirefox)
      document.readyState = 'complete';
  }
}

UI.Validation = {

  checkEmail: function(eMail) {
    return /^(\w+\.)*([\w-]+)@([\w-]+\.)+([a-zA-Z]{2,4})$/.test(eMail);
  },

  checkCPF: function(cpf) {
    cpf = _parseNumb(cpf);
    if (cpf == 0)
      return false;
    else
      return UI.Validation._testDigit(cpf, 'CPF', cpf.length-2) && 
             UI.Validation._testDigit(cpf, 'CPF', cpf.length-1);
  },

  checkCNPJ: function(cnpj) {
    cnpj = UI.Validation._parseNumb(cnpj);
    if (cnpj == 0)
      return false;
    else
      return UI.Validation._testDigit(cnpj, 'CNPJ', cnpj.length-2) && 
             UI.Validation._testDigit(cnpj, 'CNPJ', cnpj.length-1);
  },

  _clearStr: function(str, ch) {
    while ((cx = str.indexOf(ch)) != -1)
      str = str.substring(0, cx) + str.substring(cx + 1);

    return(str);
  },

  _parseNumb: function(c) {
    c = UI.Validation._clearStr(UI.Validation._clearStr(UI.Validation._clearStr(c, '-'), '/'), '.');

    if(parseFloat(c) / c != 1)
      return (parseFloat(c) * c == 0) ? c : 0;
    else
      return c;
  },

  _testDigit: function(num, type, g) {
    var dig = 0;
    var ind = 2;

    for(var f = g; f > 0; f--) {
      dig += parseInt(num.charAt(f - 1)) * ind;
      ind = (type == 'CNPJ') && (ind > 8) ? 2 : ind+1;
    }

    dig %= 11;
    dig = (dig < 2) ? 0 : 11-dig;

    return (dig == parseInt(num.charAt(g)));
  }
}

/********** listener.js **********/


UI.Comps.Listener = Class.create();

UI.Comps.Listener.prototype = {

  events: null,

  initialize: function() {
    this.events = new Array();
  },

  dispose: function() {
    for (var i = 0; i < this.events.length; i++)
      if (this.events[i]) {
        this.events[i].obj = null;
        this.events[i] = null;
      }

    this.events.length = 0;
    this.events = null;
  },

  addListener: function(obj, event) {
    if ((obj != null) && (obj != document))
      for (var i = 0; i < this.events.length; i++)
        if (this.events[i] && (this.events[i].obj == obj))
          return;

    var func = event.bind(obj);
      func.obj = obj;

    this.events.push(func);
  },

  removeListener: function(obj) {
    for (var i = 0; i < this.events.length; i++)
      if (this.events[i] && (this.events[i].obj == obj)) {
        this.events[i].obj = null;
        this.events[i] = null;
      }
  },

  call: function() {
    for (var i = 0; this.events && (i < this.events.length); i++)
      if (this.events[i] != null) {
        var ret = this.events[i].apply(this.events[i].obj, $A(arguments));

        if ((typeof ret == 'boolean') && !ret)
          return false;
      }

    return true;
  }
}

function funcInit() {
  if (!document.body) {
    setTimeout(funcInit, 10);
    return;
  }

  UI.disableSelection(document.body);

  document.body.onselectstart = function() {
    return document.activeElement && (document.activeElement.tagName.toLowerCase() == 'input');
  }

  var funcOnScroll = function() {
    if (document.modalFrame && document.modalFrame.showing)
      document.modalFrame._update();
  }

  var funcOnResize = function() {
    if (document.modalFrame && document.modalFrame.showing)
      document.modalFrame._update();

    UI.onResize.call();
  }

  if (window.addEventListener)
    window.addEventListener('DOMMouseScroll', funcOnScroll, false);

  document.body.onscroll = funcOnScroll;
  document.body.onresize = funcOnResize;
  window.onresize = funcOnResize;

  document.body.style.MozUserSelect = '';
}

setTimeout(funcInit, 0);

var scripts = document.getElementsByTagName('script');
if (scripts.length > 0) {
  var loc = window.location.toString().substring(0, window.location.toString().lastIndexOf('/'));
  var src = scripts[0].src;

  src = loc.substring(0, loc.indexOf('/Desktop/')).replace('http://', '');
  src = (src.indexOf('/') > -1) ? src.substring(src.indexOf('/')) : '';

  UI.dirBase = src;
  UI.dirImagens = UI.dirImagens.replace('~', UI.dirBase);
  UI.arqStyles = UI.arqStyles.replace('~', UI.dirBase);
  UI.onResize = new UI.Comps.Listener();
}
scripts = null;


/********** treeview.js **********/


UI.Comps.TreeView = Class.create();

UI.Comps.TreeView.SubDir = 'TreeView/';
UI.Comps.TreeView.Images = ['TreeView_01.gif', 'TreeView_02.gif', 'TreeView_03.gif', 'TreeView_04.gif', 
                            'TreeView_05.gif', 'TreeView_06.gif', 'TreeView_07.gif', 'TreeView_08.gif'];

UI.Comps.TreeView.TreeType = {
  TT_NORMAL: 0,
  TT_CHECK : 1
}

UI.Comps.TreeView.prototype = {

  indent: null,
  nodes: null,
  type: null,
  isTreeView: true,
  onChange: null,

  initialize: function(container, options) {
    this.container = $(container);
    this.type = UI.Comps.TreeView.TreeType.TT_NORMAL;

    if (!this.container.className)
      this.container.className = 'treeView';

    var expanded = false;

    if (options) {
      if (typeof options.type == 'number')
        this.type = options.type;
      else
        if (options.type == 'check')
          this.type = UI.Comps.TreeView.TreeType.TT_CHECK;

      if (typeof options.expanded == 'boolean')
        expanded = options.expanded;
    }

    this.container.style.overflow = 'auto';
    this.indent = (this.container.indent != undefined) ? Math.min(eval('0+'+this.container.indent), 25) : 19;
    this.nodes = new UI.Comps.TreeNodes(this, null, null);
    this.ignoreOnChange = false;

    this._createNodes(null, this.nodes);
    this.rebuildTree(expanded);
  },


  dispose: function() {
    this.nodes.dispose();
    this.nodes = null;

    this.onChange = null;
    this.container = null;
  },

  rebuildTree: function(expanded) {
    this.container.innerHTML = '';
    this.container.appendChild(this.nodes._createNode(0, expanded));

    this.nodes._updateSymbols(0);
    this._updateWidth();
  },

  addNode: function(text, state) {
    var node = this.nodes.add(text, state);
    this.rebuildTree();

    return node;
  },

  removeNode: function(node) {
    this.nodes.remove(node);
    this.rebuildTree();
  },

  setXML: function(xml) {
    xmldoc = UI.parseXML(xml);
    this.nodes.clear();

    this.nodes._addXml(xmldoc.documentElement.childNodes);
    this.rebuildTree();
  },

  getXML: function() {
    var xmldoc = UI.parseXML(UI.xmlHeader + '<nodes></nodes>');
    this.nodes._getXml(xmldoc, xmldoc.documentElement);

    return UI.readXML(xmldoc);
  },

  _updateWidth: function() {
    this.container.align = 'left';
    this.container.childNodes[0].style.width = this.nodes._maxWidth(0) + 'px';
  },

  _createNodes: function(owner, nodes) {
    var list = UI.getChildNodes(this.container, owner, 'node');

    for (var i = 0; i < list.length; i++) {
      var current = nodes.add(list[i].getAttribute('text'), list[i].getAttribute('state'));
      var id = list[i].getAttribute('id');
      if (id)
        current.id = id;

      current._node = list[i];
      this._createNodes(list[i], current);
    }
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.TreeView, index);
  }
}

UI.Comps.TreeNodes = Class.create();

UI.Comps.TreeNodes.prototype = {

  treeview: null,
  parent: null,
  text: null,
  state: null,
  level: -1,
  id: null,

  initialize: function(treeview, parent, text, state) {
    this.treeview = treeview;
    this.parent = parent;
    this.text = text;
    this.state = state || 0;

    this.table = null;
    this.trParent = null;
    this.img = null;
    this.collapsed = true;
    this.chk = null;
    this.link = null;

    this.count = 0;
    this.nodes = new Array();
  },

  dispose: function() {
    this.clear();
    this.nodes.length = 0;
    this.nodes = null;

    this.link = null;
    this.chk = null;
    this.trParent = null;
    this.table = null;
    this.img = null;
    this.parent = null;
    this.treeview = null;
  },

  add: function(text, state) {
    var node = new UI.Comps.TreeNodes(this.treeview, this, text, state);
    node.level = this.level + 1;
    this.nodes.push(node);
    this.count++;

    return node;
  },

  remove: function(node) {
    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i] == node) {
        this.nodes[i].dispose();
        this.nodes[i] = null;
        this.count--;
        break;
      }
  },

  clear: function() {
    for (var i = 0; i < this.count; i++) {
      this.nodes[i].dispose();
      this.nodes[i] = null;
    }

    this.count = 0;
    this.nodes.length = 0;
  },

  checkAll: function() {
    var _oldState = this.treeview.ignoreOnChange;
    this.treeview.ignoreOnChange = true;

    if (this.nodes.length == 0) {
      this._setState(1);
      this._updateCheck();
    } else {
      for (var i = 0; i < this.nodes.length; i++)
        this.nodes[i].checkAll();
      this._updateCheck();
    }

    this.treeview.ignoreOnChange = _oldState;

    if (!this.treeview.ignoreOnChange && this.treeview.onChange)
      this.treeview.onChange.call();
  },

  uncheckAll: function() {
    var _oldState = this.treeview.ignoreOnChange;
    this.treeview.ignoreOnChange = true;

    if (this.nodes.length == 0) {
      this._setState(0);
      this._updateCheck();
    } else {
      for (var i = 0; i < this.nodes.length; i++)
        this.nodes[i].uncheckAll();
      this._updateCheck();
    }

    this.treeview.ignoreOnChange = _oldState;

    if (!this.treeview.ignoreOnChange && this.treeview.onChange)
      this.treeview.onChange.call();
  },

  isChecked: function() {
    if (this.nodes.length == 0)
      return (this.state == 1);

    for (var i = 0; i < this.nodes.length; i++)
      if (!this.nodes[i].isChecked())
        return false;

    return true;
  },

  anyChildChecked: function() {
    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i].isChecked() || this.nodes[i].anyChildChecked())
        return true;

    return false;
  },

  setText: function(text) {
    var tx = (this.treeview.type == UI.Comps.TreeView.TreeType.TT_CHECK) ? '&nbsp;' + text : text;
    this.link.innerHTML = tx;
  },

  _setState: function(state) {
    if (this.state != state) {
      this.state = state;

      if (!this.treeview.ignoreOnChange && this.treeview.onChange)
        this.treeview.onChange.call();
    }
  },

  _addXml: function(nodes) {
    for (var i = 0; i < nodes.length; i++) {
      var caption = nodes[i].getAttribute('caption');
      var state = parseFloat(nodes[i].getAttribute('state'));
      var id = nodes[i].getAttribute('id');

      if ((typeof state != 'number') || ((state != 0) && (state != 1)))
        state = 0;

      var node = this.add(caption, state);
      if (id)
        node.id = id;

      node._addXml(nodes[i].childNodes);
    }
  },

  _getXml: function(xmldoc, nodes) {
    for (var i = 0; i < this.count; i++) {
      var node = xmldoc.createElement('node');

      if (this.nodes[i].id)
        node.setAttribute('id', this.nodes[i].id);
      else
        node.setAttribute('caption', this.nodes[i].text);

      var chk = this.nodes[i].anyChildChecked() || this.nodes[i].isChecked();

      if (chk)
        node.setAttribute('state', '1');

      nodes.appendChild(node);
      this.nodes[i]._getXml(xmldoc, node);
    }
  },

  _createNode: function(level, expanded) {
    var table = document.createElement('table');
    var tbody = document.createElement('tbody');
    this.table = table;
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.width = '100%';
    table.style.tableLayout = 'fixed';

    var tr, td, childTab;

    if (expanded)
      this.collapsed = false;

    if (this.text != null) {
      tr = document.createElement('tr');
      tbody.appendChild(tr);

      for (var i = 0; i < level; i++) {
        td = document.createElement('td');
        td.style.width = this.treeview.indent+'px';

        if (i == level-1) {
          td.align = 'center';

          if (this.nodes.length > 0) {
            this.img = document.createElement('img');
            this.img.src = this.treeview._getImage(this.collapsed ? 3 : 4);
            this.img.onclick = this._btnClick.bind(this, true);

            td.appendChild(this.img);
          }
        }

        tr.appendChild(td);
      }

      td = document.createElement('td');
      td.className = 'treeViewItem';
      td.align = 'left';

      if (this.treeview.type == UI.Comps.TreeView.TreeType.TT_CHECK) {
        this.chk = document.createElement('img');
        this.chk.onclick = this._chkclick.bind(this);
        td.appendChild(this.chk);
        this._updateCheck();
      }

      this.link = document.createElement('a');
      this.link.href = 'javascript: void(0);';
      this.setText(this.text);
      this.link.onclick = function() {
        if (this.treeview.type == UI.Comps.TreeView.TreeType.TT_CHECK)
          this._chkclick();
        else
          this._btnClick();
      }.bind(this);

      this.link.tabIndex = -1;

      td.appendChild(this.link);
      tr.appendChild(td);
    }

    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i]) {
        tr = document.createElement('tr');
        td = document.createElement('td');
        td.colSpan = level+1;

        childTab = this.nodes[i]._createNode(level+1, expanded);
        this.nodes[i].trParent = tr;

        if ((level > 0) && this.nodes[i].collapsed) {
          childTab.style.display = 'none';
          tr.style.display = 'none';
        }

        td.appendChild(childTab);
        tr.appendChild(td);
        tbody.appendChild(tr);
      }

    return table;
  },

  _maxWidth: function(level) {
    var chkIdent = (this.treeview.type == UI.Comps.TreeView.TreeType.TT_CHECK) ? 15 : 0;
    var max = UI.getStringWidth(this.text, 'treeViewItem') + (level * this.treeview.indent) + chkIdent;

    if (!this.collapsed || (level == 0))
      for (var i = 0; i < this.nodes.length; i++)
        if (this.nodes[i])
          max = Math.max(max, this.nodes[i]._maxWidth(level+1));

    return max;
  },

  _updateCheck: function(updateParent) {
    if (this.chk) {
      var img = '';

      if (this.isChecked())
        img = this.treeview._getImage(5); // checked
      else
        if (this.anyChildChecked())
          img = this.treeview._getImage(7); // grayed
        else
          img = this.treeview._getImage(6); // unchecked

      setTimeout((function() { this.chk.src = img; }).bind(this), 0);
    }

    if (updateParent && this.parent)
      this.parent._updateCheck(updateParent);
  },

  _chkclick: function() {
    if (this.nodes.length == 0)
      this._setState(this.state == 1 ? 0 : 1);
    else
      if (this.isChecked())
        this.uncheckAll();
      else
        this.checkAll();

    this._updateCheck(true);
  },

  _btnClick: function(fromImage) {
    this.collapsed = !this.collapsed;
    var disp = this.collapsed ? 'none' : '';
    var ret = undefined;

    if ((this.nodes.length == 0) || !fromImage)
      if (this._node && (this._node.getAttribute('onItemClick') != undefined))
        ret = this._execute(this._node.getAttribute('onItemClick'));
      else {
        var evt = this.treeview.container.onItemClick;
        if (!evt)
          evt = this.treeview.container.getAttribute('onItemClick');

        if (evt != undefined)
          ret = this._execute(evt);
      }

    if ((this.nodes.length > 0) && ((typeof ret != 'boolean') || ret || fromImage)) {
      var func = function() {
        for (var i = 0; i < this.nodes.length; i++) {
          var table = this.nodes[i].table;

          if (this.nodes[i].trParent != null)
            this.nodes[i].trParent.style.display = disp;

          this.nodes[i].table.style.display = disp;
        }

        var s = this.collapsed ? this.treeview._getImage(3) : this.treeview._getImage(4);
        this.img.src = s;
        this.treeview._updateWidth();
      }

      setTimeout(func.bind(this), 0);
    }
  },

  _execute: function(event) {
    if (typeof event != 'function') {
      var func = new Function(event).bind(this._node);
      return func(this);
    } else
      return event(this, this._node);
  },

  _itemCount: function() {
    var cnt = 0;

    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i])
        cnt += 1 + this.nodes[i]._itemCount();

    return cnt;
  },

  _getItem: function(index) {
    var obj = new Object();
    obj.index = index+1;
    obj.retorno = null;

    this._internoGetItem(obj);
    return obj.retorno;
  },

  _internoGetItem: function(obj) {
    if (obj.index == 0) {
      obj.retorno = this;
      return;
    }

    obj.index--;

    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i]) {
        this.nodes[i]._internoGetItem(obj);

        if (obj.retorno != null)
          return;
      }
  },

  _updateSymbols: function(level) {
    var cnt = 0;
    var nodeCount = 0;

    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i])
        nodeCount++;

    for (var i = 0; i < this._itemCount(); i++) {
      var node = this._getItem(i);

      if (node) {
        if (node.level == level)
          cnt++;

        if (cnt < nodeCount)
          if (node.level > level)
            node._setSymbol(level, 2);

        if (node.level == level)
          if (cnt == nodeCount)
            node._setSymbol(level, 1);
          else
            node._setSymbol(level, 0);

        if (cnt == nodeCount)
          break;
      }
    }

    for (var i = 0; i < this.nodes.length; i++)
      if (this.nodes[i])
        this.nodes[i]._updateSymbols(level+1);
  },

  _setSymbol: function(level, imgIdx) {
    if (this.level < level)
      return;

    var tds = this.table.getElementsByTagName('td');
    tds[level].style.backgroundImage = 'url("'+this.treeview._getImage(imgIdx)+'")';
  }
}


/********** popup.js **********/


UI.Comps.Popup = Class.create();

UI.Comps.Popup.prototype = {

  popup: null,
  showing: false,

  initialize: function() {
  },

  dispose: function() {
    this.popup.dispose();
    this.popup = null;
  },

  Show: function(x, y, objWidth, objHeight) {
    if (this.showing)
      this.Close();

    this.popup._createComponents();
    this.popup._show(x, y, objWidth, objHeight);
    this.showing = true;
  },

  Close: function() {
    if (this.showing) {
      this.popup._destroyComponents();
      this.showing = false;
    }
  }
}

UI.Comps.PopupItem = Class.create();

UI.Comps.PopupItem.prototype = {

  initialize: function(popup, parent, caption) {
    this.popup = popup;
    this.parent = parent;
    this.caption = caption;

    this.frame = null;
    this.showing = false;
    this._x = 0;
    this._y = 0;
    this._height = 0;
    this._width = 0;
    this.timeout = null;
    this.doc = null;
    this.btn = null;
  },

  dispose: function() {
    this.parent = null;
    this.popup = null;
  },

  _getWidth: function() {
    return 50;
  },

  _getHeight: function() {
    return 50;
  },

  _createContents: function(doc) {
  },

  _destroyContents: function() {
  },

  _getHTMLFrame: function() {
    var s = '<html>';
    s += '<body topmargin="0" leftmargin="0" style="-moz-user-focus: normal">';
    s += '<input type="text" style="position: absolute; top: -1000px; width: 0px; height: 0px">';
    s += '</body></html>';

    return s;
  },

  _onfocus: function() {
    var item = this;
    while (item.parent != null)
      item = item.parent;

    if (item.timeout != null) {
      clearTimeout(item.timeout);
      item.timeout = null;
    }
  },

  _onblur: function() {
    var item = this;
    while (item.parent != null)
      item = item.parent;

    item.timeout = setTimeout((function() {item.timeout = null; item.popup.Close();}).bind(item), 100);
  },

  _onkeydown: function(key, evt) {
  },

  _createComponents: function() {
    this.frame = document.createElement('iframe');
    this.frame.style.position = 'absolute';
    this.frame.frameBorder = 0;
    this.frame.style.display = 'none';
    this.frame.className = 'popup';
    this.frame.scrolling = 'no';
    document.body.appendChild(this.frame);

    this.doc = UI.getDocumentFromIframe(this.frame);

    this.doc.open();
    this.doc.write(this._getHTMLFrame());
    this.doc.close();

    this.btn = this.doc.getElementsByTagName('input')[0];
    this.btn.onkeydown = function(doc, evt) {
      var wnd = doc.parentWindow || doc.defaultView;

      evt = evt || wnd.event || window.event;
      var keyCode = evt.keyCode || evt.charCode || evt.which;
      return this._onkeydown(keyCode, evt);
    }.bind(this, this.doc);

    this._createContents(this.doc);

    this._height = this._getHeight();
    this._width = this._getWidth();
    this.frame.style.height = this._height + 'px';
    this.frame.style.width = this._width + 'px';
  },

  _destroyComponents: function() {
    if (this.showing)
      this._hide();

    this._destroyContents();

    this.doc.body.onfocus = null;
    this.doc.body.onblur = null;
    document.body.removeChild(this.frame);
    this.btn = null;
    this.doc = null;
    this.frame = null;
  },

  _show: function(x, y, objWidth, objHeight) {
    if (this.showing)
      this._hide();

    if (x+this._width > document.body.clientWidth)
      x = Math.max(x - this._width + (objWidth ? objWidth : 0), 0);

    if (y+this._height > document.body.clientHeight)
      y = Math.max(y - this._height + (objHeight ? objHeight : 0), 0);

    this._x = x;
    this._y = y;
    this.frame.style.left = x + 'px';
    this.frame.style.top = y + 'px';
    this.frame.style.display = 'inline';
    this.showing = true;

    this.btn.onfocus = this._onfocus.bind(this);
    this.btn.onblur = this._onblur.bind(this);

    if (this.parent == null)
      this.btn.focus();
  },

  _hide: function() {
    if (this.showing) {
      this.doc.body.onfocus = null;
      this.doc.body.onblur = null;

      this.frame.style.display = 'none';
      this.showing = false;
    }
  }
}


/********** popupmenu.js **********/


UI.Comps.PopupMenu = Class.create();

UI.Comps.PopupMenu.SubDir = 'PopupMenu/';
UI.Comps.PopupMenu.Images = ['PopupMenu_01.gif'];

UI.Comps.PopupMenu.prototype = UI.extend(UI.Comps.Popup, {

  itemHeight: 17,
  count: 0,
  popup: null,
  onItemsChange: null,

  initialize: function() {
    this.superclass.initialize.call(this);

    this.popup = new UI.Comps.PopupMenuItem(this, null, '');
  },

  dispose: function() {
    this.Clear();
    this.superclass.dispose.call(this);
  },

  AddItem: function(caption) {
    var item = this.popup.AddItem(caption);
    this.count++;

    if (this.onItemsChange)
      this.onItemsChange();

    return item;
  },

  Clear: function() {
    if (this.count > 0) {
      this.popup.Clear();
      this.count = 0;

      if (this.onItemsChange)
        this.onItemsChange();
    }
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.PopupMenu, index);
  }
});

UI.Comps.PopupMenuItem = Class.create();

UI.Comps.PopupMenuItem.prototype = UI.extend(UI.Comps.PopupItem, {

  initialize: function(popup, parent, caption) {
    this.superclass.initialize.call(this, popup, parent, caption);

    this.items = new Array();
    this.count = 0;
    this.tr = null;
  },

  dispose: function() {
    this.Clear();
    this.items = null;
    this.tr = null;

    this.superclass.dispose.call(this);
  },

  AddItem: function(caption) {
    var item = new UI.Comps.PopupMenuItem(this.popup, this, caption);
    this.items.push(item);
    this.count++;

    return item;
  },

  Clear: function() {
    for (var i = 0; i < this.items.length; i++) {
      this.items[i].dispose();
      this.items[i] = null;
    }
    this.count = 0;
  },

  _getWidth: function() {
    var max = 50;
    var owner = document.createElement('div');
    owner.display = 'none';
    document.body.appendChild(owner);

    for (var i = 0; i < this.items.length; i++) {
      var w = UI.getTextWidth(this.items[i].caption, owner, 'popupMenuItemNormal') + 6;

      if (this.items[i].count > 0)
        w += 15;

      max = Math.max(max, w);
    }

    document.body.removeChild(owner);
    return max + 2;
  },

  _getHeight: function() {
    var h = 2;

    for (var i = 0; i < this.count; i++)
      h += (this.items[i].caption == '-') ? 1 : this.popup.itemHeight;

    return h;
  },

  _createContents: function(doc) {
    var table = doc.createElement('table');
    var tbody = doc.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.className = 'popupMenu';

    for (var i = 0; i < this.count; i++) {
      var css = doc.createElement("link");
      css.rel = "stylesheet";
      css.href = UI.arqStyles;
      css.type = "text\/css";
      doc.body.appendChild(css);

      var tr = doc.createElement('tr');
      var td1 = doc.createElement('td');
      var td2 = null;
      this.items[i].tr = tr;

      if (this.items[i].caption != '-') {
        tr.height = this.popup.itemHeight + 'px';
        td1.className = 'popupMenuItemNormal';
        td1.style.paddingLeft = '3px';
        td1.style.paddingRight = '3px';
        td1.style.cursor = 'default';

        td1.innerHTML = this.items[i].caption;
      } else {
        tr.height = '1px';
        td1.className = 'popupMenuBreakLine';
      }

      if (this.items[i].count > 0) {
        td2 = doc.createElement('td');
        td2.style.width = '15px';
        td2.align = 'center';
        td2.className = 'popupMenuItemNormal';

        var img = doc.createElement('img');
        img.src = this.popup._getImage(0);

        td2.appendChild(img);
        tr.appendChild(td1);
        tr.appendChild(td2);
      } else {
        td1.colSpan = 2;
        tr.appendChild(td1);
      }

      if (this.items[i].caption != '-') {
        td1.onmouseover = this._onmouseover.bind(this, i, tr);
        td1.onmouseout = this._onmouseout.bind(this, i, tr);

        if (td2) {
          td2.onmouseover = this._onmouseover.bind(this, i, tr);
          td2.onmouseout = this._onmouseout.bind(this, i, tr);
        }
      }
      td1.onclick = this._onclick.bind(this, i);

      tbody.appendChild(tr);
    }

    doc.body.appendChild(table);
    table.style.width = this._getWidth();
  },

  _destroyContents: function() {
    this.tr = null;
  },

  _createComponents: function() {
    this.superclass._createComponents.call(this);

    for (var i = 0; i < this.count; i++)
      if (this.items[i].count > 0)
        this.items[i]._createComponents();
  },

  _destroyComponents: function() {
    for (var i = 0; i < this.count; i++)
      if (this.items[i].count > 0)
        this.items[i]._destroyComponents();

    this.superclass._destroyComponents.call(this);
  },

  _show: function(x, y, objWidth, objHeight) {
    for (var i = 0; i < this.count; i++)
      if (this.items[i].caption != '-')
        for (var j = 0; j < this.items[i].tr.childNodes.length; j++)
          this.items[i].tr.childNodes[j].className = 'popupMenuItemNormal';

    this.superclass._show.call(this, x, y, objWidth, objHeight);
  },

  _hide: function() {
    this.superclass._hide.call(this);

    for (var i = 0; i < this.count; i++)
      if (this.items[i].showing)
        this.items[i]._hide();
  },

  _onmouseover: function(index, tr) {
    tr.childNodes[0].className = 'popupMenuItemSelected';

    if (tr.childNodes.length > 1)
      tr.childNodes[1].className = 'popupMenuItemSelected';

    for (var i = 0; i < this.count; i++)
      if (this.items[i].showing && (i != index)) {
        this.items[i]._hide();
        this._onmouseout(i, this.items[i].tr);
      }

    if ((this.items[index].count > 0) && !this.items[index].showing) {
      var x = this._x + this._width - 2;
      var y = this._y + index * this.popup.itemHeight;

      this.items[index]._show(x, y, -(this._width-4), -this._height);
    }
  },

  _onmouseout: function(index, tr) {
    if (!this.items[index].showing) {
      tr.childNodes[0].className = 'popupMenuItemNormal';

      if (tr.childNodes.length > 1)
        tr.childNodes[1].className = 'popupMenuItemNormal';
    }
  },

  _onclick: function(index) {
    if ((this.items[index].count == 0) && (this.items[index].caption != '-')) {
      this.popup.Close();

      if (this.items[index].onclick)
        this.items[index].onclick.call(this.popup, this.items[index]);
    } else
      this.btn.focus();
  }
});


/********** scroll.js **********/


UI.Comps.Scroll = Class.create();
UI.Comps.Scroll.VERT = 0;
UI.Comps.Scroll.HORZ = 1;

UI.Comps.Scroll.prototype = {

  owner: null,
  orientation: UI.Comps.Scroll.VERT,
  position: 0,
  onScroll: null,

  initialize: function(owner, orientation) {
    this.owner = (typeof(owner) == 'object') ? owner : $(owner);
    this.orientation = orientation || this.orientation;
    this._scrollSize = UI.getScrollSize(this.owner);

    this._dv = null;
    this._dvScroll = null;
    this._visible = false;

    this.owner.innerHTML = '';
    this._createScroll();
  },

  dispose: function() {
    this._destroyScroll();
    this.owner = null;
  },

  setSize: function(size) {
    if (this.orientation == UI.Comps.Scroll.VERT)
      this._dvScroll.style.height = size+'px';
    else
      this._dvScroll.style.width = size+'px';

    this._refreshSize();
  },

  setPosition: function(position) {
    this.position = position;
    if (this.orientation == UI.Comps.Scroll.VERT)
      this.dv.scrollTop = position;
    else
      this.dv.scrollLeft = position;
  },

  getBarSize: function() {
    return (this._visible) ? this._scrollSize+1 : 1;
  },

  _createScroll: function() {
    this.dv = document.createElement('div');
    this.dv.className = (this.orientation == UI.Comps.Scroll.VERT) ? 'scrollVert' : 'scrollHorz';
    this.dv.onscroll = this._onScroll.bind(this);
    this.dv.onmousewheel = function() { return false; };
    this._dvScroll = document.createElement('div');
    this._dvScroll.style.fontSize = '0px';

    if (this.orientation == UI.Comps.Scroll.VERT) {
      this._dvScroll.style.width = '1px';
      this.dv.style.width = (this._scrollSize+1)+'px';
      this.owner.style.width = this.dv.style.width;
      this.dv.style.height = this.owner.clientHeight+'px';
    } else {
      this._dvScroll.style.height = '0px';
      this.dv.style.height = (this._scrollSize+1)+'px';
      this.owner.style.height = this.dv.style.height;
      this.dv.style.width = '100%';
    }

    this._refreshSize();

    this.dv.appendChild(this._dvScroll);
    this.owner.appendChild(this.dv);
  },

  _destroyScroll: function() {
    this._dv.removeChild(this._dvScroll);
    this.owner.removeChild(this._dv);

    this._dvScroll = null;
    this._dv = null;
  },

  _refreshSize: function() {
    if (this.orientation == UI.Comps.Scroll.VERT) {
      this.owner.style.display = '';
      this._visible = (this._dvScroll.offsetHeight > this.dv.offsetHeight);
      this.dv.style.width = (this._scrollSize+1)+'px';
      this.owner.style.width = this.dv.style.width;
      this.owner.style.display = this._visible ? '' : 'none';
    } else {
      this.owner.style.display = '';
      this._visible = (this._dvScroll.offsetWidth > this.dv.offsetWidth);
      this.dv.style.height = (this._scrollSize+1)+'px';
      this.owner.style.height = this.dv.style.height;
      this.owner.style.display = this._visible ? '' : 'none';
    }
  },

  _doScroll: function(position) {
    if (this.position != position) {
      this.position = position;

      if (this.onScroll)
        this.onScroll(position);
    }
  },

  _onScroll: function() {
    p = (this.orientation == UI.Comps.Scroll.VERT) ? this.dv.scrollTop : this.dv.scrollLeft;
    this._doScroll(p);
  }
}


/********** tabcontrol.js **********/


UI.Comps.TabControl = Class.create();

UI.Comps.TabControl.SubDir = 'TabControl/';
UI.Comps.TabControl.Images = ['TabControl_01.gif', 'TabControl_02.gif', 'TabControl_03.gif',
                           'TabControl_04.gif', 'TabControl_05.gif'];

UI.Comps.TabControl.prototype = {

  tabs: null,
  url: null,
  closeButton: false,
  selectedIndex: -1,
  onChange: null,

  initialize: function(container, options) {
    this.container = $(container);

    this.tabs = new Array();
    this.buttons = new Array();
    this.url = this.container.getAttribute('url') || null;
    this.tabsHeight = this.container.getAttribute('tabsHeight') || 18;
    this.tabIndent = this.container.getAttribute('tabIndent') || 7;
    this.tabLeftMargin = this.container.getAttribute('tabLeftMargin') || 9;
    this.tabRightMargin = this.container.getAttribute('tabRightMargin') || 23;
    this.closeButton = this.container.getAttribute('closeButton');
    this.buttonWidth = this.container.getAttribute('buttonWidth') || 11;
    this._containerWidth = this.container.clientWidth;

    if (this.closeButton == "false")
      this.closeButton = false;

    if (options) {
      if (typeof options.url == 'string')
        this.url = options.url;

      if (typeof options.closeButton == 'boolean')
        this.closeButton = options.closeButton;
    }

    this.dvTabs = null;
    this.trTabs = null;
    this.tdPages = null;
    this.tdButtons = null;
    this.frame = null;

    this.frm = document.createElement('iframe');
    this.frm.style.position = 'absolute';
    this.frm.style.display = 'none';
    this.container.appendChild(this.frm);

    var tt = this._initializeComponents();
    this._initializeTabs();

    UI.setEvent('resize', this._onResize, this);
    this._onResize(null);

    this.container.appendChild(tt);
    UI.resize(this.container);

    this.onChange = new UI.Comps.Listener();
  },

  dispose: function() {
    this.onChange.dispose();
    this.onChange = null;

    this.container.removeChild(this.frm);

    UI.clearEvent('resize', this._onResize, this);

    for (var i = 0; i < this.tabs.length; i++) {
      this.tabs[i].dispose();
      this.tabs[i] = undefined;
    }

    this.tabs.length = 0;
    this.tabs = null;
    this.dvTabs = null;
    this.trTabs = null;
    this.tdPages = null;
    this.tdButtons = null;
    this.frame = null;
    this.frm = null;
  },

  addTab: function(title, url, tabId, visible) {
    return new UI.Comps.Tab(this, title, url, tabId, visible);
  },

  closeTab: function(index, force) {
    if ((index < 0) || (index >= this.tabs.length))
      return;

    if (!force) {
      var atrib = this.tabs[index]._node.getAttribute('onClose');

      if (atrib == undefined)
        atrib = this.container.getAttribute('onClose');

      if (atrib != undefined) {
        var func = new Function(atrib).bind(this.tabs[index]._node);
        if (!func())
          return;
      }
    }

    var tabs = new Array();

    this.tabs[index].dispose();

    for (var i = 0; i < this.tabs.length; i++)
      if (i != index)
        tabs.push(this.tabs[i]);

    this.tabs = tabs;

    if (this.selectedIndex == this.tabs.length)
      this.selectedIndex--;

    if (this.selectedIndex > -1)
      this.tabs[this.selectedIndex]._onclick();
    else
      this._updateTabs();
  },

  selectTab: function(index) {
    this.tabs[index]._onclick();
  },

  getTab: function(id) {
    for (var i = 0; i < this.tabs.length; i++)
      if (this.tabs[i].id == id)
        return this.tabs[i];

    return null;
  },

  addChangeListener: function(obj, event) {
    if (this.onChange)
      this.onChange.addListener(obj, event);
  },

  removeChangeListener: function(obj, event) {
    if (this.onChange)
      this.onChange.removeListener(obj, event);
  },

  _createTable: function() {
    var table = document.createElement('table');
    var tbody = document.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.style.tableLayout = 'fixed';

    return table;
  },

  _initializeComponents: function() {
    var table = this._createTable();
    table.style.width = '100%';
    table.style.height = '100%';

    this.trTabs = document.createElement('tr');
    table.childNodes[0].appendChild(this.trTabs);
    this.trTabs.style.height = this.tabsHeight + 'px';

    var tdTabs = document.createElement('td');
    this.trTabs.appendChild(tdTabs);

    this.dvTabs = document.createElement('div');
    tdTabs.appendChild(this.dvTabs);
    this.dvTabs.style.overflow = 'hidden';
    this.dvTabs.style.height = this.tabsHeight + 'px';

    this.tdButtons = document.createElement('td');
    this.trTabs.appendChild(this.tdButtons);

    var trPages = document.createElement('tr');
    table.childNodes[0].appendChild(trPages);

    this.tdPages = document.createElement('td');
    trPages.appendChild(this.tdPages);
    this.tdPages.colSpan = 2;
    this.tdPages.className = 'tabControl';

    return table;
  },

  _initializeTabs: function() {
    var tabs = UI.getChildNodes(this.container, null, 'tab');

    for (var i = 0; i < tabs.length; i++) {
      var tabId = tabs[i].getAttribute('tabId') || '';
      var vis = !(tabs[i].getAttribute('visible') == 'false');

      var tab = this.addTab(tabs[i].getAttribute('title'), tabs[i].getAttribute('url'), tabId, vis);
      tab._node = tabs[i];
    }
  },

  _updateTabs: function() {
    var btnWidth = this._updateButtons();
    var maxWidth = this.container.offsetWidth - btnWidth - 2;
    var cnt = 0, l = 0, width = this.tabIndent;

    for (var i = this.dvTabs.childNodes.length-1; i >= 0; i--)
     this.dvTabs.removeChild(this.dvTabs.childNodes[i]);

    for (var i = 0; i < this.tabs.length; i++)
      if (this.tabs[i].visible) {
        width += this.tabs[i].width - this.tabIndent;

        if ((width >= maxWidth) && (i >= this.selectedIndex))
          break;

        if (i != this.selectedIndex) {
          var dv = this.tabs[i].dvTab;
          this.dvTabs.appendChild(dv);
          dv.style.top = cnt + 'px';
          cnt -= 18;
        }
      }

    if (this.selectedIndex > -1) {
      var dv = this.tabs[this.selectedIndex].dvTab;
      this.dvTabs.appendChild(dv);
      dv.style.top = (cnt + 1) + 'px';
    }

    for (var i = 0; i < this.tabs.length; i++) {
      this.tabs[i].dvTab.style.left = l + 'px';
      l += this.tabs[i].width - this.tabIndent;
    }

    this._updateFrame();
  },

  _updateFrame: function() {
    for (var i = this.tdPages.childNodes.length-1; i >= 0; i--)
      this.tdPages.childNodes[i].style.display = 'none';

    var tab = (this.selectedIndex > -1) ? this.tabs[this.selectedIndex] : this;
    var frame = tab._getFrame();

    if (frame != null) {
      frame.style.display = 'inline';
      this.frm.contentWindow.location = 'about:blank';
    }

    this.trTabs.style.display = (this.tabs.length > 0) ? UI.defaultDisplay : 'none';
  },

  _updateButtons: function() {
    var closeVisible = (this.closeButton && (this.tabs.length > 0));
    var maxTabsWidth = this.container.offsetWidth - (closeVisible ? this.buttonWidth : 0) - 2;
    var tabsWidth = this.tabIndent + this.buttonWidth;

    for (var i = 0; i < this.tabs.length; i++)
      tabsWidth += this.tabs[i].width - this.tabIndent;

    for (var i = this.tdButtons.childNodes.length-1; i >= 0; i--)
      this.tdButtons.removeChild(this.tdButtons.childNodes[i]);

    var popupVisible = (maxTabsWidth <= tabsWidth);
    var qtdButtons = (closeVisible ? 1 : 0) + 1;
    var width = (qtdButtons > 0) ? this.buttonWidth * qtdButtons : 1;

    this.tdButtons.style.width = width + 'px';
    this.tdButtons.align = 'right';

    var table = this._createTable();
    var tr = document.createElement('tr');
    table.childNodes[0].appendChild(tr);

    if (popupVisible) {
      var button = document.createElement('img');
      button.src = this._getImage(3);
      button.style.cursor = 'pointer';
      button.style.position = 'relative';
      button.onclick = this._onpopupclick.bind(this);

      var td = document.createElement('td');
      td.align = 'right';
      tr.appendChild(td);
      td.appendChild(button);
    }

    if (closeVisible) {
      var button = document.createElement('img');
      button.src = this._getImage(1);
      button.style.cursor = 'pointer';
      button.style.position = 'relative';
      button.onclick = this._oncloseclick.bind(this);

      var td = document.createElement('td');
      td.align = 'right';
      tr.appendChild(td);
      td.appendChild(button);
    }

    this.tdButtons.appendChild(table);

    return width;
  },

  _getFrame: function() {
    if ((this.frame == null) && this.url) {
      this.frame = document.createElement('iframe');
      this.frame.style.backgroundColor = 'white';
      this.frame.frameBorder = '0';
      this.frame.style.width = '100%';
      this.frame.style.height = '100%';
      this.frame.style.display = 'none';
      this.frame.src = this.url;
      this.tdPages.appendChild(this.frame);
    }
    return this.frame;
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.TabControl, index);
  },

  _onpopupclick: function() {
    var popup = new UI.Comps.PopupMenu();

    for (var i = 0; i < this.tabs.length; i++) {
      var item = popup.AddItem(this.tabs[i].title);
      item.onclick = this.selectTab.bind(this, i);
    }

    var p = UI.getAbsolutePosition(this.tdButtons);
    popup.Show(p.x, p.y+this.tdButtons.offsetWidth, this.tdButtons.offsetHeight);
  },

  _oncloseclick: function() {
    this.closeTab(this.selectedIndex);
  },

  _onResize: function(ev) {
    if (this._containerWidth != this.container.clientWidth) {
      this._updateTabs();
      this._containerWidth = this.container.clientWidth;
    }
  }
}

UI.Comps.Tab = Class.create();

UI.Comps.Tab.prototype = {

  id: '',
  title: '',
  url: '',
  selected: false,
  visible: true,
  completed: false,

  initialize: function(tabcontrol, title, url, tabId, visible) {
    this.tabcontrol = tabcontrol;
    this.title = title;
    this.url = url;

    this.frame = null;
    this.dvTab = null;
    this.tdTitle = null;
    this.width = 0;

    if (typeof visible == 'boolean')
      this.visible = visible;

    if (typeof tabId == 'string')
      this.id = tabId;

    this.selected = (this.tabcontrol.tabs.length == 0) && this.visible;
    this.tabcontrol.tabs.push(this);
    this._createComponents();

    if (this.selected)
      this._onclick();
    else
      this._update(true);
  },

  dispose: function() {
    if (this.frame != null) {
      var doc = UI.getDocumentFromIframe(this.frame);

      if (doc) {
        doc.open();
        doc.close();
      }

      this.tabcontrol.tdPages.removeChild(this.frame);
    }

    this._node = null;
    this.tabcontrol = null;
    this.dvTab = null;
    this.tdTitle = null;
    this.frame = null;
  },

  setVisible: function(value) {
    this.visible = value;

    if (value) {
      if (this.tabcontrol.selectedIndex > -1)
        for (var i = 0; i < this.tabcontrol.tabs.length; i++)
          if (this.tabcontrol.tabs[i].visible) {
            this._update(true);
            return;
          }

      this._onclick();
    } else {
      if (this.tabcontrol.selectedIndex > -1)
        if (this.tabcontrol.tabs[this.tabcontrol.selectedIndex] == this)
          this.tabcontrol.selectedIndex = -1;

      this.selected = false;
      this._update(true);
    }
  },

  _createComponents: function() {
    this.dvTab = document.createElement('div');
    this.dvTab.style.cursor = 'pointer';
    this.dvTab.style.position = 'relative';
    this.dvTab.onclick = this._onclick.bind(this);

    var table = this.tabcontrol._createTable();
    var tr = document.createElement('tr');
    table.childNodes[0].appendChild(tr);

    var tdLeft = document.createElement('td');
    tr.appendChild(tdLeft);
    tdLeft.width = this.tabcontrol.tabLeftMargin;
    var imgLeft = document.createElement('img');
    tdLeft.appendChild(imgLeft);
    imgLeft.src = this.tabcontrol._getImage(2);

    this.tdTitle = document.createElement('td');
    tr.appendChild(this.tdTitle);
    this.tdTitle.innerHTML = this.title;
    this.tdTitle.style.backgroundImage = 'url(' + this.tabcontrol._getImage(0) + ')';

    var tdRight = document.createElement('td');
    tr.appendChild(tdRight);
    tdRight.width = this.tabcontrol.tabRightMargin;
    var imgRight = document.createElement('img');
    tdRight.appendChild(imgRight);
    imgRight.src = this.tabcontrol._getImage(4);

    this.dvTab.appendChild(table);
  },

  _getFrame: function() {
    if (this.frame == null) {
      var funcStateChange = function(timedOut) {
        if (this.frame.readyState == 'complete') {
          this.completed = true;
          var doc = UI.getDocumentFromIframe(this.frame);

          if (!timedOut)
            setTimeout(funcStateChange.bind(this, true), 1);
          else
            if (doc && doc.grid)
              doc.grid.focus();
        }
      }

      this.frame = document.createElement('iframe');
      this.frame.style.backgroundColor = 'white';
      this.frame.frameBorder = '0';
      this.frame.scrolling = 'no';
      this.frame.style.width = '100%';
      this.frame.style.height = '100%';
      this.frame.src = this.url;
      this.frame.style.display = 'none';
      this.frame.onreadystatechange = funcStateChange.bind(this);

      this.tabcontrol.tdPages.appendChild(this.frame);
    }

    return this.frame;
  },

  _update: function(updateTabs) {
    this.tdTitle.className = this.selected ? 'tabControlItemSelected' : 'tabControlItemNormal';

    this.width = this.tabcontrol.tabLeftMargin +
                 UI.getTextWidth(this.title, this.tabcontrol.container, this.tdTitle.className) +
                 this.tabcontrol.tabRightMargin;

    this.dvTab.childNodes[0].width = this.width+'px';
    this.dvTab.style.width = this.width+'px';
    this.dvTab.height = this.tabcontrol.tabsHeight+'px';
    this.tdTitle.style.width = (this.width - this.tabcontrol.tabLeftMargin - this.tabcontrol.tabRightMargin) + 'px';

    if (updateTabs)
      this.tabcontrol._updateTabs();
  },

  _onclick: function() {
    for (var i = 0; i < this.tabcontrol.tabs.length; i++)
      if (this.tabcontrol.tabs[i].frame) {
        var doc = UI.getDocumentFromIframe(this.tabcontrol.tabs[i].frame);

        if (doc.readyState != 'complete')
          return false;
      }

    for (var i = 0; i < this.tabcontrol.tabs.length; i++) {
      var tab = this.tabcontrol.tabs[i];
      tab.selected = (this.tabcontrol.tabs[i] == this) && this.tabcontrol.tabs[i].visible;
      tab._update(false);

      if (tab.selected)
        this.tabcontrol.selectedIndex = i;
    }

    this.tabcontrol._updateTabs();

    if (this.completed) {
      var func = function() {
        var doc = UI.getDocumentFromIframe(this.frame);

        if (doc && doc.grid)
          doc.grid.focus();
      }
      setTimeout(func.bind(this), 1);
    }

    if (this.tabcontrol.onChange)
      this.tabcontrol.onChange.call(this.tabcontrol.selectedIndex);
  }
}


/********** grid.js **********/


UI.Comps.Grid = Class.create();

UI.Comps.Grid.SubDir = 'Grid/';
UI.Comps.Grid.Images = ['Grid_01.gif', 'Grid_02.gif', 'Grid_03.gif', 'Grid_04.gif', 'Grid_05.gif', 
                        'Grid_06.gif', 'Grid_07.gif', 'Grid_08.gif', 'Grid_09.gif', 'Grid_10.gif',
                        'Grid_11.gif', 'Grid_12.gif', 'Grid_13.gif', 'Grid_14.gif', 'Grid_15.gif',
                        'Grid_16.gif', 'Grid_17.gif'];

UI.Comps.Grid.prototype = {

  rowHeight: 18,
  visibleRows: 0,
  firstRow: 0,
  dataset: null,
  barHeight: 20,
  selected: {x: 0, y: 0},
  focused: false,
  title: '',
  buttons: null,
  enabled: true,
  canEdit: false,
  inplace: null,
  orders: null,
  multi: false,
  selectedRows: null,
  selectedAttr: '',

  onDblClick: null,
  onKeyDown: null,
  onConfirm: null,
  onCancel: null,
  onRefreshToolbar: null,

  initialize: function(container, options) {
    this.container = $(container);
    this.columns = new UI.Comps.GridColumns(this);
    this.orders = new UI.Comps.GridOrders(this);

    this.container.style.overflow = 'hidden';
    if (!this.container.className)
      this.container.className = 'grid';

    if ((typeof this.container.style.height == 'string') && (this.container.style.height.indexOf('%') > 0))
      this.container.style.height = document.body.clientHeight;

    this._downColumn = null;
    this._bufKeys = '';
    this.dvGrid = null;
    this.rows = new Array();
    this.btn = null;
    this.lookup = (options && options.lookup);
    this.buttons = new Array();
    this.selectedRows = new Array();

    this.btnFirst = null;
    this.btnPrev = null;
    this.btnNext = null;
    this.btnLast = null;
    this.btnOk = null;
    this.btnCancel = null;

    this.onDblClick = new UI.Comps.Listener();
    this.onKeyDown = new UI.Comps.Listener();
    this.onConfirm = new UI.Comps.Listener();
    this.onCancel = new UI.Comps.Listener();
    this.onRefreshToolbar = new UI.Comps.Listener();

    this.tdSeparator = null;
    this.tdTitle = null;
    this._initializeColumns();
    this._scrollSize = UI.getScrollSize(this.container);
    this.inplaceEntering = false;
    this.ordering = false;
    
    if (options) {
      if (typeof options.ds == 'object')
        this.setDataSet(options.ds);

      if (typeof options.title == 'string')
        this.title = options.title;

      if (typeof options.enabled == 'boolean')
        this.enabled = options.enabled;

      if (typeof options.canEdit == 'boolean')
        this.canEdit = options.canEdit;

      if (typeof options.multi == 'boolean')
        this.multi = options.multi;

      if (typeof options.sels == 'string') {
        var selitems = options.sels.split(',');

        for (var i = 0; i < selitems.length; i++)
          this.selectedRows.push(eval(selitems[i]));
      }

      if (typeof options.selAttr == 'string')
        this.selectedAttr = options.selAttr;

      if (typeof options.orders == 'string') {
        while (options.orders.indexOf(',') >= 0) {
          var order = options.orders.substring(0, options.orders.indexOf(','));
          var fname = order.substring(0, order.indexOf('='));
          var type = order.substring(order.indexOf('=')+1);

          this.orders.add(fname, type);
          options.orders = options.orders.substring(options.orders.indexOf(',')+1);
        }
      }
    }

    this.container.innerHTML = '';
    this._createBackground();

    UI.setEvent('mousedown', this._onResizeColumnDown, this);
    UI.setEvent('mousemove', this._onResizeColumnMove, this);
    UI.setEvent('mouseup', this._onResizeColumnUp, this);

    if (this.lookup)
      this._createLookup();

    if (this.canEdit) {
      var opt = {
        image: this._getImage(14),
        imageDisabled: this._getImage(13),
        visible: false
      };
      this.btnOk = this.addButton(opt);
    
      var opt = {
        image: this._getImage(12),
        imageDisabled: this._getImage(11),
        visible: false
      };
      this.btnCancel = this.addButton(opt);
      
      this.btnOk.onClick = this._onConfirmClick.bind(this);
      this.btnCancel.onClick = this._onCancelClick.bind(this);
    }
  },

  dispose: function() {
    UI.clearEvent('mousedown', this._onResizeColumnDown, this);
    UI.clearEvent('mousemove', this._onResizeColumnMove, this);
    UI.clearEvent('mouseup', this._onResizeColumnUp, this);

    this.onDblClick.dispose();
    this.onDblClick = null;
    this.onKeyDown.dispose();
    this.onKeyDown = null;
    this.onConfirm.dispose();
    this.onConfirm = null;
    this.onCancel.dispose();
    this.onCancel = null;
    this.onRefreshToolbar.dispose();
    this.onRefreshToolbar = null;

    for (var i = 0; i < this.buttons.length; i++)
      this.buttons[i].dispose();
      
    if (this.inplace != null) {
      this.inplace.dispose();
      this.inplace = null;
    }

    this.buttons.length = 0;
    this.buttons = null;

    this.selectedRows.length = 0;
    this.selectedRows = null;

    this.tdTitle = null;
    this.Separator = null;

    this.btnFirst = null;
    this.btnPrev = null;
    this.btnNext = null;
    this.btnLast = null;
    this.btnOk = null;
    this.btnCancel = null;

    if (this.btn.parentNode)
      this.btn.parentNode.removeChild(this.btn);

    this.btn = null;
    this.rows.length = 0;
    this.rows = null;
    this._downColumn = null;
    this.dvGrid = null;
    this.columns.dispose();
    this.columns = null;
    this.orders.dispose();
    this.orders = null;

    this.setDataSet(null);
  },

  setDataSet: function(dataset) {
    if (this.dataset != dataset) {
      if (this.dataset) {
        this.dataset.removeAfterScrollListener(this);
        this.dataset.removeFieldChangeListener(this);
        this.dataset.removeInsertListener(this);
        this.dataset.removeDeleteListener(this);
        this.dataset.removeRefreshListener(this);
      }

      if (this.columns)
        this.columns.clear();

      this.dataset = dataset;

      if (dataset) {
        dataset.addAfterScrollListener(this, this._onAfterScroll);
        dataset.addFieldChangeListener(this, this._onFieldChange);
        dataset.addInsertListener(this, this._onInsert);
        dataset.addDeleteListener(this, this._onDelete);
        dataset.addRefreshListener(this, this._onRefresh);

        for (var i = 0; i < dataset.columns.count; i++) {
          var column = dataset.columns.getColumn(i);

          if (column.visibleColumn) {
            var col = this.columns.add(column);
            col.index = i;
          }
        }
      }

      if (this.dvGrid) {
        this._recreateGrid();
        this._refreshToolbar();
      }
    }
  },

  focus: function() {
    this.btn.focus();

    for (var i = 0; i < this.buttons.length; i++)
      this.buttons[i]._onmouseout();
  },

  addDblClickListener: function(obj, event) {
    this.onDblClick.addListener(obj, event);
  },

  removeDblClickListener: function(obj) {
    this.onDblClick.removeListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    this.onKeyDown.addListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    this.onKeyDown.removeListener(obj);
  },

  addConfirmListener: function(obj, event) {
    this.onConfirm.addListener(obj, event);
  },

  removeConfirmListener: function(obj) {
    this.onConfirm.removeListener(obj);
  },

  addCancelListener: function(obj, event) {
    this.onCancel.addListener(obj, event);
  },

  removeCancelListener: function(obj) {
    this.onCancel.removeListener(obj);
  },

  addRefreshToolbarListener: function(obj, event) {
    this.onRefreshToolbar.addListener(obj, event);
  },

  removeRefreshToolbarListener: function(obj) {
    this.onRefreshToolbar.removeListener(obj);
  },

  addButton: function(options) {
    var td = document.createElement('td');
    td.style.width = '19px';
    this.tdTitle.parentNode.insertBefore(td, this.tdTitle);

    options.parent = td;
    options.caption = (options.caption || '');
    options.height = 18;
    if (options.caption == '')
      options.width = 18;

    var button = new UI.Comps.Button(null, options);
    this.buttons.push(button);

    this.updateButtons();

    return button;
  },

  confirm: function() {
    this._doConfirm();
  },

  cancel: function() {
    this._donCancel();
  },

  getButton: function(id) {
    for (var i = 0; i < this.buttons.length; i++)
      if (this.buttons[i].id == id)
        return this.buttons[i];

    return null;
  },

  updateButtons: function() {
    var visible = false;

    for (var i = 4; i < this.buttons.length; i++)
      if (this.buttons[i].visible) {
        visible = true;
        break;
      }

    this.tdSeparator.style.display = visible ? UI.defaultDisplay : 'none';
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;
      this._refreshToolbar();
      this._refreshSelection();
    }
  },

  update: function() {
    this._fillDataGrid();
    this._refreshToolbar();
    this._refreshSelection();
  },

  editingRecord: function() {
    return (this.dataset) ? (this.dataset.status != UI.Comps.DataSet.RecordState.RS_NORMAL) : false;
  },

  _initializeColumns: function() {
    this.columns.clear();

    var cols = this.container.getElementsByTagName('column');
    var col = null;

    for (var i = 0; i < cols.length; i++) {
      col = this.columns.add();
      col.index = i;
      col.name = cols[i].getAttribute('name');
      col.title = cols[i].getAttribute('name');

      if (cols[i].getAttribute('index'))
        col.index = cols[i].getAttribute('index');

      if (cols[i].getAttribute('title'))
        col.title = cols[i].getAttribute('title');

      if (cols[i].getAttribute('width'))
        col.width = cols[i].getAttribute('width');

      col.width = Math.max(parseInt(col.width), 1);
    }
  },

  _createTable: function() {
    var table = document.createElement('table');
    var tbody = document.createElement('tbody');
    table.appendChild(tbody);
    table.cellSpacing = '0px';
    table.cellPadding = '0px';
    table.style.width = '100%';
    table.style.height = '100%';
    return table;
  },

  _createBackground: function() {
    this.btn = document.createElement('input');
    this.btn.type = 'text';
    this.btn.style.position = 'absolute';
    this.btn.style.top = '-1000px';
    this.container.appendChild(this.btn);

    this.btn.onfocus = this._onfocus.bind(this);
    this.btn.onblur = this._onblur.bind(this);

    this.btn.onkeydown = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._onkeydown(keyCode, window.event || evt);
    }.bind(this);
    
    this.btn.onkeypress = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._onkeypress(keyCode, window.event || evt);
    }.bind(this);

    var dvBar = document.createElement('div');
    dvBar.style.height = this.barHeight+'px';
    dvBar.style.width = '100%';
    dvBar.style.fontSize = '1px';
    dvBar.className = 'gridBar';
    this.container.appendChild(dvBar);

    this.dvGrid = document.createElement('div');
    this.dvGrid.style.width = '100%';
    this.dvGrid.style.height = (this.container.clientHeight-this.barHeight)+'px';
    this.dvGrid.style.overflow = 'auto';
    this.container.appendChild(this.dvGrid);
    this._recreateGrid();
    this._recreateToolbar(dvBar);
  },

  _createLookup: function() {
    var btnEnabled = this.dataset && (this.dataset.count > 0);

    this.addButton({caption: UI.getLanguageTag('select'), enabled: btnEnabled}).onClick = function() {
      this._doConfirm();
    }.bind(this);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.Grid, index);
  },

  _recreateGrid: function() {
    this.visibleRows = Math.floor((this.container.clientHeight-1-this.barHeight-this.rowHeight)/this.rowHeight);
    this.rows.length = 0;

    while (this.dvGrid.childNodes.length > 0)
      this.dvGrid.removeChild(this.dvGrid.childNodes[0]);

    var table = this._createTable();
    table.style.width = '0px';
    table.style.tableLayout = 'fixed';
    this._recreateHeader(table);

    for (var i = 0; i < this.visibleRows; i++) {
      var cells = new Array();
      var tr = document.createElement('tr');
      tr.style.height = this.rowHeight + 'px';

      for (var j = 0; j < this.columns.count; j++) {
        var td = document.createElement('td');
        td.colSpan = 2;
        tr.appendChild(td);

        var dv = document.createElement('div');
        td.appendChild(dv);
        dv.className = 'gridCellHidded';
        dv.innerHTML = '&nbsp;';
        dv.style.overflow = 'hidden';
        dv.style.height = (this.rowHeight - 2) + 'px';

        td.onclick = function(i, dv, j, evt) {
          evt = evt || window.event;

          return this._onCellClick(i, dv, j, evt);
        }.bind(this, i, dv, j);

//        td.onclick = this._onCellClick.bind(this, i, dv, j);
        td.ondblclick = this._onCellDblClick.bind(this, i, dv);
        UI.disableSelection(dv);
        cells.push(dv);
      }
      table.childNodes[0].appendChild(tr);
      this.rows.push(cells);
    }

    var tr = document.createElement('tr');
    var td = document.createElement('td');

    td.innerHTML = '&nbsp;';
    td.style.fontSize = '1px';
    td.colSpan = this.columns.count*2;
    UI.disableSelection(td);
    tr.appendChild(td);
    table.childNodes[0].appendChild(tr);
    this._fillDataGrid();

    this.dvGrid.appendChild(table);
    this._updateGridSize();
  },

  _recreateHeader: function(table) {
    var tr = document.createElement('tr');
    tr.style.height = this.rowHeight+'px';

    for (var i = 0; i < this.columns.count; i++) {
      var td = document.createElement('td');
      this._recreateHeaderCell(i, td);
      UI.disableSelection(td);
      tr.appendChild(td);

      tdSeparator = document.createElement('td');
      tdSeparator.style.width = '1px';
      tdSeparator.td = td;
      tdSeparator.column = this.columns.getColumn(i);

      UI.disableSelection(tdSeparator);
      tdSeparator.style.cursor = 'w-resize';
      tr.appendChild(tdSeparator);
    }

    table.childNodes[0].appendChild(tr);
  },

  _recreateHeaderCell: function(index, td) {
    var col = this.columns.getColumn(index);
    var dv = document.createElement('div');
    var order = this.orders.findField(col.field.name);

    dv.style.width = UI.getStringWidth(col.title) + '10px';
    dv.style.height = (this.rowHeight-2) + 'px';
    dv.style.overflow = 'hidden';
    if (order) {
      var img = document.createElement('img');
      img.src = this._getImage((order.type == 'A') ? 16 : 15);
      img.style.height = '6px';
      dv.appendChild(img);
      dv.appendChild(document.createTextNode(' '+col.title));
    } else
      dv.innerHTML = col.title;

    UI.disableSelection(dv);

    td.className = 'gridCellHeader';
    td.style.width = (col.width + (this.orders.findField(col.field.name) ? 10 : 0)) + 'px';
    td.appendChild(dv);
    td.style.overflow = 'hidden';
    td.onclick = this._orderGrid.bind(this, dv, index);
  },

  _fillCell: function(column, recno, td, row) {
    var col = this.dataset.columns.getColumn(column);

    var clsName = (this.dataset.recno == recno) && (recno > -1) ? 'gridCellSelected' : 'gridCellNormal';

    if (this.multi) {
      var field = this.dataset.findField(this.selectedAttr);

      if (field) {
        var value = field.getValue(recno);

        if (this.selectedRows.indexOf(value) > -1)
          clsName = 'gridCellMarked';
      }
    }

    if ((recno == -1) && (column == 0) && (this.dataset.recno == -1) && (row == 0))
      clsName = 'gridCellFocused';

    var editing = this.editingRecord() && this.dataset && (this.dataset.recno == this.firstRow + row);

    if (editing)
      clsName = (column == this.selected.x) ? 'gridCellEditingFocused' : 'gridCellEditing';

    if (td.className != clsName)
      td.className = clsName;

    var s = (recno > -1) ? col.getDisplayValue(recno) : '';
    if (col.type == 'bool') {
      var imgs = td.getElementsByTagName('img');
      if (imgs.length == 0) {
        while (td.childNodes.length > 0)
          td.removeChild(td.childNodes[0]);

        var img = document.createElement('img');
        img.style.marginTop = '4px';
        td.appendChild(img);
      }

      if (typeof s == 'string')
        if (s == 'true')
          s = true
        else
          if (s == 'false')
            s = false;

      var src = this._getImage(s ? 10 : 9);
      var disp = (recno > -1) ? UI.defaultDisplay : 'none';

      if (td.childNodes[0].src != src)
        td.childNodes[0].src = src;

      if (td.childNodes[0].style.display != disp)
        td.childNodes[0].style.display = disp;
    } else
      td.innerHTML = (s == '') ? '&nbsp' : s;

    if ((col.type == 'number') && (td.align != 'right'))
      td.align = 'right';

    if ((col.type == 'bool') && (td.align != 'center'))
      td.align = 'center';
  },

  _fillDataGrid: function(func) {
    if (this.dataset) {
      if ((this.firstRow+this.rows.length >= this.dataset.count) && !this.dataset.fetched) {
        this.dataset._requestPacket(false, this._fillDataGrid.bind(this, func));
        return;
      }

      for (var recno = this.firstRow; recno < this.firstRow+this.rows.length; recno++) {
        for (var col = 0; col < this.columns.count; col++) {
          var td = this.rows[recno-this.firstRow][col];

          if (recno < this.dataset.count)
            this._fillCell(this.columns.getColumn(col).index, recno, td, recno);
          else
            this._fillCell(this.columns.getColumn(col).index, -1, td, recno);
        }
      }

      if (func)
        func();
    }
  },

  _createToolbarButton: function(parent, image, imageDisabled, tooltip) {
    var params = {image: image, 
                  imageDisabled: imageDisabled, 
                  width: 20, 
                  height: 18, 
                  caption: '', 
                  parent: parent,
                  tooltip: tooltip,
                  enabled: this.enabled
    };
    return new UI.Comps.Button(null, params);
  },

  _recreateToolbar: function(dvBar) {
    dvBar.style.marginLeft = '1px';

    var table = this._createTable();
    table.style.fontSize = '1px';
    var tr = document.createElement('tr');
    table.childNodes[0].appendChild(tr);

    var td = document.createElement('td');
    td.style.width = '21px';
    tr.appendChild(td);
    this.btnFirst = this._createToolbarButton(td, this._getImage(0), this._getImage(1), UI.getLanguageTag('first'));
    this.btnFirst.onClick = this._toolbarButtonClick.bind(this, 'first');
    this.buttons.push(this.btnFirst);

    td = document.createElement('td');
    td.style.width = '21px';
    tr.appendChild(td);
    this.btnPrev = this._createToolbarButton(td, this._getImage(2), this._getImage(3), UI.getLanguageTag('prev'));
    this.btnPrev.onClick = this._toolbarButtonClick.bind(this, 'prev');
    this.buttons.push(this.btnPrev);

    td = document.createElement('td');
    td.style.width = '21px';
    tr.appendChild(td);
    this.btnNext = this._createToolbarButton(td, this._getImage(4), this._getImage(5), UI.getLanguageTag('next'));
    this.btnNext.onClick = this._toolbarButtonClick.bind(this, 'next');
    this.buttons.push(this.btnNext);

    td = document.createElement('td');
    td.style.width = '21px';
    tr.appendChild(td);
    this.btnLast = this._createToolbarButton(td, this._getImage(6), this._getImage(7), UI.getLanguageTag('last'));
    this.btnLast.onClick = this._toolbarButtonClick.bind(this, 'last');
    this.buttons.push(this.btnLast);

    this.tdSeparator = document.createElement('td');
    this.tdSeparator.style.display = 'none';
    this.tdSeparator.style.width = '8px';
    this.tdSeparator.align = 'center';
    tr.appendChild(this.tdSeparator);
    UI.disableSelection(this.tdSeparator);

    var img = document.createElement('img');
    img.src = this._getImage(8);
    this.tdSeparator.appendChild(img);

    this.tdTitle = document.createElement('td');
    tr.appendChild(this.tdTitle);
    this.tdTitle.className = 'gridTitle';
    this.tdTitle.align = 'right';
    this.tdTitle.innerHTML = this.title + '&nbsp;';
    UI.disableSelection(this.tdTitle);

    this._refreshToolbar();
    dvBar.appendChild(table);
  },

  _isEnabled: function() {
    return this.enabled;
  },

  _refreshToolbar: function() {
    this.onRefreshToolbar.call(this);

    var first = this.dataset && (this.dataset.recno > 0);
    var last = this.dataset && (!this.dataset.fetched || (this.dataset.recno < this.dataset.count-1));
    var enabled = this._isEnabled();

    this.btnFirst.setEnabled(enabled && first);
    this.btnPrev.setEnabled(enabled && first);

    this.btnNext.setEnabled(enabled && last);
    this.btnLast.setEnabled(enabled && last);

    if (this.canEdit) {
      for (var i = 4; i < this.buttons.length; i++)
        if ((this.buttons[i] != this.btnOk) && (this.buttons[i] != this.btnCancel))
          this.buttons[i].setFixedVisible(!this.editingRecord());

      if (this.btnOk && this.btnCancel) {
        this.btnOk.setVisible(this.editingRecord());
        this.btnCancel.setVisible(this.editingRecord());
      }

      this.updateButtons();
    }
  },

  _toolbarButtonClick: function(event) {
    if (this.dataset)
      switch (event) {
        case 'first':
          var f = function() {
            var func = function() {
              this.dataset.first();
            }.bind(this);
            this.firstRow = 0;
            this._fillDataGrid(func);
          }.bind(this);
          this._doScroll(f);
          return;
        case 'prev':
          var func = function() {
            this.dataset.prev();
          }.bind(this);
          
          this._doScroll(func);
          return;
        case 'next':
          var func = function() {
            this.dataset.next();
          }.bind(this);
          
          this._doScroll(func);
          return;
        case 'last':
          var f = function() {
            var func = function() {
              this.firstRow = Math.max(this.dataset.count-this.visibleRows, 0);
              this._fillDataGrid();
              this.dataset.last();
            }.bind(this);

            if (!this.dataset.fetched)
              this.dataset._requestPacket(true, func);
            else
              func();
          }.bind(this);
          
          this._doScroll(f);
          return;
      }
  },

  _refreshSelection: function() {
    var sel, clsName, editing;

    this.selected.y = -1;

    if (this.dataset)
      this.selected.y = this.dataset.recno - this.firstRow;

    for (var i = 0; i < this.rows.length; i++)
      for (var j = 0; j < this.columns.count; j++) {
        if (this.dataset)
          sel = this.focused && (this.dataset.recno == this.firstRow + i) && (j == this.selected.x);
        else
          sel = this.focused && (i == this.selected.y) && (i == this.selected.x);

        var editing = this.editingRecord() && this.dataset && (this.dataset.recno == this.firstRow + i);

        if (editing) {
          clsName = (j == this.selected.x) ? 'gridCellEditingFocused' : 'gridCellEditing';
          if (j == this.selected.x)
            this._focusCell(i, j);
        } else
          if (sel) {
            clsName = 'gridCellFocused';
            this._focusCell(i, j);
          } else {
            if ((this.dataset && (this.dataset.recno == this.firstRow + i)) || (i == this.selected.y))
              clsName = 'gridCellSelected';
           else
              clsName = 'gridCellNormal';
          }

        if (this.multi && !sel) {
          var field = this.dataset.findField(this.selectedAttr);

          if (field) {
            var value = field.getValue(this.firstRow + i);

            if (this.selectedRows.indexOf(value) > -1)
              clsName = 'gridCellMarked';
          }
        }


        if (this.focused && (j == 0) && (i == 0) && (this.dataset.recno == -1))
          clsName = 'gridCellFocused';

        if (this.rows[i][j].className != clsName)
          this.rows[i][j].className = clsName;
      }
  },

  _focusCell: function(row, col) {
    var td = this.rows[row][col].parentNode;

    if (td.offsetLeft-this.dvGrid.scrollLeft < 0)
      this.dvGrid.scrollLeft = td.offsetLeft;
    else
      if (td.offsetLeft-this.dvGrid.scrollLeft > this.dvGrid.clientWidth)
        this.dvGrid.scrollLeft = td.offsetLeft;
  },

  _doConfirm: function() {
    var ret = this.onConfirm.call();

    if ((typeof ret != 'boolean') || ret)
      UI.closeModalFrame(this, UI.Comps.ModalFrame.ModalResult.MR_OK, this.dataset);
  },

  _doCancel: function() {
    if (this.editingRecord()) {
      if (this.dataset)
        this.dataset.clearChanges();

      setTimeout((function() { this._doScroll(); }).bind(this), 0);
//      this._doScroll();
    } else {
      var ret = this.onCancel.call();

      if ((typeof ret != 'boolean') || ret)
        UI.closeModalFrame(this, UI.Comps.ModalFrame.ModalResult.MR_CANCEL);
    }
  },

  _onfocus: function() {
    if (this._isEnabled()) {
      this.focused = true;

      if (this.dataset && (this.dataset.recno == -1))
        this.dataset.first();

      this._refreshSelection();
    }
  },

  _onblur: function() {
    this.focused = false;
    this._refreshSelection();
  },

  _onkeydown: function(keyCode, evt) {
    var enabled = this._isEnabled();
    var ret = enabled ? this.onKeyDown.call(keyCode, evt) : true;

    if ((typeof ret == 'boolean') && !ret)
      return false;

    for (var i = 0; i < this.buttons.length; i++) {
      ret = this.buttons[i]._onGridKeyDown(keyCode, evt);

      if ((typeof ret == 'boolean') && ret)
        return false;
    }

    if (enabled) {
      switch(keyCode) {
        case 13: // enter
          this._doConfirm();
          return;
        case 27: // esc
          this._doCancel();
          return;
        case 32: // space
          if (this.multi) {
            var field = this.dataset.findField(this.selectedAttr);

            if (field) {
              var value = field.getValue(this.dataset.recno);

              if (this.selectedRows.indexOf(value) > -1)
                this.selectedRows = this.selectedRows.without(value);
              else
                this.selectedRows.push(value);

              this._refreshSelection();
            }
          }
          return;
        case 33: // page up
          var func = function() {
            if (this.dataset)
              this.dataset.goRecord(Math.max(this.dataset.recno - this.visibleRows, 0));
          }.bind(this);
          
          this._doScroll(func);
          return;
        case 34: // page down
          var func = function() {
            if (this.dataset)
              this.dataset.goRecord(this.dataset.recno + this.visibleRows);
          }.bind(this);
          
          this._doScroll(func);
          return;
        case 36: // home
          if (evt.ctrlKey && this.dataset) {
            var func = function() {
              this.dataset.first();
            }.bind(this);
            
            this._doScroll(func);
          } else
            this.selected.x = 0;
          break;
        case 35: // end
          if (evt.ctrlKey && this.dataset) {
            var func = function() {
              this.dataset.last();
            }.bind(this);
            
            this._doScroll(func);
          } else
            this.selected.x = this.columns.count-1;
          break;
        case 37: // left
          this.selected.x = Math.max(this.selected.x-1, 0);
          break;
        case 39: // right
          this.selected.x = Math.min(this.selected.x+1, this.columns.count-1);
          break;
        case 38: // up
          var func = function() {
            if (this.dataset)
              this.dataset.prev();
          }.bind(this);

          this._doScroll(func);
          return;
        case 40: // down
          var func = function() {
            if (this.dataset)
              this.dataset.next();
          }.bind(this);

          this._doScroll(func);
          return;
        case UI.key_search: // F2
          if (this.dataset && this.canEdit && !evt.ctrlKey) {
            var col = this.columns.getColumn(this.selected.x);
            var field = this.dataset.findField(col && col.name);

            if (field && field.enable)
              if (!this.editingRecord())
                this._inplaceEnter();
              else
                this._showInplace();
          }
          return;
        case 9: // Tab
          if (this.canEdit && !evt.ctrlKey) {
            if (evt.shiftKey)
              this.selected.x = Math.max(this.selected.x-1, 0);
            else
              this.selected.x = (this.selected.x == this.columns.count-1) ? 0 : this.selected.x+1;
            
            this._refreshSelection();
            return false;
          }
          return;
        case 45: // insert
          return;
        case 46: // delete
          return;
      }

      this._refreshSelection();
    }

    return true;
    //return (keyCode == 9);
  },

  _onkeypress: function(keyCode, evt) {
    if (this.dataset && this.canEdit && !this.inplaceEntering)
      if ((keyCode >= 48) || (keyCode == 32)) {
        var col = this.columns.getColumn(this.selected.x);
        var field = this.dataset.findField(col && col.name);

        if (field && field.enable)
          if (!this.editingRecord())
            this._inplaceEnter((keyCode == 32) ? null : keyCode);
         else
            this._showInplace((keyCode == 32) ? null : keyCode);

        return false;
      }
  },

  _inplaceKeyDown: function(keyCode, evt) {
    if (this.inplace != null)
      switch (keyCode) {
        case 13:
          var func = function() {
            var f = function() {
              this._closeInplace();
              setTimeout((function() { this.focus(); }).bind(this), 1);
            }.bind(this);

            if (this.inplace.isLookup) {
              for (var i = 0; i < this.inplace.controls.length; i++)
                if (this.inplace._getControl(i).focused)
                  this.inplace._getControl(i)._doConfirm();

              this.inplace.resolveLookup(f, true, true);
            } else
              f();
          }.bind(this);

          this.inplace.confirm(func);
          break;
        case 27:
          this.inplace.cancel();
          this._closeInplace();
          setTimeout((function() { this.focus(); }).bind(this), 1);
          break;
      }
  },

  _inplaceKeyPress: function(keyCode) {
    if (this.inplace != null)
      if ((keyCode >= 48) || (keyCode == 32))
         this._bufKeys += UI.chr(keyCode);
  },

  _inplaceBlur: function() {
    this._closeInplace();
  },

  _onInplaceSelect: function() {
    setTimeout((function() { this._closeInplace(); this.focus(); }).bind(this), 1);
  },

  _showInplace: function(keyCode) {
    var col = this.columns.getColumn(this.selected.x);
    var field = this.dataset && this.dataset.findField(col && col.name);
    var obj = this.rows[this.dataset.recno - this.firstRow][this.selected.x];
    
    if (obj && field && field.enable) {
      if (field.mstAt != '') {
        var fld = this.dataset.findField(field.mstAt);
        
        if (!fld || !fld.enable)
          return;
      }

      var l = t = h = w = n = 0;
      h = obj.offsetHeight;
      w = obj.offsetWidth;

      while (obj != this.dvGrid) {
        n++;
        l += obj.offsetLeft;
        t += (n > 2) ? obj.offsetTop : 0;
        obj = obj.parentNode;

        if (n > 50) // just in case
          return;
      }

      var dv = document.createElement('div');
      dv.style.position = 'absolute';
      dv.style.left = l;
      dv.style.top = t;

      var opt = { ds: this.dataset, fieldname: field.name, caption: null, width: w };

      if (field.mstAt == '') {
        dv.style.backgroundColor = 'white';
        this.inplace = new UI.Comps.Attribute(dv, opt);
      } else {
        var pars = eval('document.parLkp_'+field.mstAt) || {};
        pars.ds = opt.ds;
        pars.fieldname = field.mstAt;
        pars.caption = null;
        pars.width = undefined;
        pars.attrs = [];

        for (var i = 0; i < this.dataset.columns.count; i++) {
          var col = this.dataset.columns.getColumn(i);

          if (col.visible && (col.mstAt == field.mstAt) && (col.name.indexOf('IDF_') == -1))
            pars.attrs.push(col.name);
        }

        if (pars.attrs.length <= 1)
          pars.lkpType = 'line';

        this.inplace = new UI.Comps.Lookup(dv, pars);
        this.inplace.addSelectListener(this, this._onInplaceSelect);
      }

      if (this.inplace.isLookup) {
        var gridHeight = this.visibleRows * this.rowHeight + (this.rowHeight + 2);

        if (t + this.inplace.height + 2 > gridHeight)
          dv.style.top = gridHeight - (this.inplace.height + 2);
      }

      this.inplace.addKeyDownListener(this, this._inplaceKeyDown);
      this.inplace.addKeyPressListener(this, this._inplaceKeyPress);
      this.inplace.addBlurListener(this, this._inplaceBlur);

      if (!this.inplace.isLookup)
        dv.style.width = w + 'px';
      dv.style.height = h + 'px';

      this.dvGrid.appendChild(dv);
      this.inplace.focus();

      var ctrl = null;

      if (this.inplace != null) {
        if (this.inplace.isLookup) {
          for (var i = 0; i < this.inplace.controls.length; i++)
            if (this.inplace._getControl(i).fieldName == field.name) {
              ctrl = this.inplace._getControl(i);
              break;
            }
        } else
          ctrl = this.inplace.control;
      }

      this._bufKeys = '';
      if (keyCode && ((keyCode >= 48) || (keyCode == 32))) {
        this._bufKeys += UI.chr(keyCode);

        var func = function() {
          if (ctrl && ctrl.edit) {
            var funcSetText = function() {
              if (ctrl.edit.createTextRange) {
                var range = ctrl.edit.createTextRange();
                range.text = this._bufKeys;
                range.select();
              } else
                if (typeof ctrl.edit.selectionStart != undefined)
                  ctrl.edit.value = this._bufKeys;
            }.bind(this);

            if (!ctrl.focused) {
              ctrl.focus();
              setTimeout(funcSetText, 1);
            } else
              funcSetText();
          }

        }.bind(this);

        setTimeout(func, 1);
      } else
        if (ctrl && this.inplace.isLookup)
          ctrl.focus();
    }
  },

  _closeInplace: function() {
    if (this.inplace != null) {
      this.dvGrid.removeChild(this.inplace.container);

      this.inplace.dispose();
      this.inplace = null;
    }
  },

  _inplaceEnter: function(keyCode) {
    if (!this.canEdit || !this.dataset)
      return;

    var objId = this.dataset.id;
    var keyField = this.dataset.findKeyField();

    if (!keyField) {
      alert('Atributo ID não encontrado !');
      return;
    }

    var id = keyField.getValue();
    if ((id == null) || (id == 0))
      return;

    if (document.onBeforeAlterar) {
      var ret = document.onBeforeAlterar();
      
      if ((typeof ret == 'boolean') && !ret)
        return;
    }

    var xmldoc = UI.parseXML(UI.xmlHeader + '<ds id="' + objId + '"><row _op="E" _key="' + id + '"/></ds>');

    var opt = {
      method     : 'post',
      postBody   : xmldoc,
      onException: function() {
        this._afterInplaceEnter(true);
      }.bind(this),
      onFailure  : function() {
        this._afterInplaceEnter(true);
      }.bind(this)
    };

    UI.registerAjaxRequest(UI.dirBase + UI.pgData, this._afterInplaceEnter.bind(this, false, keyCode), opt);

    this.inplaceEntering = true;
  },

  _afterInplaceEnter: function(erro, keyCode, xml) {
    if (!erro) {
      var xmldoc = UI.parseXML(xml);

      if (UI.getMessageErro(xmldoc)) {
        if (this.dataset.status == UI.Comps.DataSet.RecordState.RS_NORMAL)
          this.dataset.edit();
        
        this._fillDataGrid();
        this._refreshToolbar();
        this._refreshSelection();
        
        this._showInplace(keyCode);
      }
    } else
      alert('Erro durante edição de registro !');

    this.inplaceEntering = false;
  },
  
  _doScroll: function(func) {
    if (this.dataset.refreshing || this.dataset.confirmando)
      return;

    if (this.editingRecord()) {
      this._closeInplace();

      var id = this.dataset.findKeyField().getValue();

      if (func) {
        var action = 'confirm';
        var xmldoc = this.dataset.getXmlDelta();
      } else {
        var action = 'cancel';
        var xmldoc = UI.parseXML(UI.xmlHeader + '<ds id="' + this.dataset.id + '"><row _op="C" _key="' + id + '"/></ds>');
      }

      var opt = {
        method     : 'post',
        postBody   : xmldoc,
        onException: function(req, exception) {
          this._afterDoScroll(true);
        }.bind(this),
        onFailure  : function() {
          this._afterDoScroll(true);
        }.bind(this)
      };

      this.dataset.confirmando = true;
      UI.registerAjaxRequest(UI.dirBase + UI.pgData, this._afterDoScroll.bind(this, false, action, func), opt);
    } else
      if (func)
        func();
  },

  _afterDoScroll: function(erro, action, func, xml) {
    this.dataset.confirmando = false;

    if (!erro) {
      var xmldoc = UI.parseXML(xml);

      if (UI.getMessageErro(xmldoc)) {
        if (action == 'confirm') {
          var recs = xmldoc.documentElement.getElementsByTagName('rec');
          var kfield = this.dataset.findKeyField();
          var idxKeyField = kfield ? kfield.index : -1;

          for (var i = 0; i < recs.length; i++) {
            var key = recs[i].getAttribute('_key');
            var recno = this.dataset.seek(idxKeyField, key);

            if (recno > -1)
              for (var j = 0; j < recs[i].attributes.length; j++) {
                var field = this.dataset.findField(recs[i].attributes[j].name);

                if (field)
                  field.setValue(recs[i].attributes[j].value);
              }
          }
        }

        if (action == 'cancel')
          this.dataset.cancel();
        else
          this.dataset.clearChanges();

        this.dataset.post();

        if ((action == 'confirm') && document.onAfterConfirmar)
          document.onAfterConfirmar();

        this._fillDataGrid();
        this._refreshToolbar();
        this._refreshSelection();

        if (func)
          func();
      }
    } else
      if (action == 'cancel')
        alert('Erro durante cancelamento de registro !');
      else
        alert('Erro durante confirmação de registro !');

    this.inplaceEntering = false;
  },

  _onAfterScroll: function() {
    var recVisible = (this.dataset.recno >= this.firstRow) && (this.dataset.recno <= this.firstRow+this.visibleRows-1);

    if (!recVisible) {
      if (this.dataset.recno < this.firstRow)
        this.firstRow = Math.max(this.dataset.recno, 0);
      else
        this.firstRow = this.dataset.recno-this.visibleRows+1;

      this._fillDataGrid();
    }

    this._refreshToolbar();
    this._refreshSelection();
  },

  _onConfirmClick: function() {
    var func = function() { }
    this._doScroll(func);
  },

  _onCancelClick: function() {
    this._doScroll(false);
  },

  _orderGrid: function(dv, index, ev) {
    if (this.ordering)
      return false;

    if (this.editingRecord()) {
      alert('Confirme antes de ordenar pela coluna !');
      return false;
    }
    ev = ev || window.event;

    if (ev && (typeof ev.ctrlKey == 'boolean') && !ev.ctrlKey) {
      var curCol = this.columns.getColumn(index);

      for (var i = this.orders.count-1; i >= 0; i--)
        if (this.orders.getOrder(i).fieldName != curCol.field.name)
          this.orders.remove(i);
    }

    for (var i = 0; i < this.columns.count; i++) {
      var col = this.columns.getColumn(i);
      var order = this.orders.findField(col.field.name);
      var td = dv.parentNode.parentNode.childNodes[i*2];
      var div = td.childNodes[0];
      
      if (i == index)
        if (order == null)
          order = this.orders.add(col.field.name, 'A');
        else
          order.type = (order.type == 'A') ? 'D' : 'A';

      if (order != null) {
        div.innerHTML = '';
        var img = document.createElement('img');
        img.src = this._getImage((order.type == 'A') ? 16 : 15);
        img.style.height = '6px';
        div.appendChild(img);
        div.appendChild(document.createTextNode(' '+col.title));
      } else
        if (div.innerHTML != col.title)
          div.innerHTML = col.title;
    }

    var atts = '';
    for (var i = 0; i < this.orders.count; i++)
      atts += this.orders.getOrder(i).fieldName + '=' + this.orders.getOrder(i).type + ',';

    var xmldoc = UI.parseXML(UI.xmlHeader + '<xm method="ord" objId="' + this.dataset.id + '"></xm>');
    xmldoc.documentElement.setAttribute('atts', atts);

    var opt = {
      method     : 'post',
      postBody   : xmldoc,
      onException: this._afterOrderBy.bind(this, true),
      onFailure  : this._afterOrderBy.bind(this, true)
    };

    this.ordering = true;
    UI.registerAjaxRequest(UI.dirBase + UI.pgExecMethod, this._afterOrderBy.bind(this, false), opt);
  },

  _afterOrderBy: function(erro, xml) {
    this.ordering = false;

    if (!erro) {
      var xmldoc = UI.parseXML(xml);
      var msgErro = xmldoc.documentElement.getAttribute('err');

      if (!msgErro) {
        this.dataset.refresh();
        this.dataset.first();
      } else
        alert(msgErro);
    }
  },

  _onFieldChange: function(field, oldvalue, newvalue) {
    var line = this.dataset.recno - this.firstRow;

    if ((line >= 0) && (line < this.firstRow+this.visibleRows))
      for (var i = 0; i < this.columns.count; i++)
        if (this.columns.getColumn(i).name == field.name) {
          var td = this.rows[line][i];
          this._fillCell(this.columns.getColumn(i).index, this.dataset.recno, td, line);
          break;
        }
  },

  _onRefresh: function() {
    var func = function() {
      this.dataset.first();
    }.bind(this);

    this.firstRow = 0;
    this._fillDataGrid(func);
    this._refreshToolbar();
    this._refreshSelection();
  },

  _onInsert: function() {
    this._fillDataGrid();
  },

  _onDelete: function() {
    this._fillDataGrid();
  },

  _onCellClick: function(line, td, column, evt) {
    if (!this._isEnabled())
      return false;

    if (this.multi && evt.ctrlKey) {
      var field = this.dataset.findField(this.selectedAttr);

      if (field) {
        var value = field.getValue(this.firstRow + line);

        if (this.selectedRows.indexOf(value) > -1)
          this.selectedRows = this.selectedRows.without(value);
        else
          this.selectedRows.push(value);

        this._refreshSelection();
      }
    }

    if (this.inplace != null) {
      var func = function() {
        this._closeInplace();
        this._onCellClick(line, td, column);
      }.bind(this);

      this.inplace.confirm(func);
      return;
    }

    if (this.dataset && (this.dataset.recno != line+this.firstRow)) {
      var func = function() {
        this.dataset.goRecord(line+this.firstRow);
      }.bind(this);

      this._doScroll(func);
    } else
      if (this.dataset && this.canEdit && this.focused && (this.selected.x == column)) {
        var col = this.columns.getColumn(column);
        var field = this.dataset.findField(col && col.name);

        if (field && field.enable)
          if (!this.editingRecord())
            this._inplaceEnter();
          else
            this._showInplace();
      }

    if (!this.focused)
      this.btn.focus();

    if (this.selected.x != column) {
      this._closeInplace();

      this.selected.x = column;
      this._refreshSelection();
      this.focus();
    }
  },

  _onCellDblClick: function(line, td) {
    if (!this._isEnabled())
      return false;

    if (this.firstRow + line >= this.dataset.count)
      return;

    if (this.dataset && (this.dataset.recno == -1))
      return false;

    var ret = this.onDblClick.call(line);

    if ((typeof ret != 'boolean') || ret)
      this._doConfirm();
  },

  _updateGridSize: function() {
    var barSize = this._scrollSize;
    var table = this.dvGrid.childNodes[0];
    var barVisible = (table.clientWidth >= this.container.clientWidth);
    var sz = barVisible ? barSize : 0;

    if (table.style.height != (this.container.clientHeight-sz-this.barHeight) + 'px') {
      table.style.height = (this.container.clientHeight-sz-this.barHeight) + 'px';

      var vis = Math.floor((this.container.clientHeight-3-this.rowHeight-sz-this.barHeight)/this.rowHeight);
      this.visibleRows = vis;

      for (var i = 0; i < this.rows.length; i++)
        for (var j = 0; j < this.columns.count; j++)
          this.rows[i][j].parentNode.parentNode.style.display = (i < vis) ? '' : 'none';
    }
  },

  _onResizeColumnDown: function(ev) {
    ev = ev || window.event;
    var obj = ev.target || ev.srcElement;

    if (obj && obj.column)
      for (var i = 0; i < this.columns.count; i++)
        if (this.columns.getColumn(i) == obj.column) {
          this._downColumn = new Object();
          this._downColumn.index = i;
          this._downColumn.td = obj.td;
          this._downColumn.width = obj.td.offsetWidth;
          this._downColumn.x = ev.clientX;

          break;
        }
  },

  _onResizeColumnMove: function(ev) {
    ev = ev || window.event;

    if (this._downColumn) {
      var down = this._downColumn;
      var column = this.columns.getColumn(down.index);
      var width = down.width + (ev.clientX - down.x);

      if (width > 0) {
        down.td.style.width = width + 'px';
        column.width = width;
        this._updateGridSize();
      }
    }
  },

  _onResizeColumnUp: function(ev) {
    if (this._downColumn) {
      this._downColumn.td = null;
      this._downColumn = null;
    }
  }
}

UI.Comps.GridColumns = Class.create();

UI.Comps.GridColumns.prototype = {

  grid: null,
  count: 0,

  initialize: function(grid) {
    this.grid = grid;
    this.columns = new Array();
  },
  
  dispose: function() {
    this.columns.length = 0;
    this.columns = null;
  },

  clear: function() {
    this.columns.clear();
    this.count = 0;
  },

  add: function(field) {
    var column = new UI.Comps.GridColumn(this);
    this.columns.push(column);
    this.count++;

    if (field) {
      column.field = field;
      column.title = field.titleColumn;
      column.name = field.name;
      var strWidth = UI.getStringWidth(field.titleColumn, 'gridCellHeader')+3;
      
      if (field.type == 'date')
        column.width = Math.max(70, strWidth);
      else
        column.width = Math.max(field.sizeCol*5, strWidth);
    }

    return column;
  },

  remove: function(index) {
    if ((index >= 0) && (index < this.count)) {
      this.columns.remove(index);
      this.count = this.columns.length;
    }
  },

  getColumn: function(index) {
    return this.columns[index];
  }
}

UI.Comps.GridColumn = Class.create();

UI.Comps.GridColumn.prototype = {

  index: -1,
  title: '',
  name: '',
  width: 80,
  field: null,

  initialize: function(columns) {
    this.columns = columns;
  },

  dispose: function() {
    this.columns = null;
  }
}

UI.Comps.GridOrders = Class.create();

UI.Comps.GridOrders.prototype = {

  grid: null,
  count: 0,

  initialize: function(grid) {
    this.grid = grid;
    this.orders = new Array();
  },

  dispose: function() {
    this.orders.length = 0;
    this.orders = null;
  },

  clear: function() {
    this.orders.clear();
    this.count = 0;
  },

  add: function(fieldName, type) {
    var order = new UI.Comps.GridOrder(this);
    this.orders.push(order);
    this.count++;

    order.fieldName = fieldName;
    order.type = type;

    return order;
  },

  remove: function(index) {
    if ((index >= 0) && (index < this.count)) {
      this.orders = this.orders.without(this.getOrder(index));
      this.count = this.orders.length;
    }
  },

  getOrder: function(index) {
    return this.orders[index];
  },

  findField: function(fieldName) {
    for (var i = 0; i < this.count; i++)
      if (this.orders[i].fieldName == fieldName)
        return this.orders[i];

    return null;
  }
}

UI.Comps.GridOrder = Class.create();

UI.Comps.GridOrder.prototype = {

  fieldName: '',
  type: 0,

  initialize: function(orders) {
    this.orders = orders;
  },

  dispose: function() {
    this.orders = null;
  }
}

/********** dataset.js **********/


UI.Comps.DataSet = Class.create();

UI.Comps.DataSet.RecordState = {
  RS_NORMAL   : 0,
  RS_EDITING  : 1,
  RS_INSERTING: 2
}

UI.Comps.DataSet.prototype = {

  id: 0,
  columns: null,
  count: 0,
  recno: -1,
  packetSize: 60,
  fetched: false,
  master: null,
  details: null,
  delta: null,
  status: UI.Comps.DataSet.RecordState.RS_NORMAL,
  editing: false,
  inserting: false,
  isDataset: true,
  parentDocument: null,
  scrolling: false,

  onUpdateColumns: null,
  onBeforeScroll: null,
  onAfterScroll: null,
  onFieldChange: null,
  onInsert: null,
  onDelete: null,
  onStateChange: 0,
  onRefresh: null,

  initialize: function(id, options) {
    this.id = id;
    this.data = new Array();
    this.columns = new UI.Comps.DataCols(this);
    this.fetching = false;
    this.initialized = false;
    this.details = new Array();
    this.updating = false;

    this._receivingPacket = false;
    this._oldData = null;
    this.delta = new UI.Comps.DataSetDelta(this);
    this.parentDocument = document;

    this.onBeforeScroll = new UI.Comps.Listener();
    this.onAfterScroll = new UI.Comps.Listener();
    this.onFieldChange = new UI.Comps.Listener();
    this.onUpdateColumns = new UI.Comps.Listener();
    this.onInsert = new UI.Comps.Listener();
    this.onDelete = new UI.Comps.Listener();
    this.onStateChange = new UI.Comps.Listener();
    this.onRefresh = new UI.Comps.Listener();

    var wnd = UI.getFirstWindow();
    if (wnd.datasets) {
      wnd.datasets.push(this);

      if (options && (typeof options.master == 'string'))
        for (var i = 0; i < wnd.datasets.length; i++) {
          if (wnd.datasets[i].id == options.master) {
            this.master = wnd.datasets[i];
            wnd.datasets[i].details.push(this);
          }
        }
    }
  },

  dispose: function() {
    for (var i = 0; i < this.details.length; i++)
      this.details[i].master = null;

    this.details.length = 0;
    this.details = null;

    var wnd = UI.getFirstWindow();
    if (wnd.datasets)
      wnd.datasets = wnd.datasets.without(this);

    this.onStateChange.dispose();
    this.onStateChange = null;
    this.onDelete.dispose();
    this.onDelete = null;
    this.onInsert.dispose();
    this.onInsert = null;
    this.onAfterScroll.dispose();
    this.onAfterScroll = null;
    this.onBeforeScroll.dispose();
    this.onBeforeScroll = null;
    this.onUpdateColumns.dispose();
    this.onUpdateColumns = null;
    this.onFieldChange.dispose();
    this.onFieldChange = null;
    this.onRefresh.dispose();
    this.onRefresh = null;

    this.parentDocument = null;
    this.delta.dispose();
    this.delta = null;
    this.columns.dispose();
    this.columns = null;

    this.data.length = 0;
    this.data = null;
  },

  open: function() {
    this.initialized = true;
  },

  first: function(func) {
    if (this.count == 0)
      this._requestPacket(false, function() { this.goRecord(this.count > 0 ? 0 : -1, func); }.bind(this));
    else
      this.goRecord(0, func);
  },

  prev: function() {
    if (this.recno > 0)
      this.goRecord(this.recno-1);
  },

  next: function() {
    var func = function() {
      if (this.recno+1 < this.count)
        this.goRecord(this.recno+1);
    }.bind(this);

    if (this.recno+1 >= this.count)
      this._requestPacket(false, func);
    else
      func();
  },

  last: function() {
    var func = function() {
      this.goRecord(this.count-1);
    }.bind(this);

    if (!this.fetched)
      this._requestPacket(true, func);
    else
      func();
  },

  goRecord: function(recno, func, execBefore) {
    if (this.recno == Math.min(this.count-1, recno)) {
      if (func)
        func();

      return;
    }

    if ((typeof execBefore != 'boolean') || !execBefore)
      if (!this.onBeforeScroll.call()) {
        if (func)
          func();

        return;
      }

    if (this.scrolling) {
      setTimeout(this.goRecord.bind(this, recno, func, execBefore), 50);
      return;
    }

    var f = function(fnc, text) {
      if (!this.fetched && (recno >= this.count)) {
        this.goRecord(recno, fnc, false);
        return;
      }

      for (var i = 0; i < this.details.length; i++)
        this.details[i].refresh();

      this.scrolling = false;
      this.recno = Math.min(this.count-1, recno);

      this.post();
      this.onAfterScroll.call();
      this._onScrolled();

      if (text && (typeof text == 'string') && (text != ''))
        try {
          eval(text);
        } catch(e) {
        }

      if (fnc)
        fnc();
    }.bind(this, func);

    var f2 = this._execScrollEvent.bind(this, recno, f, func);

    if (!this.fetched && (recno >= this.count))
      this._requestPacket(false, f2);
    else
      f2();
  },

  addRow: function(data) {
    this.data[this.count++] = data;

    if (this.initialized && !this._receivingPacket)
      this.delta.addRow(data);
  },

  refresh: function() {
    var r = this.recno;
    this.recno = -1;
    this.fetched = false;
    this.count = 0;
    this.data.length = 0;

    var f = function() {
      if (this.recno == -1) {
        if (r != this.recno) {
          var f2 = function(text) {
            this.scrolling = false;

            if (text && (typeof text == 'string') && (text != ''))
              try {
                eval(text);
              } catch(e) {
              }
          }.bind(this);

          this._execScrollEvent(this.recno, f2);
        }

        for (var i = 0; i < this.details.length; i++)
          this.details[i].refresh();
      }

      if (this.onRefresh)
        this.onRefresh.call(this);
    }.bind(this);

    this.first(f);
  },

  insert: function(data) {
    var rec = Math.max(this.recno, 0);

    for (var i = this.count-1; i >= rec; i--)
      this.data[i+1] = this.data[i];

    this.data[rec] = data;
    this.count++;

    this.delta.addRow(data);
    this.recno = rec;
    this._setState(UI.Comps.DataSet.RecordState.RS_INSERTING);

    this._oldData = [];
    for (var i = 0; i < data.length; i++)
      this._oldData[i] = (data[i] == null) ? null : data[i].toString();

    if (this.master)
      this.master.edit();

    this.onInsert.call();
  },

  cancel: function() {
    switch (this.status) {
      case UI.Comps.DataSet.RecordState.RS_EDITING:

        for (var i = 0; i < this.columns.count; i++)
          this.columns.getColumn(i).setValue(this._oldData[i]);

        this._setState(UI.Comps.DataSet.RecordState.RS_NORMAL);
        break;
      case UI.Comps.DataSet.RecordState.RS_INSERTING:
        this.removeRow();
        break;
    }
  },

  post: function() {
    if (this.recno > -1) {
      this._oldData = [];

      for (var i = 0; i < this.columns.count; i++) {
        this._oldData[i] = this.data[this.recno][i];

        if (this._oldData[i] != null)
          this._oldData[i] = this._oldData[i].toString();
      }
    } else
      this._oldData = null;

    this._setState(UI.Comps.DataSet.RecordState.RS_NORMAL);
  },

  edit: function() {
    if (this.recno > -1) {
      if (this.status != UI.Comps.DataSet.RecordState.RS_EDITING) {
        this.delta.changeData(this.recno);
        this._setState(UI.Comps.DataSet.RecordState.RS_EDITING);
      }

      if (this.master)
        this.master.edit();
    }
  },

  removeRow: function(recno) {
    recno = recno || this.recno;

    if ((recno >= 0) && (recno < this.count)) {
      this.delta.removeRow(recno);

      for (var i = recno; i < this.count-1; i++)
        this.data[i] = this.data[i+1];

      this.data.length--;
      this.count--;
      this.recno = -1;

      if (this.count > 0)
        this.goRecord(recno);
      else
        this.post();

      this.onDelete.call();
    }
  },

  getValue: function(col, row) {
    if (typeof(row) != 'number')
      row = this.recno;

    if ((row >= 0) && (row < this.count)) {
      if ((col >= 0) && (col < this.data[row].length))
        return this.data[row][col];
    }

    return null;
  },

  setValue: function(fieldName, value) {
    var field = this.findField(fieldName);
    if (field)
      field.setValue(value);
  },

  getRow: function(index) {
    if (index < 0)
      return null;

    if (index+1 > this.count) {
      this._requestPacket(index-this.count+1, null);
      return null;
    } else
      return this.data[index];
  },

  findField: function(fieldName, funcTest) {
    for (var i = 0; i < this.columns.count; i++) {
      var col = this.columns.getColumn(i);

      if (col.name == fieldName)
        if (!funcTest || funcTest(col))
          return col;
    }

    return null;
  },

  findKeyField: function() {
    for (var i = 0; i < this.columns.count; i++)
      if (this.columns.getColumn(i).fieldname == 'ID')
        return this.columns.getColumn(i);

    return null;
  },

  seek: function(idxField, value) {
    for (var i = 0; i < this.count; i++)
      if (this.data[i][idxField] == value)
        return i;

    return -1;
  },

  addBeforeScrollListener: function(obj, event) {
    if (this.onBeforeScroll)
      this.onBeforeScroll.addListener(obj, event);
  },

  removeBeforeScrollListener: function(obj) {
    if (this.onBeforeScroll)
      this.onBeforeScroll.removeListener(obj);
  },

  addAfterScrollListener: function(obj, event) {
    if (this.onAfterScroll)
      this.onAfterScroll.addListener(obj, event);
  },

  removeAfterScrollListener: function(obj) {
    if (this.onAfterScroll)
      this.onAfterScroll.removeListener(obj);
  },

  addUpdateColumnsListener: function(obj, event) {
    if (this.onUpdateColumns)
      this.onUpdateColumns.addListener(obj, event);
  },

  removeUpdateColumnsListener: function(obj) {
    if (this.onUpdateColumns)
      this.onUpdateColumns.removeListener(obj);
  },

  addFieldChangeListener: function(obj, event) {
    if (this.onFieldChange)
      this.onFieldChange.addListener(obj, event);
  },

  removeFieldChangeListener: function(obj) {
    if (this.onFieldChange)
      this.onFieldChange.removeListener(obj);
  },

  addInsertListener: function(obj, event) {
    if (this.onInsert)
      this.onInsert.addListener(obj, event);
  },

  removeInsertListener: function(obj) {
    if (this.onInsert)
      this.onInsert.removeListener(obj);
  },

  addDeleteListener: function(obj, event) {
    if (this.onDelete)
      this.onDelete.addListener(obj, event);
  },

  removeDeleteListener: function(obj) {
    if (this.onDelete)
      this.onDelete.removeListener(obj);
  },

  addStateChangeListener: function(obj, event) {
    if (this.onStateChange)
      this.onStateChange.addListener(obj, event);
  },

  removeStateChangeListener: function(obj) {
    if (this.onStateChange)
      this.onStateChange.removeListener(obj);
  },

  addRefreshListener: function(obj, event) {
    if (this.onRefresh)
      this.onRefresh.addListener(obj, event);
  },

  removeRefreshListener: function(obj) {
    if (this.onRefresh)
      this.onRefresh.removeListener(obj);
  },

  getXmlDelta: function() {
    var doc = UI.parseXML(UI.xmlHeader + '<ds/>');
    doc.documentElement.setAttribute('id', this.id);

    if (this.delta.data.length > 0)
      this.delta.applyChanges(doc);

    return doc;
  },

  clearChanges: function() {
    this.delta.clearChanges();
  },

  _execScrollEvent: function(recno, func, funcError) {
    if (this.details.length > 0) {
      var xmldoc = UI.parseXML(UI.xmlHeader + '<xm method="scrl" objId="' + this.id + '"></xm>');
      var field = this.findKeyField();
      var r = Math.min(this.count-1, recno);

      xmldoc.documentElement.setAttribute('id', (r >= 0) ? this.data[r][field.index] : 0);

      var opt = {
        method     : 'post',
        postBody   : xmldoc,
        onException: function() {
          this.scrolling = false;
          if (funcError)
            funcError();
        },
        onFailure  : function() {
          this.scrolling = false;
          if (funcError)
            funcError();
        }
      };

      this.scrolling = true;

      UI.registerAjaxRequest(UI.dirBase + UI.pgExecMethod, func, opt);
    } else
      func();
  },

  _onScrolled: function() {
    for (var i = 0; i < this.details.length; i++)
      this.details[i]._clearData();
  },

  _clearData: function() {
    this.data.length = 0;
    this.count = 0;
    this.recno = -1;
    this.fetched = false;
    this._oldData = null;
    this.clearChanges();

    for (var i = 0; i < this.details.length; i++)
      this.details[i]._clearData();
  },

  _setState: function(state) {
    if (this.status != state) {
      this.editing = (state != UI.Comps.DataSet.RecordState.RS_NORMAL);
      this.status = state;

      if (this.onStateChange)
        this.onStateChange.call();
    }
  },

  _requestPacket: function(all, func) {
    if (!this.fetched && !this.fetching) {
      var recs = (typeof(all) == 'number') ? all : (all ? -1 : this.packetSize);
      var url = UI.dirBase + UI.pgReqPacket + '?objId='+this.id+'&init='+this.count+'&fetch='+recs+'&_uid='+UI.random();

      this.fetching = true;
      UI.registerAjaxRequest(url, this._onReceivePacket.bind(this, func), [recs]);
    }
  },

  _onReceivePacket: function(func, xml, pktsize) {
    if (xml != null) {
      var doc = UI.parseXML(xml).documentElement;
      var elements = doc.getElementsByTagName('row');
      var from = this.count-1;

      this._receivingPacket = true;

      for (var i = 0; i < elements.length; i++) {
        var row = [];

        for (var j = 0; j < this.columns.count; j++)
          if (this.columns.getColumn(j).type == 'bool')
            row[j] = elements[i].getAttribute('c'+(j+1)) == 'true';
          else
            row[j] = elements[i].getAttribute('c'+(j+1));

        this.addRow(row);
      }

      this._receivingPacket = false;
      this.fetched = (pktsize == -1) || (doc.childNodes.length < pktsize);
      doc = null;

      if (func)
        func();
    } else
      this.fetched = true;

    this.fetching = false;
  },

  _onAddColumn: function() {
    for (var i = 0; i < this.count; i++)
      this.data[i][this.columns.count-1] = null;

    this._doUpdateColumns();
  },

  _onRemoveColumn: function(index) {
    for (var i = 0; i < this.count; i++)
      this.data[i].remove(index);

    this._doUpdateColumns();
  },

  _onClearColumn: function() {
    for (var i = 0; i < this.count; i++)
      this.data[i].length = 0;

    this._doUpdateColumns();
  },

  _doUpdateColumns: function() {
    if (this.onUpdateColumns)
      this.onUpdateColumns.call();
  },

  _onFieldChange: function(field, oldvalue, newvalue) {
    if (this.onFieldChange)
      this.onFieldChange.call(field, oldvalue, newvalue);
  }
}

UI.Comps.DataCols = Class.create();

UI.Comps.DataCols.prototype = {

  dataset: null,
  count: 0,

  initialize: function(dataset) {
    this.dataset = dataset;
    this.data = new Array();
  },

  dispose: function() {
    this.clear();

    this.data = null;
    this.dataset = null;
  },

  getColumn: function(index) {
    return this.data[index];
  },

  add: function(name, params) {
    var col = new UI.Comps.DataCol(this, name);
    this.data[this.count++] = col;
    this.data[this.count-1].title = name;

    if (typeof params == 'object') {
      if (params.nf)
        this.data[this.count-1].fieldname = params.nf;
      if (params.title)
        this.data[this.count-1].title = params.title;
      if (params.type)
        this.data[this.count-1].type = params.type;
      if (params.items)
        this.data[this.count-1].items = params.items;
      if (typeof params.size == 'number') {
        this.data[this.count-1].size = params.size;
        this.data[this.count-1].sizeCol = params.size;
      }
      if (params.decimals)
        this.data[this.count-1].decimals = params.decimals;
      if (typeof params.visible == 'boolean')
        this.data[this.count-1].visible = params.visible;
      if (typeof params.enabled == 'boolean')
        this.data[this.count-1].enable = params.enabled;
      if (typeof params.visibleColumn == 'boolean')
        this.data[this.count-1].visibleColumn = params.visibleColumn;
      if (typeof params.titleColumn == 'string')
        this.data[this.count-1].titleColumn = params.titleColumn;
      else
        this.data[this.count-1].titleColumn = this.data[this.count-1].title;
      if (typeof params.mstAt == 'string')
        this.data[this.count-1].mstAt = params.mstAt;
      if (typeof params.sizeCol == 'number')
        this.data[this.count-1].sizeCol = params.sizeCol;
      if (typeof params.mask == 'string')
        this.data[this.count-1].mask = params.mask;
    }

    this.dataset._onAddColumn();
  },

  remove: function(index) {
    if (index < this.count) {
      this.data.remove(index);
      this.count--;

      this.dataset._onRemoveColumn(index);

      for (var i = 0; i < this.count; i++)
        this.getColumn(i).index = i;
    }
  },

  clear: function() {
    for (var i = 0; i < this.data.length; i++)
      this.data[i].dispose();

    this.data.length = 0;
    this.dataset._onClearColumn();
  }
}

UI.Comps.DataCol = Class.create();

UI.Comps.DataCol.prototype = {

  index: -1,
  name: '',
  title: '',
  type: '',
  size: 10,
  sizeCol: 10,
  decimals: 0,
  items: '',
  enable: true,
  visible: true,
  visibleColumn: true,
  titleColumn: null,
  fieldname: '',
  mstAt: '',
  mask: '',

  initialize: function(datacols, name) {
    this.datacols = datacols;
    this.index = this.datacols.count;

    this.name = name;
  },

  dispose: function() {
    this.datacols = null;
  },

  getValue: function(recno) {
    var dataset = this.datacols.dataset;

    if (typeof recno != 'number')
      recno = dataset.recno;

    if ((this.index > -1) && (this.index < dataset.columns.count) && (recno >= 0))
      return dataset.data[recno][this.index];
    else
      return null;
  },

  setValue: function(value) {
    var dataset = this.datacols.dataset;

    if ((this.index > -1) && (this.index < dataset.columns.count) && (dataset.recno >= 0)) {
      var oldvalue = dataset.data[dataset.recno][this.index];

      if (oldvalue != value) {
        if (!dataset.updating && (dataset.status == UI.Comps.DataSet.RecordState.RS_NORMAL))
          dataset.edit();

        dataset.data[dataset.recno][this.index] = value;
        dataset.delta.changeData(dataset.recno, this.index);
        dataset._onFieldChange(this, oldvalue, value);
      }
    } else
      return null;
  },

  getDisplayValue: function(recno) {
    if (this.type == 'number')
      return UI.formatNumber(this.getValue(recno), this.decimals);

    if (this.type == 'combo')
      return this._getComboValue(recno);

    if (this.type == 'date')
      return this._getDateValue(recno);

    if (this.type == 'radio')
      return this._getRadioValue(recno);

    var value = this.getValue(recno);
    return (value != null) ? value : '';
  },

  _getComboValue: function(recno) {
    var s = this.getValue(recno);

    if (s == null)
      return '';

    var list = this.items.split(';');

    for (var i = 0; i < list.length; i++) {
      var item = list[i].split('=');

      if ((item.length == 2) && (s == item[0]))
        return item[1];
    }

    return s;
  },

  _getDateValue: function(recno) {
    var s = this.getValue(recno);

    if (s == null)
      return '';

    var lst = s.split('-');

    if (lst.length != 3)
      return '';

    return UI.dateMask.replace('dd', UI.padl(lst[2], 2, '0')).
                       replace('mm', UI.padl(lst[1], 2, '0')).
                       replace('yyyy', UI.padl(lst[0], 4, '0'));
  },

  _getRadioValue: function(recno) {
    var s = this.getValue(recno);

    if (s == null)
      return '';

    var list = this.mask.split(';');

    for (var i = 0; i < list.length; i++) {
      var item = list[i].split('=');

      if ((item.length == 2) && (s == item[0]))
        return item[1];
      else
        if ((item.length == 1) && (s == item[0]))
          return item[0];
    }

    return s;
  }
}


UI.Comps.DataSetDelta = Class.create();

UI.Comps.DataSetDelta.prototype = {

  dataset: null,
  keyIndex: -1,
  data: null,

  initialize: function(dataset) {
    this.dataset = dataset;
    this.data = new Array();
  },

  dispose: function() {
    this.data.length = 0;
    this.data = null;
    this.dataset = null;
  },

  addRow: function(data) {
    var keyIndex = this._getKeyIndex();
    var key = data[keyIndex];
    var row = [];

    for (var i = 0; i < data.length; i++)
      row[i] = (i != keyIndex) ? UI.chr(255) : data[i].toString();

    this.data.push([key, 'I', row]);
  },

  removeRow: function(recno) {
    var key = this.dataset.data[recno][this._getKeyIndex()];
    var insertRemove = true;

    for (var i = 0; i < this.data.length; i++)
      if (this.data[i][0] == key) {
        insertRemove = (this.data[i][1] != 'I');

        for (var j = i; j < this.data.length-1; j++)
          this.data[j] = this.data[j+1];

        this.data.length--;
        break;
      }

    if (insertRemove)
      this.data.push([key, 'D']);
  },

  changeData: function(recno, col) {
    var key = this.dataset.data[recno][this._getKeyIndex()];

    for (var i = 0; i < this.data.length; i++)
      if (this.data[i][0] == key) {
        if ((typeof col == 'number') && (col > -1)) {
          var value = this.dataset.updating ? UI.chr(255) : this.dataset.data[recno][col];
          this.data[i][2][col] = (value == null) ? null : value.toString();
        }
        return;
      }

    var oldData = this.dataset.data[recno];
    var data = [];
    for (var i = 0; i < oldData.length; i++)
      if (i == col)
        data[i] = (oldData[i] == null) ? null : oldData[i].toString();
      else
        data[i] = UI.chr(255);

    this.data.push([key, 'M', data]);
  },

  applyChanges: function(xmldoc) {
    var keyIndex = this._getKeyIndex();

    for (var i = 0; i < this.data.length; i++) {
      var row = xmldoc.createElement('row');
      row.setAttribute('_key', this.data[i][0]);
      row.setAttribute('_op', this.data[i][1]);

      for (var j = 0; j < this.data[i][2].length; j++) {
        var value = this.data[i][2][j];
        //this.dataset.columns.getColumn(j).name
        row.setAttribute('col'+j, (value == null) ? 'null' : value);
      }

      xmldoc.documentElement.appendChild(row);
    }
  },

  clearChanges: function() {
    this.data.length = 0;
  },

  _getKeyIndex: function() {
    if (this.keyIndex > -1)
      return this.keyIndex;

    for (var i = 0; i < this.dataset.columns.count; i++)
      if (this.dataset.columns.getColumn(i).fieldname == 'ID') {
        this.keyIndex = i;
        return i;
      }

    return -1;
  }
}


/********** button.js **********/


UI.Comps.Button = Class.create();

UI.Comps.Button.SubDir = 'Button/';
UI.Comps.Button.Images = ['Button_01.gif'];

UI.Comps.Button.prototype = {

  id: null,
  caption: 'Button',
  imageEnabled: '',
  imageDisabled: '',
  enabled: true,
  visible: true,
  popup: null,
  imgsize: null,
  btntype: null,
  fixedEnabled: true,
  fixedVisible: true,
  ownerVisible: null,
  shortCut: 0,
  onClick: null,

  btnUpClass: 'buttonUp',
  btnDownClass: 'buttonDown',
  btnOverClass: 'buttonOver',
  btnDisabledClass: 'buttonDisable',

  initialize: function(container, parameters) {
    this._containerCreated = false;
    this.doc = (parameters && (typeof parameters.document == 'object')) ? parameters.document : document;

    if (typeof container != 'string') {
      this._containerCreated = true;
      this.container = this.doc.createElement('div');
      this.container.style.width = '70px';
      this.container.style.height = '20px';
    } else
      this.container = $(container);

    ownerVisible = this.container;

    if (typeof parameters == 'object') {
      if (typeof parameters.id == 'string')
        this.id = parameters.id;

      if (typeof parameters.shortcut == 'number')
        this.shortCut = parameters.shortcut;

      if (typeof parameters.image == 'string')
        this.imageEnabled = parameters.image;

      if (typeof parameters.imageDisabled == 'string')
        this.imageDisabled = parameters.imageDisabled;

      if (parameters.width)
        this.container.style.width = parameters.width+'px';

      if (parameters.height)
        this.container.style.height = parameters.height+'px';

      if (typeof parameters.parent == 'object') {
        parameters.parent.appendChild(this.container);

        if (!this.ownerVisible)
          this.ownerVisible = parameters.parent;
      }

      if (typeof parameters.type == 'string')
        this.btntype = parameters.type;

      if (typeof parameters.visible == 'boolean')
        this.visible = parameters.visible;

      if (typeof parameters.caption == 'string') {
        if (parameters.caption.indexOf('@') == 0)
          this.caption = UI.getLanguageTag(parameters.caption.substr(1));
        else
          this.caption = parameters.caption;
      }

      if (typeof parameters.enabled == 'boolean')
        this.enabled = parameters.enabled;

      if (typeof parameters.tooltip == 'string') {
        if (parameters.tooltip.indexOf('@') == 0)
          this.container.title = UI.getLanguageTag(parameters.tooltip.substr(1));
        else
          this.container.title = parameters.tooltip;
      } else
        this.container.title = this.caption;

      if (typeof parameters.imgsize == 'object')
        this.imgsize = parameters.imgsize;

      this.btnUpClass = parameters.btnUpClass || this.btnUpClass;
      this.btnDownClass = parameters.btnDownClass || this.btnDownClass;
      this.btnOverClass = parameters.btnOverClass || this.btnOverClass;
      this.btnDisabledClass = parameters.btnDisabledClass || this.btnDisabledClass;
    } else {
      if (this.container.getAttribute('image'))
        this.imageEnabled = this.container.getAttribute('image');

      if (this.container.getAttribute('imageDisabled'))
        this.imageDisabled = this.container.getAttribute('imageDisabled');
    }

    this.popup = new UI.Comps.PopupMenu();
    this.popup.onItemsChange = this._onPopupChange.bind(this);
    this.tmOut = null;
    this._popupVisible = false;
    this.table = null;
    this._down = false;
    this._over = false;
    this._img = null;
    this._tdBtn = null;
    this._recreateButton();

    this.container.onmouseover = this._onmouseover.bind(this);
    this.container.onmouseout = this._onmouseout.bind(this);
    this.container.onmousedown = this._onmousedown.bind(this);
    this.container.onmouseup = this._onmouseup.bind(this);

    UI.Controls.push(this);
  },

  dispose: function() {
    UI.Controls = UI.Controls.without(this);

    if (this.tmOut) {
      clearTimeout(this.tmOut);
      this.tmOut = null;
    }

    if (this.btntype) {
      var form = UI.getParentForm(this.container);
      if (form)
        switch(this.btntype) {
          case 'submit': form.submitButton = null;
          case 'reset' : form.resetButton = null;
        }
    }

    this.container.onmouseover = null;
    this.container.onmouseout = null;
    this.container.onmousedown = null;
    this.container.onmouseup = null;

    this.table = null;
    this._img = null;
    this._tdBtn = null;
    this.onClick = null;

    if (this._containerCreated) {
      this.setParent(null);
      this.container = null;
    }
  },

  click: function() {
    if (!this.enabled || !this.fixedEnabled)
      return;

    var obj = document.activeElement;

    if (!obj)
      obj = UI.getActiveElement(document);

    while (obj && obj.tagName.toLowerCase() == 'iframe')
      obj = UI.getDocumentFromIframe(obj).activeElement;

    var f = function() {
      if (this.btntype) {
        var form = UI.getParentForm(this.container);

        if (form)
          switch (this.btntype) {
            case 'submit':
              var ok = true;
              if (typeof form.getAttribute('onsubmit') == 'string') {
                var func = new Function(form.getAttribute('onsubmit')).bind(form);
                ok = func();
              } else
                if (typeof form.onsubmit == 'function')
                  ok = form.onsubmit();

              if (ok) {
                UI.disableControls();
                form.submit();
              }
              break;
            case 'reset':
              form.reset();
              break;
          }

        return;
      }

      if (this._popupVisible) {
        var p = UI.getAbsolutePosition(this.table);
        this.popup.Show(p.x, p.y+this.table.offsetHeight, this.table.offsetWidth);
      } else
        if (this.onClick)
          this.onClick();
    }.bind(this);

    if (document.body.focus)
      document.body.focus();

    if (!this.ignoreBlur) {
      if (obj && (obj.tagName.toLowerCase() == 'input') && (typeof obj.onblur == 'function')) {
        var wnd = obj;

        while (wnd && wnd.parentNode && (wnd.parentNode != wnd))
          wnd = wnd.parentNode;

        wnd = wnd.parentWindow || wnd.defaultView;

        if (wnd && wnd.UI)
          for (var i = 0; i < wnd.UI.Attributes.length; i++)
            if (wnd.UI.Attributes[i].isLookup && wnd.UI.Attributes[i].timeoutBlur && wnd.UI.Attributes[i]._changed()) {
              var ev = wnd.UI.Attributes[i].afterCheck;

              if (wnd.UI.Attributes[i].checking) {
                wnd.UI.Attributes[i].afterCheck = function() {
                  if (typeof ev == 'function')
                    ev();

                  wnd.UI.Attributes[i].resolveLookup(f);
                }
              } else
                wnd.UI.Attributes[i].resolveLookup(f);

              return;
            }

        var ret = obj.onblur.call(this, f);

        if ((typeof ret == 'boolean') && !ret)
          return;
      }

      if (obj && (obj.tagName.toLowerCase() == 'input'))
        obj.focus();
    }

    f();
  },

  isPressed: function() {
    return this._down;
  },

  setFixedEnabled: function(value) {
    this.fixedEnabled = value;
    this._updateEnabled();
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;
      this._updateEnabled();
    }
  },

  setVisible: function(value) {
    this.ownerVisible.style.display = value && this.fixedVisible ? UI.defaultDisplay : 'none';
    this.visible = value;
  },

  setFixedVisible: function(value) {
    this.ownerVisible.style.display = value && this.visible ? UI.defaultDisplay : 'none';
    this.fixedVisible = value;
  },

  setCaption: function(caption) {
    this.caption = caption;
    this._recreateButton();
  },

  setImageEnabled: function(image) {
    this.imageEnabled = image;
    this._recreateButton();
  },

  setImageDisabled: function(image) {
    this.imageDisabled = image;
    this._recreateButton();
  },

  setParent: function(parent) {
    if (this.container.parentNode != parent) {
      if (this.container.parentNode)
        this.container.parentNode.removeChild(this.container);

      if (parent)
        parent.appendChild(this.container);
    }
  },

  setWidth: function(width) {
    this.container.style.width = (typeof width == 'string') ? width : width+'px';
  },

  getWidth: function() {
    var w = (this.container.style.width + '').replace('px', '');

    return eval(w);
  },

  setHeight: function(height) {
    this.container.style.height = (typeof height == 'string') ? height : height+'px';

    if ((typeof height == 'string') || (height >= 15))
      this._tdBtn.style.fontSize = '';
    else
      this._tdBtn.style.fontSize = '1px';
  },

  setFontColor: function(color) {
    this._tdBtn.style.color = color;
  },

  hideBorder: function() {
    this.table.style.borderWidth = '0px';
  },

  setBtnOverClass: function(cls) {
    this.btnOverClass = cls || 'buttonOver';
  },

  setBtnUpClass: function(cls) {
    this.btnUpClass = cls || 'buttonUp';

    if (this.table.className != this.btnUpClass)
      this.table.className = this.btnUpClass;
  },

  setBtnDownClass: function(cls) {
    this.btnDownClass = cls || 'buttonDown';
  },

  _createTable: function() {
    var table = this.doc.createElement('table');
    var tbody = this.doc.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.style.width = '100%';
    table.style.height = '100%';
    return table;
  },

  _recreateButton: function() {
    while (this.container.childNodes.length > 0)
      this.container.removeChild(this.container.childNodes[0]);

    if (this.ownerVisible && (!this.visible || !this.fixedVisible))
      this.ownerVisible.style.display = 'none';

    if (this.btntype) {
      var form = UI.getParentForm(this.container);
      if (form)
        switch(this.btntype) {
          case 'submit': form.submitButton = this;
          case 'reset' : form.resetButton = this;
        }
    }

    this.table = this._createTable();
    var tr = this.doc.createElement('tr');
    this.table.childNodes[0].appendChild(tr);
    this._tdBtn = this.doc.createElement('td');
    tr.appendChild(this._tdBtn);

    var imgsrc = this.enabled ? this.imageEnabled : this.imageDisabled;
    UI.disableSelection(this._tdBtn);
    this._tdBtn.align = 'center';

    this.table.className = this.enabled ? this.btnUpClass : this.btnDisabledClass;
    this._img = null;

    if (imgsrc != '') {
      this._img = this.doc.createElement('img');
      this._img.setAttribute('src', imgsrc);
      UI.disableSelection(this._img);

      if (this.imgsize) {
        this._img.style.width = this.imgsize.width+'px';
        this._img.style.height = this.imgsize.height+'px';
      }

      this._tdBtn.appendChild(this._img);
    }

    var caption = (imgsrc != '') ? ' '+this.caption : this.caption;
    this._tdBtn.appendChild(this.doc.createTextNode(caption));

    if (this._popupVisible) {
      var td = this.doc.createElement('td');
      tr.appendChild(td);
      td.className = 'buttonPopup';

      var img = this.doc.createElement('img');
      img.setAttribute('src', this._getImage(0));
      UI.disableSelection(img);
      td.appendChild(img);
    }

    this.container.appendChild(this.table);
  },

  _onGridKeyDown: function(keyCode, evt) {
    if ((this.shortCut > 0) && (keyCode == this.shortCut)) {
      this.click();
      return true;
    }

    return false;
  },

  _onmouseover: function() {
    if (this.enabled && this.fixedEnabled) {
      this._over = true;
      this.table.className = this.btnOverClass;
    }
  },

  _onmouseout: function() {
    if (this.enabled && this.fixedEnabled) {
      this._over = false;
      this.table.className = this.btnUpClass;
    }
  },

  _onmousedown: function() {
    if (this.enabled && this.fixedEnabled) {
      this._down = true;
      this.table.className = this.btnDownClass;
    }
  },

  _onmouseup: function() {
    if (this.enabled && this.fixedEnabled) {
      this._down = false;
      this.table.className = this._over ? this.btnOverClass : this.btnUpClass;
      this.click();
    }
  },

  _onPopupChange: function() {
    if (this._popupVisible != (this.popup.count > 0)) {
      this._popupVisible = (this.popup.count > 0);
      this._recreateButton();
    }
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.Button, index);
  },

  _updateEnabled: function() {
    var enable = this.enabled && this.fixedEnabled;

    this.table.className = enable ? this.btnUpClass : this.btnDisabledClass;

    var imgsrc = enable ? this.imageEnabled : this.imageDisabled;

    if (this._img && (imgsrc != '')) {
      if (this.tmOut) {
        clearTimeout(this.tmOut);
        this.tmOut = null;
      }

      this.tmOut = setTimeout((function() { this._img.setAttribute('src', imgsrc);}).bind(this), 0);
    }
  }
}


/********** component.js **********/


UI.Comps.Component = Class.create();

UI.Comps.Component.prototype = {

  dataset: null,
  fieldName: '',
  container: null,

  initialize: function(container, options) {
    this.container = container;

    if (typeof this.container.getAttribute('fieldName') == 'string')
      this.setFieldName(this.container.getAttribute('fieldName'));

    if (options)
      if (typeof options.fieldname == 'string')
        this.setFieldName(options.fieldname);

    this._createControls();

    if (options && (typeof options.ds == 'object'))
      this.setDataSet(options.ds);
  },

  dispose: function() {
    this._destroyControls();
    this.container = null;
    this.setDataSet(null);
  },

  setDataSet: function(dataset) {
    if (this.dataset != dataset) {
      if (this.dataset) {
        this.dataset.removeAfterScrollListener(this);
        this.dataset.removeFieldChangeListener(this);
      }

      this.dataset = dataset;

      if (dataset) {
        var field = dataset.findField(this.fieldName);

        if (field) {
          dataset.addAfterScrollListener(this, this._onAfterScroll);
          dataset.addFieldChangeListener(this, this._onFieldChange);

          this._updateFieldType();
          this._doChange(field);
        }
      }
    }
  },

  setFieldName: function(fieldName) {
    if (this.fieldName != fieldName) {
      if (this.dataset)
        this.dataset.removeAfterScrollListener(this);

      this.fieldName = fieldName;
      var field = null;

      if (this.dataset)
        field = this.dataset.findField(this.fieldName);

      if (field)
        this.dataset.addAfterScrollListener(this, this._onAfterScroll);

      if (this.dataset)
        this._doChange(field);
    }
  },

  focus: function() {
  },

  _recreateControls: function() {
    this._destroyControls();
    this._createControls();
  },

  _updateFieldType: function() {
  },

  _createControls: function() {
  },

  _destroyControls: function() {
  },

  _doChange: function(field) {
  },

  _onAfterScroll: function() {
    if (this.dataset)
      this._doChange(null);
  },

  _onFieldChange: function(field, oldvalue, newvalue) {
    this._doChange(field);
  }
}


/********** edit.js **********/


UI.Comps.Edit = Class.create();

UI.Comps.Edit.EditType = {
  ET_DEFAULT : 0,
  ET_PASSWORD: 1,
  ET_NUMBER  : 2
};

UI.Comps.Edit.prototype = UI.extend(UI.Comps.Component, {

  edit: null,
  editType: UI.Comps.Edit.EditType.ET_DEFAULT,
  mask: '',
  enabled: true,
  visible: true,
  decimals: 0,
  edtname: null,
  text: '',
  width: 0,
  height: 20,
  focused: false,
  fixedEnabled: true,
  tabstop: true,
  align: null,

  onChange: null,
  onChangeText: null,
  onFocus: null,
  onBlur: null,
  onKeyDown: null,
  onKeyPress: null,
  onSubmit: null,

  initialize: function(container, options) {
    if (typeof container == 'string')
      container = $(container);
    else
      if ((typeof container != 'object') || (container == null)) {
        this._containerCreated = true;
        container = document.createElement('div');
      }

    container.className = 'editBackground';
    this.align = 'left';

    if (options) {
      if (typeof options.type == 'number')
        this.editType = options.type;

      if (typeof options.align == 'string')
        this.align = options.align;

      if (typeof options.type == 'string')
        if (options.type == 'password')
          this.editType = UI.Comps.Edit.EditType.ET_PASSWORD;
        else if (options.type == 'number')
          this.editType = UI.Comps.Edit.EditType.ET_NUMBER;

      if (typeof options.visible == 'boolean')
        this.visible = options.visible;

      if (typeof options.tabstop == 'boolean')
        this.tabstop = options.tabstop;

      if (typeof options.width == 'number')
        this.width = options.width;

      if (typeof options.height == 'number')
        this.height = options.height;

      if (typeof options.mask == 'string')
        this.mask = options.mask;

      if (typeof options.enabled == 'boolean')
        this.enabled = options.enabled;

      if (typeof options.name == 'string')
        this.edtname = options.name;

      if (typeof options.text == 'string')
        this.text = options.text;

      if (typeof options.decimals == 'number')
        this.decimals = options.decimals;
    }

    if (!this.visible)
      container.style.display = 'none';

    this.onChange = new UI.Comps.Listener();
    this.onChangeText = new UI.Comps.Listener();
    this.onFocus = new UI.Comps.Listener();
    this.onBlur = new UI.Comps.Listener();
    this.onKeyDown = new UI.Comps.Listener();
    this.onKeyPress = new UI.Comps.Listener();
    this.onSubmit = new UI.Comps.Listener();

    this.charWidth = (this.editType == UI.Comps.Edit.EditType.ET_PASSWORD) ? 7 : UI.getStringWidth();
    this._changingValue = false;
    this._oldtext = '';
    this.buttons = new Array();

    this.superclass.initialize.call(this, container, options);

    if (this.width == 0)
      this.width = this._getPreferredWidth();

    container.style.width = this.width + 'px';
    container.style.height = this.height + 'px';

    if (!options || !options.isFromAttribute)
      UI.Controls.push(this);

    if (this.editType == UI.Comps.Edit.EditType.ET_PASSWORD)
      this._addButton(UI.getImage(UI.Comps.Lookup, 0), UI.getImage(UI.Comps.Lookup, 1), UI.getLanguageTag('clear'), this._onClearClick.bind(this));
  },

  dispose: function() {
    UI.Controls = UI.Controls.without(this);

    this.buttons.length = 0;
    this.buttons = null;
    this.onChange.dispose();
    this.onChange = null;
    this.onChangeText.dispose();
    this.onChangeText = null;
    this.onFocus.dispose();
    this.onFocus = null;
    this.onBlur.dispose();
    this.onBlur = null;
    this.onKeyDown.dispose();
    this.onKeyDown = null;
    this.onKeyPress.dispose();
    this.onKeyPress = null;
    this.onSubmit.dispose();
    this.onSubmit = null;

    if (this._containerCreated && (this.container.parentNode))
      this.container.parentNode.removeChild(this.container);

    this.superclass.dispose.call(this);
  },

  setEditType: function(value) {
    this.editType = value;
    this._recreateControls();
  },

  setMask: function(mask) {
    if (this.editType == UI.Comps.Edit.EditType.ET_DEFAULT) {
      this.mask = mask;
      this._recreateControls();
    }
  },

  setFieldName: function(fieldName) {
    this.superclass.setFieldName.call(this, fieldName);

    if (this.dataset)
      this._updateFieldType();
  },

  clearButtons: function() {
    this.buttons.length = 0;
    this._recreateControls();
  },

  setFixedEnabled: function(value) {
    if (this.fixedEnabled != value) {
      this.fixedEnabled = value;
      this._updateEnable();
    }
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;
      this._updateEnable();
    }
  },

  focus: function() {
    if (document.body.focus)
      document.body.focus();

    this.edit.focus();
  },

  clear: function() {
    this._setText('');
  },

  setText: function(value) {
    this._setText(value);
  },

  confirm: function() {
    this._doConfirm();
  },
  
  cancel: function() {
    var field = this.dataset && this.dataset.findField(this.fieldName);
    
    if (field)
      this._doChange(field);
    else
      this.edit.value = this._oldtext;
  },

  addChangeListener: function(obj, event) {
    this.onChange.addListener(obj, event);
  },

  removeChangeListener: function(obj) {
    this.onChange.removeListener(obj);
  },

  addChangeTextListener: function(obj, event) {
    this.onChangeText.addListener(obj, event);
  },

  removeChangeTextListener: function(obj) {
    this.onChangeText.removeListener(obj);
  },

  addFocusListener: function(obj, event) {
    this.onFocus.addListener(obj, event);
  },

  removeFocusListener: function(obj) {
    this.onFocus.removeListener(obj);
  },

  addBlurListener: function(obj, event) {
    this.onBlur.addListener(obj, event);
  },

  removeBlurListener: function(obj) {
    this.onBlur.removeListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    this.onKeyDown.addListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    this.onKeyDown.removeListener(obj);
  },
  
  addKeyPressListener: function(obj, event) {
    this.onKeyPress.addListener(obj, event);
  },

  removeKeyPressListener: function(obj) {
    this.onKeyPress.removeListener(obj);
  },

  addSubmitListener: function(obj, event) {
    this.onSubmit.addListener(obj, event);
  },

  removeSubmitListener: function(obj) {
    this.onSubmit.removeListener(obj);
  },

  _getPreferredWidth: function() {
    var field = (this.dataset) ? this.dataset.findField(this.fieldName) : null;
    return field ? Math.round(field.size * this.charWidth) : 100;
  },

  _isEnabled: function() {
    var readonly = (this.dataset && (this.dataset.recno == -1)) || !this.enabled || !this.fixedEnabled;
    return !readonly;
  },

  _updateEnable: function() {
    var readonly = !this._isEnabled();

    if (this.edit != null) {
      this.edit.readOnly = readonly;

      var clsName = this.edit.readOnly ? 'editDisabled' : 'edit';
      if (this.edit.className != clsName)
        this.edit.className = clsName;
    }

    if (this.buttons != null)
      for (var i = 0; i < this.buttons.length; i++)
        if (this.buttons[i])
          this.buttons[i].setEnabled(!readonly);

    return !readonly;
  },

  _updateFieldType: function() {
    var field = (this.dataset) ? this.dataset.findField(this.fieldName) : null;

    if (field) {
      switch (field.type) {
        case 'number':
          this.editType = UI.Comps.Edit.EditType.ET_NUMBER;
          this.decimals = field.decimals;
          this.edit.style.textAlign = 'right';
          break;
        case 'string':
          if (this.editType != UI.Comps.Edit.EditType.ET_PASSWORD)
            this.editType = UI.Comps.Edit.EditType.ET_DEFAULT;

          if (field.mask)
            this.mask = field.mask;

          this.edit.style.textAlign = this.align;
          break;
      }
    } else
      if (this.editType == UI.Comps.Edit.EditType.ET_NUMBER)
        this.edit.style.textAlign = 'right';
      else
        this.edit.style.textAlign = this.align;

    this._updateEnable();
  },

  _onClearClick: function() {
    if (!this.dataset)
      this._oldtext = null;

    this._setText(null);
  },

  _addButton: function(image, imageDisabled, tooltip, onclick) {
    var params = {image: image,
                  imageDisabled: imageDisabled,
                  width: 11,
                  height: 18,
                  caption: '',
                  tooltip: tooltip
    };

    var button = new UI.Comps.Button(null, params);

    button.hideBorder();
    button.onClick = onclick;

    this.buttons.push(button);
    this._recreateControls();

    return button;
  },

  _createControls: function() {
    var table = document.createElement('table');
    var tbody = document.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.style.width = '100%';
    table.style.height = '100%';

    var tr = document.createElement('tr');
    table.childNodes[0].appendChild(tr);
    var td = document.createElement('td');
    tr.appendChild(td);
    this.edit = document.createElement('input');
    this.edit.className = 'edit';
    this.edit.style.width = '100%';
    this.edit.onkeypress = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._dokeypress(keyCode);
    }.bind(this);
    this.edit.onkeydown = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._dokeydown(keyCode, window.event || evt);
    }.bind(this);
    this.edit.onclick = function() {
      this._doeditclick();
    }.bind(this);
    this.edit.onpaste = function() {
      return false;
    }
    this.edit.onfocus = this._dofocus.bind(this);
    this.edit.onblur = this._doblur.bind(this);

    if (!this.tabstop)
      this.edit.tabIndex = -1;

    if (this.edtname)
      this.edit.name = this.edtname;

    switch (this.editType) {
      case UI.Comps.Edit.EditType.ET_PASSWORD:
        this.edit.type = 'password';
        break;
      case UI.Comps.Edit.EditType.ET_NUMBER:
        this.edit.align = 'right';
        break;
      case UI.Comps.Edit.EditType.ET_DEFAULT:
        this.edit.align = this.align;
        break;
    }

    this.edit.value = this.value || this.text;

    td.appendChild(this.edit);

    var btnLines = Math.ceil(this.buttons.length/2);
    var btn = 0;

    while (btn < this.buttons.length) {
      td = document.createElement('td');
      td.style.width = '1px';
      td.className = 'lookupSeparator';
      tr.appendChild(td);

      td = document.createElement('td');
      tr.appendChild(td);
      td.style.width = '11px';

      this.buttons[btn++].setParent(td);

      if (btn < this.buttons.length) {
        this.buttons[btn-1].setHeight(9);
        this.buttons[btn].setHeight(9);

        this.buttons[btn++].setParent(td);
      }
    }

    this.container.appendChild(table);
    this._updateFieldType();

    setTimeout((function() { if (this.edit) this.edit.style.width = this.edit.offsetWidth; }).bind(this), 1);
  },

  _destroyControls: function() {
    this.edit.onkeypress = null;
    this.edit.onkeydown = null;
    this.edit.onclick = null;
    this.edit.onpaste = null;
    this.edit.onfocus = null;
    this.edit.onblur = null;

    if (this.edit.parentNode)
      this.edit.parentNode.removeChild(this.edit);

    while (this.container.childNodes.length > 0)
      this.container.removeChild(this.container.childNodes[0]);

    this.edit = null;
  },

  _formatMask: function(keyCode) {
    var ch = String.fromCharCode(keyCode);
    var isNumber = ((keyCode >= 48) && (keyCode <= 57));
    var textSel = UI.getInputSelection(this.edit);

    if ((this.edit.value.length >= this.mask.length) && (textSel == ''))
      return false;

    if ((this.mask.charAt(this.edit.value.length) == '9') && !isNumber)
      return false;

    if ((this.mask.length > this.edit.value.length+1) && (this.mask.charAt(this.edit.value.length+1) != '9')) {
      this.edit.value += ch + this.mask.charAt(this.edit.value.length+1);
      return false;
    }

    if ((this.mask.length > this.edit.value.length) && (this.mask.charAt(this.edit.value.length) != '9')) {
      if (this.mask.charAt(this.edit.value.length) != ch) {
        this.edit.value += this.mask.charAt(this.edit.value.length);

        if ((this.mask.charAt(this.edit.value.length) != '9') || isNumber)
          this.edit.value += ch;
      } else
        this.edit.value += this.mask.charAt(this.edit.value.length);

      return false;
    }

    this.edit.value += '';
  },

  _formatNumber: function(keyCode) {
    if (keyCode == 46)
      keyCode = 44;

    var ch = String.fromCharCode(keyCode);
    var isNumber = ((keyCode >= 48) && (keyCode <= 57));
    var textSel = UI.getInputSelection(this.edit);

    if ((this.decimals == 0) && (ch == ','))
      return false;

    if (!isNumber && (ch != ',') && (ch != '-'))
      return false;

    if ((ch == '-') && (this.edit.value.indexOf('-') > -1) && (textSel.indexOf('-') == -1))
      return false;

    if ((ch == ',') && (this.edit.value.indexOf(',') > -1) && (textSel.indexOf(',') == -1))
      return false;

    var func = function() {
      if (this.edit.value.indexOf('.') > -1) {
        var caretPos = UI.getCaretPos(this.edit);
        var text = this.edit.value;

        if (this.decimals == 0)
          text = text.replace('.', '');

        this._setEditValue(text.replace('.', ','));
        UI.setCaretPos(this.edit, caretPos);
      }
    }.bind(this);

    setTimeout(func, 0);
  },

  _checkNewValue: function(value) {
    switch (this.editType) {
      case UI.Comps.Edit.EditType.ET_DEFAULT:
        if ((this.mask == '') || (this.edit.value == ''))
          return value;

        if (this.mask.length != this.edit.value.length)
          return false;

        for (var i = 0; i < this.mask.length; i++)
          if (this.mask.charAt(i) == '9') {
            if ('0123456789'.indexOf(this.edit.value.charAt(i)) == -1)
              return false;
          } else
            if (this.mask.charAt(i) != this.edit.value.charAt(i))
              return false;

        return value;

      case UI.Comps.Edit.EditType.ET_NUMBER:
        value = parseFloat(this.edit.value.replace('.', '').replace(',', '.'));
        return UI.roundTo(value || 0, this.decimals);
    }
    return value;
  },

  _setText: function(text) {
    var field = null;

    if (this.dataset && this.dataset.recno > -1)
      var field = this.dataset.findField(this.fieldName);

    if (text != this._oldtext)
      text = this._setFieldValue(field, text);

    if (this.editType == UI.Comps.Edit.EditType.ET_NUMBER) {
      while (text.indexOf('.') > -1)
        text = text.replace('.', '');

      text = text.replace(',', '.');

      this._setEditValue(UI.formatNumber(text, this.decimals), text);
    } else
      this._setEditValue(text);
  },

  _setEditValue: function(value, value2) {
    if ((value == null) && (this.editType != UI.Comps.Edit.EditType.ET_PASSWORD))
      value = '';

    var change = (value != this.edit.value);

    this.edit.value = value || '';

    if (value2 && (this.editType = UI.Comps.Edit.EditType.ET_NUMBER))
      this._setValue(value2);
    else
      this._setValue(value);

    if (this.text != value) {
      this.text = value;
      this.onChange.call(this);
    }

    if (change)
      this.onChangeText.call(this);
  },

  _setValue: function(value) {
    this.value = value;
  },

  _setFieldValue: function(field, value) {
    if (!field)
      if (this.editType == UI.Comps.Edit.EditType.ET_NUMBER)
        return UI.formatNumber(value, this.decimals);
      else
        return value;

    this._changingValue = true;
    field.setValue(value);
    this._changingValue = false;

    return field.getDisplayValue();
  },

  _dofocus: function() {
    var field = (this.dataset) ? this.dataset.findField(this.fieldName) : null;

    if (field)
      this._oldtext = field.getDisplayValue();
    else
      this._oldtext = this.edit.value;

    if (this.editType == UI.Comps.Edit.EditType.ET_PASSWORD)
      this.edit.value = '';

    if (this.edit.createTextRange) {
      var range = this.edit.createTextRange();
      range.select();
    } else
      if (typeof this.edit.selectionStart != undefined) {
        this.edit.selectionStart = 0;
        this.edit.selectionEnd = this.edit.value.length;
      }

    if (!this.focused)
      this._dofocusEvent();
  },

  _dofocusEvent: function() {
    if (!this.focused) {
      this.focused = true;
      this.onFocus.call(this);
    }
  },

  _doblur: function() {
    this._doConfirm();

    if (this.focused)
      return this._doblurEvent();
  },

  _doblurEvent: function(func) {
    if (this.focused) {
      this.focused = false;
      
      if (this.onBlur)
        return this.onBlur.call(this, func);
    }

    if (func)
      func();
  },

  _doConfirm: function() {
    if (this.edit.value != this._oldtext) {
      var text = '';
      var field = null;
      var validText = this._checkNewValue(this.edit.value).toString();

      if (this.editType == UI.Comps.Edit.EditType.ET_PASSWORD)
        if (this.edit.value == '') {
          this.edit.value = this._oldtext;
          validText = this._oldtext;
        }

      var s = (typeof validText == 'string') ? validText : this._oldtext;
      this._setText(s);
    }
  },

  _doeditclick: function() {
  },

  _dokeydown: function(key, evt) {
    var opt = [];

    opt.ctrl = evt.ctrlKey;
    opt.alt = evt.altKey;
    opt.shift = evt.shiftKey;

    if (opt.ctrl && (key == UI.key_search) && (this.editType == UI.Comps.Edit.EditType.ET_PASSWORD))
      if (this._isEnabled()) {
        this._setText(null);
        this._oldtext = null;
        return false;
      }

    this.onKeyDown.call(key, opt);

    if (key == 9)
      return true;

    if ((key == 27) || !this.enabled)
      return false;

    if ((key == 8) || (key == 46))
      this.onChangeText.call(this);

    if (key == 46)
      this._editDataset();
  },

  _dokeypress: function(key) {
    if (key == 13) {
      var form = UI.getParentForm(this.container);

      if (form && form.submitButton) {
        if (document.body) {
          document.body.focus();
          setTimeout(function() { form.submitButton.click(); }, 1);
        } else
          form.submitButton.click();
      } else {
        this.onSubmit.call();
        return false;
      }
    }

    this.onKeyPress.call(key);

    if ((key == 27) || !this.enabled)
      return false;

    if ((key == 8) || (key == 0))
      return true;

    if (key != 46) {
      this.onChangeText.call(this);
      this._editDataset();
    }

    if (this.editType == UI.Comps.Edit.EditType.ET_NUMBER)
      return this._formatNumber(key);
    else
      if (this.mask != '')
        return this._formatMask(key);
      else
        return true;
  },

  _doChange: function(field) {
    if (this._changingValue)
      return;

    field = field || this.dataset.findField(this.fieldName);

    if (field && (field.name == this.fieldName)) {
      var value = field.getDisplayValue();

      this._setEditValue((value == null) ? '' : value);
      this._oldtext = this.value;
    }
    this._updateEnable();
  },

  _editDataset: function() {
    if (this.dataset && (this.dataset.status == UI.Comps.DataSet.RecordState.RS_NORMAL))
      this.dataset.edit();
  }
});


/********** accordion.js **********/


UI.Comps.Accordion = Class.create();

UI.Comps.Accordion.prototype = {

  container: null,
  options: {},

  initialize: function(container, options) {
    this.container = $(container);
    this.lastExpandedTab = null;
    this.accordionTabs = new Array();
    this.setOptions(options);
    this._attachBehaviors();

    this.container.className = 'accordionBackground';
    this.options.onLoadShowTab = 0;

    for (var i = 0; i < this.accordionTabs.length; i++)
      if (i != this.options.onLoadShowTab) {
        this.accordionTabs[i].collapse();
        this.accordionTabs[i].content.style.display = 'none';
      }

    this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
    if (this.options.panelHeight == 'auto') {
      var tabToCheck = (this.options.onloadShowTab === 0) ? 1 : 0;
      var titleBarSize = parseInt(UI.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
        if (isNaN(titleBarSize))
          titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;

        var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
        var parentHeight = parseInt(UI.getElementsComputedStyle(this.container.parentNode, 'height'));
        if (isNaN(parentHeight))
          parentHeight = this.container.parentNode.offsetHeight;

        this.options.panelHeight = parentHeight - totalTitleBarSize-2;
    }

    this.lastExpandedTab.content.style.height = this.options.panelHeight + 'px';
    this.lastExpandedTab.showExpanded();
  },

  setHeight: function(height) {
    var tabToCheck = (this.options.onloadShowTab === 0) ? 1 : 0;
    var titleBarSize = parseInt(UI.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
      if (isNaN(titleBarSize))
        titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;

      var totalTitleBarSize = this.accordionTabs.length * titleBarSize;

    if (UI.isFirefox)
      totalTitleBarSize += 2;

    this.options.panelHeight = height;
    this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
    this.container.style.height = (this.options.panelHeight + totalTitleBarSize) + 'px';
    this.lastExpandedTab.showExpanded();
  },

  setOptions: function(options) {
    this.options = {
      panelHeight         : 200,
      onHideTab           : null,
      onShowTab           : null,
      onLoadShowTab       : 0
    }
    Object.extend(this.options, options || {});
  },

  showTabByIndex: function(anIndex, animate) {
    var doAnimate = arguments.length == 1 ? true : animate;
    this.showTab(this.accordionTabs[anIndex], doAnimate);
  },

  showTab: function(accordionTab, animate) {
    if (this.lastExpandedTab == accordionTab)
      return;

    var doAnimate = arguments.length == 1 ? true : animate;

    if (this.options.onHideTab)
      this.options.onHideTab(this.lastExpandedTab);

    this.lastExpandedTab.showCollapsed(); 
    var accordion = this;
    var lastExpandedTab = this.lastExpandedTab;

    this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
    accordionTab.content.style.display = '';

    if (doAnimate) {
      new UI.Comps.AccordionSize(this.lastExpandedTab.content,
                 accordionTab.content, 1, this.options.panelHeight, 100, 10,
                 { complete: function() {accordion.showTabDone(lastExpandedTab)} });

        this.lastExpandedTab = accordionTab;
    } else {
      this.lastExpandedTab.content.style.height = '1px';
      accordionTab.content.style.height = this.options.panelHeight + 'px';
      this.lastExpandedTab = accordionTab;
      this.showTabDone(lastExpandedTab);
    }
  },

  showTabDone: function(collapsedTab) {
    collapsedTab.content.style.display = 'none';
    this.lastExpandedTab.showExpanded();
    if (this.options.onShowTab)
      this.options.onShowTab(this.lastExpandedTab);
  },

  _attachBehaviors: function() {
    var panels = this._getDirectChildrenByTag(this.container, 'DIV');

    for (var i = 0; i < panels.length; i++) {
      var tabChildren = this._getDirectChildrenByTag(panels[i], 'DIV');
      if (tabChildren.length != 2)
        continue;

      var tabTitleBar = tabChildren[0];
      var tabContentBox = tabChildren[1];
      this.accordionTabs.push(new UI.Comps.Accordion.Tab(this, tabTitleBar, tabContentBox));
    }
  },

  _getDirectChildrenByTag: function(e, tagName) {
    var kids = new Array();
    var allKids = e.childNodes;

    for(var i = 0; i < allKids.length; i++)
      if (allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName)
        kids.push(allKids[i]);

    return kids;
  }
}

UI.Comps.Accordion.Tab = Class.create();

UI.Comps.Accordion.Tab.prototype = {

  accordion: null,
  titleBar: null,
  content: null,

  initialize: function(accordion, titleBar, content) {
    this.accordion = accordion;
    this.titleBar = titleBar;
    this.content = content;
    this._attachBehaviors();
  },

  collapse: function() {
    this.showCollapsed();
    this.content.style.height = '1px';
  },

  showCollapsed: function() {
    this.expanded = false;
    this.titleBar.className = 'accordionTitleBarNormal';
    this.content.style.overflow = 'hidden';
  },

  showExpanded: function() {
    this.expanded = true;
    this.titleBar.className = 'accordionTitleBarExpanded';
    this.content.style.overflow = 'auto';
  },

  titleBarClicked: function(e) {
    if (this.accordion.lastExpandedTab != this)
      this.accordion.showTab(this);
  },

  hover: function(e) {
    if (!this.expanded)
      this.titleBar.className = 'accordionTitleBarHover';
  },

  unhover: function(e) {
    this.titleBar.className = (this.expanded) ? 'accordionTitleBarExpanded' : 'accordionTitleBarNormal';
  },

  _attachBehaviors: function() {
    this.content.className = 'accordionContent';

    this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
    this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
    this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
  }
}

UI.Comps.AccordionSize = Class.create();

UI.Comps.AccordionSize.prototype = {

  initialize: function(e1, e2, start, end, duration, steps, options) {
    this.e1 = $(e1);
    this.e2 = $(e2);
    this.start = start;
    this.end = end;
    this.duration = duration;
    this.steps = steps;
    this.options = arguments[6] || {};

    this.accordionSize();
  },

  accordionSize: function() {

    if (this.isFinished()) {
      this.e1.style.height = this.start + 'px';
      this.e2.style.height = this.end + 'px';

      if (this.options.complete)
        this.options.complete(this);

      return;
    }

    if (this.timer)
      clearTimeout(this.timer);

    var stepDuration = Math.round(this.duration/this.steps);

    var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
    this.resizeBy(diff);

    this.duration -= stepDuration;
    this.steps--;

    this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
  },

  isFinished: function() {
    return this.steps <= 0;
  },

  resizeBy: function(diff) {
    var h1Height = this.e1.offsetHeight;
    var h2Height = this.e2.offsetHeight;
    var intDiff = parseInt(diff);

    if (diff != 0) {
      this.e1.style.height = (h1Height - intDiff) + 'px';
      this.e2.style.height = (h2Height + intDiff) + 'px';
    }
  }
}


/********** modalframe.js **********/


UI.Comps.ModalFrame = Class.create();

UI.Comps.ModalFrame.SubDir = 'ModalFrame/';
UI.Comps.ModalFrame.Images = ['ModalFrame_01.gif', 'ModalFrame_02.gif'];

UI.Comps.ModalFrame.ModalResult = {
  MR_OK     : 0,
  MR_CANCEL : 1
}

UI.Comps.ModalFrame.prototype = {

  backFrame: null,
  shadowFrame: null,
  frontFrame: null,
  frame: null,
  tdTitle: null,
  btnClose: null,
  showing: false,
  parentWindow: null,

  initialize: function(wnd) {
    this.parentWindow = (wnd) ? wnd : UI.getFirstWindow(false);

    this.backFrame = this.parentWindow.document.createElement('div');
    this.backFrame.style.display = 'none';
    this.backFrame.className = 'modalBackground';
    UI.disableSelection(this.backFrame);

    this.parentWindow.document.body.style.marginRight = '0px';
    this.parentWindow.document.body.appendChild(this.backFrame);

    this.shadowFrame = this.parentWindow.document.createElement('div');
    this.shadowFrame.style.display = 'none';
    this.shadowFrame.style.position = 'absolute';
    this.shadowFrame.className = 'modalShadow';
    UI.disableSelection(this.shadowFrame);
    this.parentWindow.document.body.appendChild(this.shadowFrame);

    this.frontFrame = this.parentWindow.document.createElement('div');
    this.frontFrame.style.display = 'none';
    this.frontFrame.style.width = '600px';
    this.frontFrame.style.height = '500px';
    this.frontFrame.className = 'modalFrameFront';
    UI.disableSelection(this.frontFrame);
    this.parentWindow.document.body.appendChild(this.frontFrame);

    this._onClose = null;
    this._createWindow();
  },

  show: function(options) {
    this._onClose = null;

    var doc = UI.getDocumentFromIframe(this.frame);

    if (doc) {
      this.frame.src = '';

      doc.open();
      doc.write(UI.getLanguageTag('loading'));
      doc.close();
    }

    if (options) {
      this.frontFrame.style.width = (options.width) ? options.width+'px' : '600px';
      this.frontFrame.style.height = (options.height) ? options.height+'px' : '500px';
      this.tdTitle.innerHTML = (options.title) ? options.title : '&nbsp;';
      this._onClose = (options.onClose) ? options.onClose : null;

      if (options.url)
        this.frame.src = options.url;

      this.btnClose.setEnabled((typeof options.canClose != 'boolean') || options.canClose);
    }

    this.backFrame.style.display = '';
    this.frontFrame.style.display = '';
    this.shadowFrame.style.display = '';
    this._update();
    this.showing = true;
  },

  close: function(modalResult) {
    if (this.showing) {
      var onClose = this._onClose;

      if (onClose && !onClose.apply(null, arguments))
        return false;

      this._onClose = null;

      var doc = UI.getDocumentFromIframe(this.frame);

      if (doc && doc.body && (typeof doc.body.onunload == 'function')) {
        doc.body.onunload.call(doc.body);
        doc.body.onunload = null;
      }

      this.showing = false;
      this.frontFrame.style.display = 'none';
      this.shadowFrame.style.display = 'none';
      this.backFrame.style.display = 'none';

      return true;
    }
  },

  _createWindow: function() {
    var table = this.parentWindow.document.createElement('table');
    var tbody = this.parentWindow.document.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    table.style.width = '100%';
    table.style.height = '100%';

    var tr = this.parentWindow.document.createElement('tr');
    tbody.appendChild(tr);
    tr.className = 'modalTitleBar';
    this.tdTitle = this.parentWindow.document.createElement('td');
    tr.appendChild(this.tdTitle);
    tr.style.height = '21px';
    this.tdTitle.className = 'modalTitleBarFont';
    this.tdTitle.innerHTML = '&nbsp;';
    this.tdTitle.style.width = '100%';
    this.tdTitle.style.paddingLeft = '4px';
    UI.disableSelection(this.tdTitle);

    var td = this.parentWindow.document.createElement('td');
    tr.appendChild(td);
    td.style.width = '25px';

    var options = {
      caption: '',
      width: 18,
      height: 18,
      tooltip: UI.getLanguageTag('close'),
      image: this._getImage(0),
      imageDisabled: this._getImage(1),
      document: this.parentWindow.document
    }

    this.btnClose = new UI.Comps.Button(null, options);
    this.btnClose.setParent(td);
    this.btnClose.container.style.marginRight = '2px';

    this.btnClose.onClick = function() {
      UI.closeModalFrame(this, UI.Comps.ModalFrame.ModalResult.MR_CANCEL);
    }.bind(this);

    tr = this.parentWindow.document.createElement('tr');
    tbody.appendChild(tr);
    td = this.parentWindow.document.createElement('td');
    tr.appendChild(td);
    td.colSpan = 2;

    this.frame = this.parentWindow.document.createElement('iframe');
    td.appendChild(this.frame);
    this.frame.frameBorder = 0;
    this.frame.scrolling = 'no';
    this.frame.style.width = '100%';
    this.frame.style.height = '100%';
    this.frame.style.backgroundColor = 'white';

    this.frontFrame.appendChild(table);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.ModalFrame, index);
  },

  _update: function() {
    this.backFrame.style.top = this.parentWindow.document.body.scrollTop+'px';

    var t = Math.max(Math.round(this.backFrame.offsetHeight/2 - this.frontFrame.offsetHeight/2), 0);
    var l = Math.max(Math.round(this.backFrame.offsetWidth/2 - this.frontFrame.offsetWidth/2), 0);

    this.frontFrame.style.top = (t+this.parentWindow.document.body.scrollTop)+'px';
    this.frontFrame.style.left = (l+this.parentWindow.document.body.scrollLeft)+'px';

    this.shadowFrame.style.top = parseFloat(this.frontFrame.style.top)+5 + 'px';
    this.shadowFrame.style.left = parseFloat(this.frontFrame.style.left)+5 + 'px';
    this.shadowFrame.style.width = this.frontFrame.style.width;
    this.shadowFrame.style.height = this.frontFrame.style.height;
  }
}


/********** combo.js **********/


UI.Comps.Combo = Class.create();

UI.Comps.Combo.SubDir = 'Combo/';
UI.Comps.Combo.Images = ['Combo_01.gif', 'Combo_02.gif', 'Combo_03.gif', 'Combo_04.gif'];

UI.Comps.Combo.ComboType = {
  CT_NORMAL   : 0,
  CT_DROPLIST : 1,
  CT_CHECKLIST: 2
};

UI.Comps.Combo.prototype = UI.extend(UI.Comps.Edit, {

  popup: null,
  btnPopup: null,

  comboType: UI.Comps.Combo.ComboType.CT_NORMAL,
  selectedIndex: -1,
  value: '',
  canClear: false,

  initialize: function(container, options) {
    if (options) {
      if ((typeof options.droplist == 'boolean') && options.droplist)
        this.comboType = UI.Comps.Combo.ComboType.CT_DROPLIST;

      if ((typeof options.checklist == 'boolean') && options.checklist)
        this.comboType = UI.Comps.Combo.ComboType.CT_CHECKLIST;
    }

    this.superclass2.initialize.call(this, container, options);

    this.btnPopup = this._addButton(this._getImage(0), this._getImage(1), '', this._onButtonClick.bind(this));
    this.popup = new UI.Comps.PopupCombo(this);
    this.ignoreBlurEvent = false;
    this.timeoutblur = null;

    var items = [];
    var vlrPadrao = null;

    if (options) {
      if (typeof options.items == 'string')
        items = options.items.split(';');

      if (typeof options.canClear == 'boolean')
        this.canClear = options.canClear;
    }

    if (this.dataset && (items.length == 0)) {
      var field = this.dataset.findField(this.fieldName);

      if (field) {
        items = field.items.split(';');

        if (typeof field.getValue() == 'string') {
          this.value = field.getValue();
          vlrPadrao = this.value.split(',');
        }
      }
    }

    for (var i = 0; i < items.length; i++) {
      this.addItem(items[i]);

      if (vlrPadrao)
        this.popup._getItem(i).checked = vlrPadrao.indexOf(this.popup._getItem(i).key) > -1;
    }

    if (vlrPadrao)
      this._updateCheckedValue(false);

    if (options && (typeof options.selectedIndex == 'number'))
      if ((options.selectedIndex >= 0) && (options.selectedIndex < items.length)) {
        var item = this.getItem(options.selectedIndex);
        this.selectedIndex = options.selectedIndex;
        this.value = item.key;
        this.text = item.caption;
        this.edit.value = this.text;
      }
  },

  dispose: function() {
    this.btnPopup = null;

    this.superclass2.dispose.call(this);
  },

  addItem: function(caption, flag) {
    var idx = this.popup._addItem(caption);

    if (flag) // selected or checked
      if (this.comboType == UI.Comps.Combo.ComboType.CT_DROPLIST)
        this.setSelectedIndex(idx);
      else if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST)
        this.setChecked(idx);
  },

  clear: function() {
    this.popup._clear();
  },

  getCount: function() {
    return this.popup._getCount();
  },

  getItem: function(index) {
    return this.popup._getItem(index);
  },

  setSelectedIndex: function(index) {
    var item = this.popup._getItem(index);

    if (item && (typeof item == 'object')) {
      this.selectedIndex = index;
      this.value = item.key;
      this._setText(item.caption);
    }
  },

  setChecked: function(index) {
    var item = this.popup._getItem(index);
    if (item && (typeof item == 'object')) {
      item.checked = true;
      this._updateCheckedValue();
    }
  },

  checkAll: function() {
    var cnt = this.getCount();

    for (var i = 0; i < cnt; i++)
      this.getItem(i).checked = true;

    this._updateCheckedValue();
  },

  unCheckAll: function() {
    var cnt = this.getCount();

    for (var i = 0; i < cnt; i++)
      this.getItem(i).checked = false;

    this._updateCheckedValue();
  },

  clear: function() {
    this.selectedIndex = -1;
    this.value = '';
    this.text = '';
    this.edit.value = '';
    this._oldtext = '';
    this.superclass2.clear.call(this);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.Combo, index);
  },

  _getTextWidth: function(caption) {
    var owner = document.createElement('div');
    owner.display = 'none';

    document.body.appendChild(owner);
    var w = UI.getTextWidth(caption, owner, 'attributeCaption');
    document.body.removeChild(owner);

    return w;
  },

  _updateCheckedValue: function(setvalue) {
    var cnt = this.getCount();
    var value = '';
    var caption = '';

    for (var i = 0; i < cnt; i++) {
      var item = this.getItem(i);

      if (item.checked) {
        value += item.key + ',';
        caption = (caption == '') ? item.caption : UI.getLanguageTag('combo_all');
      }
    }

    if (value.length > 0)
      value = value.substring(0, value.length-1);

    if (this.value != value)
      if ((typeof setvalue != 'boolean') || setvalue)
        this._setValue(value);

    if (caption != this.text)
      this._setText(caption);
  },

  _createControls: function() {
    this.superclass2._createControls.call(this);
  },


  _setText: function(text) {
    if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST) {
      this.text = text;
      this._setEditValue(text);
    } else
      this.superclass2._setText.call(this, text);
  },

  _setEditValue: function(value) {
    if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST) {
      this.edit.value = (value || '');
      this.onChange.call(this);
    } else
      this.superclass2._setEditValue.call(this, value);
  },

  _setValue: function(value) {
    if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST)
      this.value = value;
    else
      if (this.selectedIndex > -1) {
        this.value = this.getItem(this.selectedIndex).key;
      } else
        this.value = '';
  },

  _setFieldValue: function(field, value) {
    if (field) {
      var items = field.items.split(';');
      var key = field.getValue();
    } else {
      var items = new Array();
      var key = this.value;

      for (var i = 0; i < this.getCount(); i++) {
        var item = this.getItem(i);
        items.push(item.key+'='+item.caption);
      }
    }

    var newvalue = this._oldtext;
    var key = null;

    if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST) {
      var s = '';

      for (var i = 0; i < items.length; i++)
        if (this.getItem(i).checked)
          s += this.getItem(i).key + ',';

      if (s != '')
        key = s.substring(0, s.length-1);
    } else {
      var funcTest = function(value, str) {
        if (value == '')
          return (str == '');
        else
          return str.substring(0, value.length).toLowerCase() == value.toLowerCase();
      }

      if ((value == '') && (this.canClear)) {
        key = null;
        newvalue = '';
        this.selectedIndex = -1;
      } else
        for (var i = 0; i < items.length; i++) {
          var s = items[i].split('=');

          if ((s.length == 1) && funcTest(value, s[0])) {
            key = s[0];
            newvalue = s[0];
            this.selectedIndex = i;
            break;
          }

          if ((s.length == 2) && funcTest(value, s[1])) {
            key = s[0];
            newvalue = s[1];
            this.selectedIndex = i;
            break;
          }
        }
    }

    if (!field) {
      this.value = key;
      return newvalue;
    } else
      return this.superclass2._setFieldValue.call(this, field, key);
  },

  _getWidth: function() {
    return this.container.offsetWidth;
  },

  _updateEnable: function() {
    this.superclass2._updateEnable.call(this);
    this.edit.readOnly = this.edit.readOnly || 
                         (this.comboType == UI.Comps.Combo.ComboType.CT_DROPLIST) ||
                         (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST);
  },

  _doblur: function() {
    if (this.canClear && (this.comboType == UI.Comps.Combo.ComboType.CT_NORMAL))
      if ((this.edit.value == '') && (this._oldtext != '')) {
        this.selectedIndex = -1;
        this.value = '';
        this._oldtext = '';

        var field = this.dataset ? this.dataset.findField(this.fieldName) : null;
        if (field)
          this._setFieldValue(field, '');
      }

    this.superclass2._doblur.call(this);
  },

  _dofocusEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    this.superclass2._dofocusEvent.call(this);
  },

  _doblurEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    if (this.ignoreBlurEvent)
      return;

    var f = function() {
      if (!this.popup.showing && this.focused)
        this.superclass2._doblurEvent.call(this);
    }

    this.timeoutblur = setTimeout(f.bind(this), 100);
  },

  _doeditclick: function() {
    if (!this.enabled || !this.fixedEnabled)
      return;

    if (!this.popup.showing && ((this.comboType == UI.Comps.Combo.ComboType.CT_DROPLIST) || 
      (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST))) {
      this._onButtonClick();
    } else {
      this.ignoreBlurEvent = true;
      this.popup.Close();
      this.ignoreBlurEvent = false;
      this._dofocusEvent();
    }
  },

  _dokeypress: function(key) {
    this.superclass2._dokeypress.call(this, key);

    if ((this.comboType == UI.Comps.Combo.ComboType.CT_DROPLIST) || 
      (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST))
      if (key == 8)
        return false;
  },

  _dokeydown: function(key, evt) {
    this.superclass2._dokeydown.call(this, key, evt);

    if (evt.ctrlKey || evt.altKey)
      if ((key == 40) && !this.popup.showing)
        this._onButtonClick();

    if ((this.comboType == UI.Comps.Combo.ComboType.CT_DROPLIST) ||
      (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST))
      if (key == 8)
        return false;
  },

  _onkeydown: function(key, evt) {
    if (this.popup.showing) {
      if (key == 27) {
        this._onButtonClick();
        this.edit.focus();
      }

      if (this.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST)
        if ((key == 32) && (this.popup.popup._selected > -1)) {
          var p = this.popup.popup;
          p._onItemClick(p._selected, p.tds[p._selected]);
        }
    }
  },

  _onButtonClick: function() {
    if (this._isEnabled())
      if (!this.popup.showing) {
        var p = UI.getAbsolutePosition(this.container);

        this.edit.focus();
        this.popup.Show(p.x, p.y+this.container.offsetHeight, this.container.offsetWidth);
      } else
        this.popup.Close();
  }
});

UI.Comps.PopupCombo = Class.create();

UI.Comps.PopupCombo.prototype = UI.extend(UI.Comps.Popup, {

  combo: null,

  initialize: function(combo) {
    this.superclass.initialize.call(this);

    this.combo = combo;
    this.popup = new UI.Comps.PopupComboItems(this, null, '', combo);
  },

  _addItem: function(caption) {
    return this.popup._addItem(caption);
  },

  _getItem: function(index) {
    return this.popup._getItem(index);
  },

  _getCount: function() {
    return this.popup._getCount();
  },

  _clear: function() {
    this.popup._clear();
  }
});

UI.Comps.PopupComboItems = Class.create();

UI.Comps.PopupComboItems.prototype = UI.extend(UI.Comps.PopupItem, {

  combo: null,
  height: 100,
  items: null,

  initialize: function(popup, parent, caption, combo) {
    this.superclass.initialize.call(this, popup, parent, caption);

    this.combo = combo;
    this.items = new Array();

    this.div = null;
    this.tds = new Array();
    this.chks = new Array();
    this._selected = -1;
  },

  dispose: function() {
    this.chks.length = 0;
    this.chks = null;
    this.tds.length = 0;
    this.tds = null;
    this.div = null;

    this.superclass.dispose.call(this);
  },

  _addItem: function(caption) {
    var item = new UI.Comps.PopupComboItem(caption);
    this.items[this.items.length] = item;

    return this.items.length-1;
  },

  _getItem: function(index) {
    return this.items[index];
  },

  _getCount: function() {
    return this.items.length;
  },

  _clear: function() {
    this.items.length = 0;
  },

  _getWidth: function() {
    return this.combo._getWidth();
  },

  _getHeight: function() {
    return this.height;
  },

  _createTable: function() {
    var table = this.doc.createElement('table');
    var tbody = this.doc.createElement('tbody');
    table.appendChild(tbody);
    table.cellPadding = '0px';
    table.cellSpacing = '0px';
    return table;
  },

  _createContents: function(doc) {
    var css = doc.createElement("link");
    css.rel = "stylesheet";
    css.href = UI.arqStyles;
    css.type = "text\/css";
    doc.body.appendChild(css);

    var div = doc.createElement('div');
    div.style.width = '100%';
    div.style.height = '100%';
    div.style.overflow = 'auto';
    div.style.marginTop = '-2px';
    div.className = 'comboPopupBackground';
    UI.disableSelection(div);
    this.div = div;

    this._selected = this.combo.selectedIndex;
    this._createItems(div);
    doc.body.appendChild(div);
    doc.body.className = 'comboPopupBorder';

    div.onfocus = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);

    div.onmousedown = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);
  },

  _createItems: function(owner) {
    var table = this._createTable();
    table.style.tableLayout = 'fixed';
    table.style.width = '100%';
    this.tds.length = this.items.length;
    this.chks.length = this.items.length;

    for (var i = 0; i < this.items.length; i++)
      if (this.items[i] != null) {
        var tr = this.doc.createElement('tr');
        table.childNodes[0].appendChild(tr);
        var td = this.doc.createElement('td');
        tr.appendChild(td);
        

        if (this.combo.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST) {
          td.className = 'comboItemNormal';

          this.chks[i] = this.doc.createElement('img');
          this.chks[i].src = this.combo._getImage(this.items[i].checked ? 2 : 3);

          td.appendChild(this.chks[i]);
          td.appendChild(this.doc.createTextNode(' ' + this.items[i].caption));
        } else {
          td.className = (i == this.combo.selectedIndex) ? 'comboItemSelected' : 'comboItemNormal';
          td.innerHTML = this.items[i].caption;
        }

        td.onclick = this._onItemClick.bind(this, i, td);
        UI.disableSelection(td);
        this.tds[i] = td;
      }

    owner.appendChild(table);
  },

  _destroyContents: function() {
    this.tds.length = 0;
    this.chks.length = 0;
    this.div = null;
  },

  _show: function(x, y, objWidth, objHeight) {
    this.superclass._show.call(this, x, y, objWidth, objHeight);

    document.body.unselectable = "off";
  },

  _hide: function() {
    document.body.unselectable = "on";
    this.superclass._hide.call(this);

    this.combo._doblurEvent();
  },

  _updateItemsClass: function() {
    for (var i = 0; i < this.tds.length; i++)
      this.tds[i].className = (i == this._selected) ? 'comboItemSelected' : 'comboItemNormal';

    if (this._selected > -1) {
      var td = this.tds[this._selected];
      var p = UI.getAbsolutePosition(td);

      if (p.y < this.div.scrollTop)
        this.div.scrollTop = p.y;
      else
        if (p.y + td.offsetHeight > this.div.scrollTop + this.div.offsetHeight)
          this.div.scrollTop = p.y + td.offsetHeight - this.div.offsetHeight;
    }
  },

  _onkeydown: function(key, evt) {
    switch (key) {
      case 33: //page up
        this._selected = Math.max(this._selected-5, 0);
        this._updateItemsClass();
        break;
      case 34: //page down
        this._selected = Math.min(this._selected+5, this.items.length-1);
        this._updateItemsClass();
        break;
      case 38: //up
        this._selected = Math.max(this._selected-1, 0);
        this._updateItemsClass();
        break;
      case 40: //down
        this._selected = Math.min(this._selected+1, this.items.length-1);
        this._updateItemsClass();
        break;
      case 13: //enter
        if (this._selected > -1)
          this._onItemClick(this._selected, this.tds[this._selected]);
        break;
    }

    this.combo._onkeydown(key, evt);
  },

  _onItemClick: function(index, td) {
    this.combo.ignoreBlurEvent = true;

    if (this.combo.comboType == UI.Comps.Combo.ComboType.CT_CHECKLIST) {
      this._selected = index;
      this._updateItemsClass();

      this.items[index].checked = !this.items[index].checked;
      this.chks[index].src = this.combo._getImage(this.items[index].checked ? 2 : 3);

      if (this.combo.dataset) {
        var field = this.combo.dataset.findField(this.combo.fieldName);

        if (field)
          this.combo._setFieldValue(field, null);
      }

      this.combo._updateCheckedValue();
      this.btn.focus();
    } else {
      this.combo.setSelectedIndex(index);
      this.popup.Close();

      setTimeout((function() { this.combo.edit.focus(); }).bind(this), 0);
      setTimeout((function() { this.combo.ignoreBlurEvent = false; }).bind(this), 1);
    }
  }
});

UI.Comps.PopupComboItem = Class.create();

UI.Comps.PopupComboItem.prototype = {

  key: '',
  caption: '',

  initialize: function(caption) {
    if (caption.indexOf('=') == -1) {
      this.key = caption;
      this.caption = caption;
    } else {
      this.key = caption.substring(0, caption.indexOf('='));
      this.caption = caption.substring(caption.indexOf('=')+1);
    }
  }
}


/********** attribute.js **********/


UI.Comps.Attribute = Class.create();

UI.Comps.Attribute.AttributeType = {
  AT_DEFAULT : 0,
  AT_COMBO   : 2,
  AT_CHECKBOX: 3,
  AT_DATE    : 4,
  AT_MEMO    : 5,
  AT_RADIO   : 6,
  AT_TIME    : 7
}

UI.Comps.Attribute.prototype = {

  container: null,
  caption: '',
  labelWidth: 0,
  width: 150,
  height: 0,
  type: UI.Comps.Attribute.AttributeType.AT_DEFAULT,
  dataset: null,
  fieldname: '',
  control: null,
  enabled: true,
  column: 0,
  fixedEnabled: true,
  onChange: null,

  initialize: function(container, options, isLookup) {
    this.container = (typeof container == 'string') ? $(container) : container;

    if (!this.container) {
      this.containerCreated = true;
      this.container = document.createElement('div');
    }

    if (options) {
      if (typeof options.labelWidth == 'number')
        this.labelWidth = options.labelWidth;

      if (typeof options.width == 'number')
        this.width = options.width;

      if (typeof options.col == 'number')
        this.column = options.col;

      if ((typeof options.caption == 'object') || (typeof options.caption == 'string'))
        this.caption = (typeof options.caption == 'string') ? options.caption : null;

      if (typeof options.attType == 'number')
        this.type = options.attType;

      if (typeof options.enabled == 'boolean')
        this.enabled = options.enabled;

      if (typeof options.ds == 'object')
        this.setDataset(options.ds);

      if (typeof options.fieldname == 'string')
        this.fieldname = options.fieldname;

      if (typeof options.attType == 'string')
        if (options.attType == 'combo')
          this.type = UI.Comps.Attribute.AttributeType.AT_COMBO;
        else
          if (options.attType == 'checkbox')
            this.type = UI.Comps.Attribute.AttributeType.AT_CHECKBOX;
          else
            if (options.attType == 'date')
              this.type = UI.Comps.Attribute.AttributeType.AT_DATE;
            else
              if (options.attType == 'radio')
                this.type = UI.Comps.Attribute.AttributeType.AT_RADIO;
              else
                if (options.attType == 'time')
                  this.type = UI.Comps.Attribute.AttributeType.AT_TIME;
                else
                  this.type = UI.Comps.Attribute.AttributeType.AT_MEMO;
    }

    this.tdCaption = null;
    this._updateProperties();
    this._createComponents(options);

    if (!isLookup)
      UI.Attributes.push(this);
    UI.Controls.push(this);

    this.addChangeTextListener(this, this._onChangeText);
  },

  dispose: function() {
    UI.Controls = UI.Controls.without(this);
    UI.Attributes = UI.Attributes.without(this);

    this.removeChangeTextListener(this);
    this.onChange = null;

    this._destroyComponents();
    this.setDataset(null);

    if (this.containerCreated && this.container.parentNode)
      this.container.parentNode.removeChild(this.container);

    this.tdCaption = null;
    this.container = null;
    this.control = null;
  },

  setDataset: function(dataset) {
    this.dataset = dataset;

    if (this.control && !this.isLookup)
      if (this.control.setDataset)
        this.control.setDataset(dataset);
      else
        this.control.setDataSet(dataset);
  },

  setParent: function(owner) {
    if (owner) {
      if (this.container.parentNode)
        this.container.parentNode.removeChild(this.container);

      owner.appendChild(this.container);
    }
  },

  focused: function() {
    return this.control.focused;
  },

  doBlurEvent: function(func) {
    if (this.control._doblurEvent)
      this.control._doblurEvent(func);
    else
      func();
  },

  setFixedEnabled: function(value) {
    if (this.fixedEnabled != value) {
      this.fixedEnabled = value;

      this.control.setFixedEnabled(value);
      this._updateEnable();
    }
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;
      this.control.setEnabled(value);

      this._updateEnable();
    }
  },

  setLabelWidth: function(value) {
    if (this.type == UI.Comps.Attribute.AttributeType.AT_CHECKBOX)
      value--;

    this.labelWidth = value;
    this.tdCaption.style.width = value + 'px';
    this.width = value + this._getControlWidth() + 2;
    this.container.style.width = this.width + 'px';
  },

  getLabelWidth: function(caption) {
    if (this.labelWidth > 0)
      return this.labelWidth;

    return this._getTextWidth(caption) + 4;
  },
  
  confirm: function(func) {
    this.control.confirm();
    
    if (func)
      func();
  },
  
  cancel: function() {
    this.control.cancel();
  },

  focus: function() {
    this.control.focus();
  },

  getValue: function() {
    return this.control.value;
  },

  setValue: function(value) {
    this.control.setText(value);
  },

  addSubmitListener: function(obj, event) {
    this.control.addSubmitListener(obj, event);
  },

  removeSubmitListener: function(obj) {
    this.control.removeSubmitListener(obj);
  },

  addChangeTextListener: function(obj, event) {
    this.control.addChangeTextListener(obj, event);
  },

  removeChangeTextListener: function(obj) {
    this.control.removeChangeTextListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    this.control.addKeyDownListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    this.control.removeKeyDownListener(obj);
  },

  addKeyPressListener: function(obj, event) {
    this.control.addKeyPressListener(obj, event);
  },

  removeKeyPressListener: function(obj) {
    this.control.removeKeyPressListener(obj);
  },

  addBlurListener: function(obj, event) {
    this.control.addBlurListener(obj, event);
  },

  removeBlurListener: function(obj) {
    this.control.removeBlurListener(obj);
  },

  _addFocusListener: function(obj, event) {
    this.control.addFocusListener(obj, event);
  },

  _addBlurListener: function(obj, event) {
    this.control.addBlurListener(obj, event);
  },

  _onChangeText: function() {
    if (this.onChange)
      this.onChange();
  },

  _updateEnable: function() {
  },

  _updateProperties: function() {
    var field = this.dataset ? this.dataset.findField(this.fieldname) : null;

    if (field) {
      if (field.type == 'combo')
        this.type = UI.Comps.Attribute.AttributeType.AT_COMBO;
      else
        if (field.type == 'bool')
          this.type = UI.Comps.Attribute.AttributeType.AT_CHECKBOX;
        else
          if (field.type == 'date')
            this.type = UI.Comps.Attribute.AttributeType.AT_DATE;
          else
            if (field.type == 'memo')
              this.type = UI.Comps.Attribute.AttributeType.AT_MEMO;
            else
              if (field.type == 'radio')
                this.type = UI.Comps.Attribute.AttributeType.AT_RADIO;
              else
                if (field.type == 'time')
                  this.type = UI.Comps.Attribute.AttributeType.AT_TIME;
                else
                  this.type = UI.Comps.Attribute.AttributeType.AT_DEFAULT;
    }
  },

  _createComponents: function(options) {
    var table = UI.createTable({width: '100%', height: '100%'});
    var tr = UI.createTableElement(table, 'tr');
    var td = UI.createTableElement(tr, 'td');
    td.colSpan = 2;
    td.style.height = '1px';

    tr = UI.createTableElement(table, 'tr');
    var tds = UI.createTableElement(tr, 'td', 2);
    var caption = this._getCaption();
    var w = (caption == null) ? 0 : this.getLabelWidth(caption+':');
    this.labelWidth = w;

    this.tdCaption = tds[0];
    this.tdCaption.className = 'attributeCaption';
    this.tdCaption.innerHTML = (caption == null) ? '' : caption + ':';
    this.tdCaption.style.overflow = 'hidden';
    this.tdCaption.style.width = w + 'px';

    this.control = this._createControl(options, tds[1]);
    this.width = w + this._getControlWidth() + 2;
    this.height = this.control.height || this.height;

    tr = UI.createTableElement(table, 'tr');
    td = UI.createTableElement(tr, 'td');
    td.colSpan = 2;
    td.style.height = '1px';

    table.style.height = tds[1].style.height;
    this.container.appendChild(table);
    this.container.style.width = this.width;
  },

  _destroyComponents: function() {
    if (this.control && this.control.dispose)
      this.control.dispose();

    this.tdCaption = null;
    this.control = null;
  },

  _createControl: function(options, owner) {
    options.isFromAttribute = true;

    switch (this.type) {
      case UI.Comps.Attribute.AttributeType.AT_COMBO:
        return new UI.Comps.Combo(owner, options);
      case UI.Comps.Attribute.AttributeType.AT_CHECKBOX:
        options.caption = '';
        return new UI.Comps.CheckBox(owner, options);
      case UI.Comps.Attribute.AttributeType.AT_DATE:
        return new UI.Comps.Date(owner, options);
      case UI.Comps.Attribute.AttributeType.AT_MEMO:
        return new UI.Comps.Memo(owner, options);
      case UI.Comps.Attribute.AttributeType.AT_RADIO:
        return new UI.Comps.Radio(owner, options);
      case UI.Comps.Attribute.AttributeType.AT_TIME:
        return new UI.Comps.Time(owner, options);
      default:
        return new UI.Comps.Edit(owner, options);
    }
  },

  _getControlWidth: function() {
    return this.control.width;
  },

  _getCaption: function() {
    if (this.caption != '')
      return this.caption;

    var field = this.dataset ? this.dataset.findField(this.fieldname) : null;

    if (field)
      return field.title;

    return caption;
  },

  _getTextWidth: function(caption) {
    var owner = document.createElement('div');
    owner.display = 'none';

    document.body.appendChild(owner);
    var w = UI.getTextWidth(caption, owner, 'attributeCaption');
    document.body.removeChild(owner);

    return w;
  }
}


/********** lookup.js **********/


UI.Comps.Lookup = Class.create();

UI.Comps.Lookup.SubDir = 'Lookup/';
UI.Comps.Lookup.Images = ['Lookup_01.gif', 'Lookup_02.gif', 'Lookup_03.gif', 'Lookup_04.gif'];

UI.Comps.Lookup.LookupType = {
  LT_LINE  : 0,
  LT_COLUMN: 1
};

UI.Comps.Lookup.prototype = UI.extend(UI.Comps.Attribute, {

  isLookup: true,
  lookupType: UI.Comps.Lookup.LookupType.LT_COLUMN,
  fieldname: '',
  family: '',
  controls: null,
  buttonWidth: 0,
  btnClear: null,
  btnFind: null,
  enable: true,
  manager: null,
  column: 0,
  idObjLookup: -1,
  atribRet: 'ID',
  vsLkp: '',
  famLkp: '',
  idBrw: '',
  afterCheck: null,
  multi: false,
  
  onSelect: null,
  onDeselect: null,
  onBlur: null,

  initialize: function(container, options) {
    if (options) {
      if (typeof options.lkpType == 'number')
        this.lookupType = options.lkpType;
      else
        if ((typeof options.lkpType == 'string') && (options.lkpType == 'line'))
          this.lookupType = UI.Comps.Lookup.LookupType.LT_LINE;

      if (typeof options.family == 'string')
        this.family = options.family;

      if (typeof options.vsLkp == 'string')
        this.vsLkp = options.vsLkp;

      if (typeof options.famLkp == 'string')
        this.famLkp = options.famLkp;

      if (typeof options.idBrw == 'string')
        this.idBrw = options.idBrw;

      if (typeof options.fieldname == 'string')
        this.fieldname = options.fieldname;

      if (typeof options.atribRet == 'string')
        this.atribRet = options.atribRet;

      if (typeof options.multi == 'boolean')
        this.multi = options.multi;
    }

    this.editingLookup = false;
    this.timeoutBlur = null;
    this.data = [];
    this.selectedData = [];
    this.controls = [];
    this.checking = false;
    this.changingIdf = false;

    this.superclass.initialize.call(this, container, options);
    this._updateEnable();

    for (var i = 0; i < this.controls.length; i++) {
      var ctrl = this._getControl(i);

      this.data[i] = ctrl.value;
      this.selectedData[i] = ctrl.value;
      ctrl.addKeyDownListener(this, this._onKeyDown);
    }

    this.onSelect = new UI.Comps.Listener();
    this.onDeselect = new UI.Comps.Listener();
    this.onBlur = new UI.Comps.Listener();

    if (this.multi)
      this._updateFieldsValue();
  },

  dispose: function() {
    this.onBlur.dispose();
    this.onBlur = null;
    this.onSelect.dispose();
    this.onSelect = null;
    this.onDeselect.dispose();
    this.onDeselect = null;

    if (this.timeoutBlur) {
      clearTimeout(this.timeoutBlur);
      this.timeoutBlur = null;
    }

    this.manager = null;

    this.btnClear = null;
    this.btnFind = null;

    this.superclass.dispose.call(this);
  },

  setDataset: function(dataset) {
    if (this.dataset != dataset) {
      if (this.dataset) {
        this.dataset.removeFieldChangeListener(this);
        this.dataset.removeAfterScrollListener(this);
      }

      this.superclass.setDataset.call(this, dataset);

      if (dataset) {
        var field = dataset.findField(this.fieldname);
        if (field)
          dataset.addFieldChangeListener(this, this._onFieldChange);

        dataset.addAfterScrollListener(this, this._onAfterScroll);
        this._updateEnable();
      }
    }
  },

  addSelectListener: function(obj, event) {
    this.onSelect.addListener(obj, event);
  },

  removeSelectListener: function(obj) {
    this.onSelect.removeListener(obj);
  },

  addDeselectListener: function(obj, event) {
    this.onDeselect.addListener(obj, event);
  },

  removeDeselectListener: function(obj) {
    this.onDeselect.removeListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).addKeyDownListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).removeKeyDownListener(obj);
  },

  addKeyPressListener: function(obj, event) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).addKeyPressListener(obj, event);
  },

  removeKeyPressListener: function(obj) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).removeKeyPressListener(obj);
  },

  addBlurListener: function(obj, event) {
    this.onBlur.addListener(obj, event);
  },

  removeBlurListener: function(obj) {
    this.onBlur.removeListener(obj);
  },

  confirm: function(func) {
    this.resolveLookup(func, true, true);
  },

  cancel: function() {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).cancel();
  },

  focus: function() {
    if (this.controls.length > 0)
      this._getControl(0).focus();
  },

  getValue: function() {
    return this._getControl(0).value;
  },

  setValue: function(value) {
    // ?
  },

  focused: function() {
    for (var i = 0; i < this.controls.length; i++)
      if (this._getControl(i).focused)
        return true;

    return false;
  },

  addSubmitListener: function(obj, event) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).addSubmitListener(obj, event);
  },

  removeSubmitListener: function(obj, event) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).removeSubmitListener(obj, event);
  },

  addChangeTextListener: function(obj, event) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).addChangeTextListener(obj, event);
  },

  removeChangeTextListener: function(obj) {
    for (var i = 0; i < this.controls.length; i++)
      this._getControl(i).removeChangeTextListener(obj);
  },

  resolveLookup: function(func, clrBlurTmOut, force) {
    if (clrBlurTmOut)
      this.timeoutBlur = null;

    var editing = false;

    for (var i = 0; i < this.controls.length; i++)
      if (this._getControl(i).focused) {
        editing = true;
        break;
      }

    if (!editing || force) {
      this.editingLookup = false;
      this._closeLookup(func);
    } else {
      if (typeof func == 'function')
        func();

      if (typeof this.afterCheck == 'function') {
        var after = this.afterCheck;
        this.afterCheck = null;
        after();
      }
    }
  },

  resolveLookupById: function(id) {
    this._checkLookup(false, undefined, id);
  },

  setFixedEnabled: function(value) {
    if (this.fixedEnabled != value) {
      this.fixedEnabled = value;

      if (this.controls)
        for (var i = 0; i < this.controls.length; i++)
          this._getControl(i).setFixedEnabled(value);

      this._updateEnable();
    }
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;
      this._updateEnable();
    }
  },

  _onFieldChange: function(field, oldvalue, newvalue) {
    if (field.name == this.fieldname)
      if (newvalue == null) {
        for (var i = 0; i < this.controls.length; i++)
          this._getControl(i)._setEditValue(null);
      }

//    if (!this.dataset.updating && !this.changingIdf && (field.name == this.fieldname))
//      this.resolveLookupById(newvalue);

    for (var i = 0; i < this.controls.length; i++)
      if (field.name == this._getControl(i).fieldName) {
        this._getControl(i)._setEditValue(field.getDisplayValue());

        if (this.data && (this.data.length > 0))
          this.data[i] = this._getControl(i).value;

        break;
      }
  },

  _onAfterScroll: function() {
    this._updateEnable();
    this._updateFieldsValue();
  },

  _updateEnable: function() {
    var enable = !this.dataset;

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname);
      enable = (this.dataset.recno >= 0) && field && field.enable;
    }

    this.enable = (enable == null) ? false : enable && this.fixedEnabled && this.enabled;

    if (this.controls)
      for (var i = 0; i < this.controls.length; i++) {
        this._getControl(i).setEnabled(this.enable && !this.multi);

        if (this.multi) {
          var btns = this._getControl(i).buttons;

          for (var n = 0; n < btns.length; n++)
            btns[n].setEnabled(this.enable);
        }
      }

    if (this.btnClear && this.btnFind) {
      this.btnClear.setEnabled(this.enable);
      this.btnFind.setEnabled(this.enable);
    }
  },

  _updateFieldsValue: function() {
    if (this.dataset)
      for (var i = 0; i < this.controls.length; i++) {
        var control = this._getControl(i);
        var field = this.dataset.findField(control.fieldName);

        if (field) {
          var value = field.getDisplayValue();

          if (this.multi && value && (value != ''))
            control._setEditValue(UI.descLkpSelected);
          else
            control._setEditValue(value);
        }
      }
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.Lookup, index);
  },

  _createControl: function(options, owner) {
    options.ds = this.dataset;

    if (this.lookupType == UI.Comps.Lookup.LookupType.LT_LINE) {
      if (options.attrs && (options.attrs.length == 1))
        options.fieldname = options.attrs[0];

      var control = this.superclass._createControl.call(this, options, owner);
      control.setDataSet(null);

      control._addButton(this._getImage(0), this._getImage(1), UI.getLanguageTag('clear'), this._onClearClick.bind(this));
      control._addButton(this._getImage(2), this._getImage(3), UI.getLanguageTag('find'), this._onFindClick.bind(this));

      control.addFocusListener(this, this._onAttributeFocus);
      control.addBlurListener(this, this._onAttributeBlur);

      this.controls.push(control);
    } else {
      this.tdCaption.vAlign = 'top';

      var labelWidth = 0;
      var funcTest = function(att) {
        return true;
//        return (this.fieldname == att.mstAt);
      }.bind(this);

      for (var i = 0; i < options.attrs.length; i++)
        if (this.dataset && (typeof options.attrs[i] == 'string')) {
          var field = this.dataset.findField(options.attrs[i], funcTest);

          if (field)
            labelWidth = Math.max(this._getTextWidth(field.title+':') + 4, labelWidth);
        }

      options.labelWidth = labelWidth;

      var control = UI.createTable({width: '100%', height: '100%'});
      var tr = UI.createTableElement(control, 'tr');
      var tdsButton = UI.createTableElement(tr, 'td', 2);

      var table = UI.createTable({width: '100%', height: '100%'});
      tdsButton[0].appendChild(table);
      var trs = UI.createTableElement(table, 'tr', options.attrs.length);
      var height = 4;

      for (var i = 0; i < options.attrs.length; i++) {
        var tds = UI.createTableElement(trs[i], 'td', 2);
        var attr = options.attrs[i];
        tds[0].style.width = '1px';

        if (typeof attr == 'string') {
          options.fieldname = attr;
          options.mstAt = this.fieldname;
          options.caption = '';
          attr = new UI.Comps.Attribute(null, options, true);
          attr.setDataset(null);
        }

        if (typeof attr == 'object') {
          attr._addFocusListener(this, this._onAttributeFocus);
          attr._addBlurListener(this, this._onAttributeBlur);

          height += attr.height + 2;
          tds[1].appendChild(attr.container);
          this.controls.push(attr);
        }
      }

      this.buttonWidth = 14;
      tdsButton[1].style.width = this.buttonWidth + 'px';
      tdsButton[1].vAlign = 'top';
      this._createButtons(tdsButton[1]);
      this.height = height;

      owner.style.height = height + 'px';
      owner.appendChild(control);
      table.className = 'lookup';
    }

    return control;
  },

  _destroyComponents: function() {
    if (this.timeoutBlur) {
      clearTimeout(this.timeoutBlur);
      this.timeoutBlur = null;
    }

    for (var i = 0; i < this.controls.length; i++) {
      var ctrl = this._getControl(i);
      ctrl.removeFocusListener(this);
      ctrl.removeBlurListener(this);
      ctrl.dispose();

      this.controls[i] = null;
      ctrl = null;
    }

    this.controls.length = 0;
    this.controls = null;

    this.superclass._destroyComponents.call();
  },

  _createButtons: function(owner) {
    var div = document.createElement('div');
    owner.appendChild(div);
    div.className = 'lookupButtons';

    var options = {
      image: this._getImage(0),
      imageDisabled: this._getImage(1),
      width: 13,
      height: 9,
      caption: '',
      tooltip: UI.getLanguageTag('clear'),
      parent: div
    }
    this.btnClear = new UI.Comps.Button(null, options);
    this.btnClear.setHeight(11);
    this.btnClear.hideBorder();
    this.btnClear.onClick = this._onClearClick.bind(this);

    var options = {
      image: this._getImage(2),
      imageDisabled: this._getImage(3),
      width: 13,
      height: 9,
      caption: '',
      tooltip: UI.getLanguageTag('find'),
      parent: div
    }
    this.btnFind = new UI.Comps.Button(null, options);
    this.btnFind.setHeight(11);
    this.btnFind.hideBorder();
    this.btnFind.onClick = this._onFindClick.bind(this);
  },

  _onAttributeFocus: function(sender) {
    if (this.lookupType == UI.Comps.Lookup.LookupType.LT_COLUMN) {
      if (this.timeoutBlur) {
        clearTimeout(this.timeoutBlur);
        this.timeoutBlur = null;
      }

      if (!this.editingLookup) {
        this.editingLookup = true;
        this._editLookup();
      }
    } else
      this._editLookup();
  },

  _onAttributeBlur: function(sender, func) {
    if (this.enable) {
      var f = function() {
        var f2 = function() {
          if (func)
            func();

          var f3 = function() {
            var ok = !this.btnClear || !this.btnClear.isPressed();
            ok = ok && (!this.btnFind || !this.btnFind.isPressed());

            if (!this.checking && this.onBlur && ok && !this.focused())
              this.onBlur.call();
          }.bind(this);

          setTimeout(f3, 0);
        }.bind(this);

        this.resolveLookup(f2, true);
      }.bind(this);

      this.timeoutBlur = setTimeout(f, 50);
    }

    if (typeof func == 'function')
      return false;
  },

  _editLookup: function() {
    this.data.length = 0;

    for (var i = 0; i < this.controls.length; i++)
      this.data[i] = this._getControl(i).value;
  },

  _closeLookup: function(func) {
    var changed = false;

    for (var i = 0; i < this.controls.length; i++) {
      var text = this._getControl(i).value;

      if (this.data[i] != text) {
        this.data[i] = text;
        changed = true;
      }
    }

    if (!UI.showingModalFrame())
      if (changed)
        this._checkLookup(false, func);
      else
        if (typeof func == 'function')
          func();
  },

  _changed: function() {
    var changed = false;

    for (var i = 0; i < this.controls.length; i++) {
      var text = this._getControl(i).value;

      if (this.data[i] != text)
        changed = true;
    }

    return changed;
  },

  _getControlWidth: function() {
    if (this.lookupType == UI.Comps.Lookup.LookupType.LT_LINE)
      return this.superclass._getControlWidth.call(this);

    var maxCtrlWidth = 0;

    for (var i = 0; i < this.controls.length; i++)
      maxCtrlWidth = Math.max(this.controls[i].width, maxCtrlWidth);

    return maxCtrlWidth + this.buttonWidth + 2;
  },

  _getControl: function(n) {
    if (this.lookupType == UI.Comps.Lookup.LookupType.LT_COLUMN)
      return this.controls ? this.controls[n].control : null;
    else
      return this.control;
  },

  _checkLookup: function(showLookup, func, byId) {
    var xmldoc = null;

    if (byId != undefined) {
      xmldoc = UI.parseXML(UI.xmlHeader + '<flds/>');
      xmldoc.documentElement.setAttribute(this.fieldname, byId);
    } else
      for (var i = 0; i < this.data.length; i++)
        if (this.data[i] != '') {
          var ctrl = this._getControl(i);

          if ((ctrl.editType == UI.Comps.Edit.EditType.ET_NUMBER) && (parseFloat(this.data[i]) == 0))
            continue;

          if (xmldoc == null)
            xmldoc = UI.parseXML(UI.xmlHeader + '<flds/>');

          xmldoc.documentElement.setAttribute(ctrl.fieldName, this.data[i]);
        }

    if (showLookup || (xmldoc != null)) {
      UI.disableAttributes();
      this.checking = UI.random();
      var params = 'maxrec=2&family=' + this.family + '&objId=' + this.idObjLookup + 
        '&target=' + this.dataset.id + '&field=' + this.fieldname + 
        '&vsLkp=' + this.vsLkp + '&famLkp=' + this.famLkp + '&idBrw=' + this.idBrw + '&_uid=' + this.checking;

      var url = UI.dirBase + UI.pgLookup + '?' + params;
      var opt = {
        method: 'post',
        postBody: xmldoc,
        onException: function() {
          UI.enableAttributes();
          this.checking = false;
          return true;
        }.bind(this),

        onFailure: function() {
          UI.enableAttributes();
          this.checking = false;
          return true;
        }.bind(this)
      };

      UI.registerAjaxRequest(url, this._onLookupChecked.bind(this, this.checking, showLookup, func), opt);
    } else
      this._onClearClick();
  },

  _onClearClick: function() {
    var funcTest = function(att) {
      return true;
//      return (this.fieldname == att.mstAt);
    }.bind(this);

    for (var i = 0; i < this.controls.length; i++) {
      var control = this._getControl(i);
      var field = this.dataset.findField(control.fieldName, funcTest);

      control.clear();
      this.data[i] = control.value;
      this.selectedData[i] = control.value;

      if (field)
        field.setValue(null);
    }

    this.checking = false;

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname, funcTest);

      if (field) {
        var changed = (field.getValue() != null);
        this.changingIdf = true;
        field.setValue(null);
        this.changingIdf = false;

        if (changed)
          this._doClear();
      }
    }

//    this.focus();
  },

  _onFindClick: function() {
    for (var i = 0; i < this.data.length; i++)
      this.data[i] = this._getControl(i).edit.value;

    this._checkLookup(true);
  },

  _onLookupChecked: function(chkID, showLookup, func, xml) {
    if (chkID != this.checking)
      return;

    if (xml != null) {
      var obj = UI.parseXML(xml);
      var doc = obj.documentElement;
      this.idObjLookup = doc.getAttribute('objId') || this.idObjLookup;

      var elements = doc.getElementsByTagName('row');
      showLookup = ((typeof showLookup == 'boolean') && (showLookup == true)) || (elements.length > 1) || this.multi;

      if ((this.atribRet == 'ID') && (elements.length > 0) && elements[0].getAttribute('_key'))
        this.atribRet = elements[0].getAttribute('_key');

      if (elements.length == 0)
        this._onClearClick();

      if (!this.multi && !showLookup && (elements.length == 1)) {
        this._onClearClick();

        this.dataset.updating = true;
        try {
          var funcTest = function(att) {
            return true;
//            return (this.fieldname == att.mstAt);
          }.bind(this);

          for (var i = 0; i < this.controls.length; i++) {
            var control = this._getControl(i);
            var value = elements[0].getAttribute(control.fieldName);
            var field = this.dataset.findField(control.fieldName, funcTest);

            if (value != null) {
              control._setText(value);
              this.data[i] = control.value;
              this.selectedData[i] = control.value;
              field.setValue(value);
            }
          }
        } finally {
          this.dataset.updating = false;
        }

        var fieldname = this.atribRet;

        if ((this.atribRet == 'ID') && elements[0].getAttribute('_key'))
          fieldname = elements[0].getAttribute('_key');

        this.changingIdf = true;
        this.dataset.findField(this.fieldname).setValue(elements[0].getAttribute(fieldname));
        this.changingIdf = false;
        this._doSelect();
      }

      if (showLookup || (elements.length > 1)) {
        var atr = (this.atribRet == 'ID') ? this.fieldname : this.atribRet;
        var field = this.dataset.findField(this.fieldname);

        var _url = UI.dirBase + UI.pgLookupWindow + '?family=' + this.family + '&objID=' + this.idObjLookup;
        _url += '&attr=' + atr;
        _url += '&_uid=' + UI.random();

        if (field && this.multi) {
          var ids = field.getValue();

          _url += '&multi=true';

          if (ids)
            _url += '&vlrSel=' + ids;
        }

        var options = {
          title: UI.getLanguageTag('search'),
          url: _url,
          onClose: this._onCloseLookup.bind(this)
        };

        UI.showModalFrame(options);
      }

      if ((typeof func == 'function') && (elements.length < 2))
        func();

      elements = null;
      doc = null;
      obj = null;
    }
    UI.enableAttributes();
    this.checking = false;

    if (this.afterCheck) {
      this.afterCheck();
      this.afterCheck = null;
    }
  },

  _onCloseLookup: function(grid, modalResult, dataset) {
    switch (modalResult) {
      case UI.Comps.ModalFrame.ModalResult.MR_OK:
        dataset.updating = true;
        try {
          var funcTest = function(att) {
            return true;
//            return (this.fieldname == att.mstAt);
          }.bind(this);

          for (var i = 0; i < this.controls.length; i++) {
            var control = this._getControl(i);

            if (!grid.multi) {
              var field = dataset.findField(control.fieldName);

              if (field) {
                control._setText(field.getDisplayValue());
                this.data[i] = control.value;
                this.selectedData[i] = control.value;

                var field2 = this.dataset.findField(control.fieldName, funcTest);

                if (field2)
                  field2.setValue(field.getValue());
              }
            }
          }
        } finally {
          dataset.updating = false;
        }

        var field = (this.atribRet == 'ID') ? dataset.findKeyField() : dataset.findField(this.atribRet);
        var field2 = (this.dataset) ? this.dataset.findField(this.fieldname) : null;

        var value = field ? field.getValue() : null;

        if (grid.multi)
          if (grid.selectedRows.length > 0) {
            var ids = '';

            for (var i = 0; i < grid.selectedRows.length; i++)
              ids += grid.selectedRows[i] + ',';

            value = ids.substring(0, ids.length-1);
          } else
            if (dataset.recno == -1)
              value = null;

        if (field && field2) {
          this.changingIdf = true;
          field2.setValue(value);
          this.changingIdf = false;
        }

        if (this.multi)
          this._updateFieldsValue();

        this._doSelect();

        break;
      case UI.Comps.ModalFrame.ModalResult.MR_CANCEL:
        for (var i = 0; i < this.controls.length; i++) {
          var control = this._getControl(i);

          if (this.multi) {
            var field = (this.dataset) ? this.dataset.findField(this.fieldname) : null;
            var value = field ? field.getValue() : null;

            if (value && (value != ''))
              control._setText(UI.descLkpSelected);
            else
              control._setText('');
          } else
            control._setText(this.selectedData[i]);

          this.data[i] = control.value;
        }

        break;
    }

    if (this.controls.length > 0)
      setTimeout((function() { if (this.controls) this._getControl(0).focus(); }).bind(this), 1);

    return true;
  },

  _doSelect: function() {
    var field = (this.atribRet == 'ID') ? this.dataset.findKeyField() : this.dataset.findField(this.atribRet);

    if (field) {
      this.onSelect.call(this, field.getValue(), this.dataset);

      if (eval('document.evSelect_' + this.fieldname) != null)
        eval('document.evSelect_' + this.fieldname+'();');
    }
  },

  _doClear: function() {
    this.onDeselect.call(this);

    if (eval('document.evClear_' + this.fieldname) != null)
      eval('document.evClear_' + this.fieldname+'();');
  },

  _onKeyDown: function(keyCode, pars) {
    if (keyCode == UI.key_search) {
      if (!this.enable)
        return;

      if (pars.ctrl) {
        this._onClearClick();

        if (this.controls.length > 0)
          setTimeout((function() { this._getControl(0).focus();}).bind(this), 1);
      } else
        this._onFindClick();
    }
  }
});


/********** checkbox.js **********/


UI.Comps.CheckBox = Class.create();

UI.Comps.CheckBox.SubDir = 'CheckBox/';
UI.Comps.CheckBox.Images = ['CheckBox_01.gif', 'CheckBox_02.gif', 'CheckBox_03.gif'];

UI.Comps.CheckBox.prototype = {

  container: null,
  dataset: null,
  fieldname: '',
  caption: null,
  checked: false,
  enabled: true,
  fixedEnabled: true,
  focused: false,
  width: 0,
  height: 15,

  onChange: null,
  onSubmit: null,
  onChangeText: null,
  onKeyDown: null,

  initialize: function(container, options) {
    this.container = (typeof container == 'string') ? $(container) : container;

    if (!this.container) {
      this._containerCreated = true;
      this.container = document.createElement('div');
    }

    this.btn = null;
    this.img = null;
    this.tdCaption = null;
    this._timeout = null;
    this._oldValue = null;
    
    this.onChange = new UI.Comps.Listener();
    this.onSubmit = new UI.Comps.Listener();
    this.onChangeText = new UI.Comps.Listener();
    this.onKeyDown = new UI.Comps.Listener();

    if (options) {
      if (typeof options.ds == 'object')
        this.setDataset(options.ds);

      if (typeof options.fieldname == 'string')
        this.fieldname = options.fieldname;

      if (typeof options.caption == 'string')
        this.caption = options.caption;

      if (typeof options.checked == 'boolean')
        this.checked = options.checked;

      if (typeof options.enabled == 'boolean')
        this.enabled = options.enabled;
    }

    if ((this.caption == null) && this.dataset) {
      var field = this.dataset.findField(this.fieldname);

      if (field) {
        this.caption = field.title;
        this._oldValue = field.getValue();
      }
    }

    this.caption = this.caption || '';
    this._createControl();
  },

  dispose: function() {
    this.setDataset(null);

    if (this._containerCreated && this.container.parentNode)
      this.container.parentNode.removeChild(this.container);

    this.onChangeText.dispose();
    this.onChangeText = null;
    this.onSubmit.dispose();
    this.onSubmit = null;
    this.onChange.dispose();
    this.onChange = null;
    this.onKeyDown.dispose();
    this.onKeyDown = null;

    this.tdCaption = null;
    this.btn = null;
    this.img = null;
    this.container = null;
  },

  setDataset: function(dataset) {
    if (this.dataset != dataset) {
      if (this.dataset) {
        this.dataset.removeAfterScrollListener(this);
        this.dataset.removeFieldChangeListener(this);
      }

      this.dataset = dataset;

      if (dataset) {
        dataset.addAfterScrollListener(this, this._onAfterScroll);
        dataset.addFieldChangeListener(this, this._onFieldChange);

        if (this.img)
          this._update();
      }
    }
  },

  confirm: function(func) {
    var field = this.dataset && this.dataset.findField(this.fieldname);

    if (field)
      field.setValue(this.checked);
  },

  cancel: function() {
    var field = this.dataset && this.dataset.findField(this.fieldname);

    if (field)
      field.setValue(this._oldValue);
  },

  focus: function() {
    this.btn.focus();
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;

      this.tdCaption.className = 'chkFont ' + (this._getEnabled() ? 'chkEnabled' : 'chkDisabled');
      this._update();
    }
  },

  setFixedEnabled: function(value) {
    if (this.fixedEnabled != value) {
      this.fixedEnabled = value;
      this._update();
    }
  },

  addChangeListener: function(obj, event) {
    this.onChange.addListener(obj, event);
  },

  removeChangeListener: function(obj) {
    this.onChange.removeListener(obj);
  },

  addSubmitListener: function(obj, event) {
    this.onSubmit.addListener(obj, event);
  },

  removeSubmitListener: function(obj) {
    this.onSubmit.removeListener(obj);
  },

  addChangeTextListener: function(obj, event) {
    this.onChangeText.addListener(obj, event);
  },

  removeChangeTextListener: function(obj) {
    this.onChangeText.removeListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    this.onKeyDown.addListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    this.onKeyDown.removeListener(obj);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.CheckBox, index);
  },

  _getTextWidth: function(caption) {
    var owner = document.createElement('div');
    owner.display = 'none';

    document.body.appendChild(owner);
    var w = UI.getTextWidth(caption, owner, 'chkFont');
    document.body.removeChild(owner);

    return w;
  },

  _createControl: function() {
    while (this.container.childNodes.length > 0)
      this.container.removeChild(this.container.childNodes[0]);

    var table = UI.createTable({width: '100%'});
    var tr = UI.createTableElement(table, 'tr');
    var tds = UI.createTableElement(tr, 'td', 2);

    if (this.caption != '')
      table.style.height = '100%';

    tds[0].style.width = '15px';
    UI.disableSelection(tds[0]);
    UI.disableSelection(tds[1]);

    this.img = document.createElement('img');
    this.img.src = this._getImage(this.checked ? (this.enabled ? 1 : 2) : 0);
    this.img.onclick = this._onclick.bind(this);
    UI.disableSelection(this.img);
    tds[0].appendChild(this.img);

    this.tdCaption = tds[1];
    this.tdCaption.className = 'chkFont ' + (this._getEnabled() ? 'chkEnabled' : 'chkDisabled');
    this.tdCaption.innerHTML = this.caption;
    this.tdCaption.style.display = (this.caption == '') ? 'none' : UI.defaultDisplay;
    this.tdCaption.onclick = this._onclick.bind(this);

    this.width = 15 + this._getTextWidth(this.caption);

    this.container.style.width = this.width;
    this.container.appendChild(table);

    this.btn = document.createElement('input');
    this.btn.type = 'button';
    this.btn.style.position = 'absolute';
    this.btn.style.top = -1000;
    this.btn.onkeydown = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._onkeydown(keyCode, window.event || evt);
    }.bind(this);
    this.btn.onfocus = this._onfocus.bind(this);
    this.btn.onblur = this._onblur.bind(this);
    this.container.appendChild(this.btn);

    this._update();
  },

  _onclick: function() {
    if (this.enabled) {
      var field = null;

      if (this.dataset) {
        field = this.dataset.findField(this.fieldname);

        if ((this.dataset.recno < 0) || !field || !field.enable)
          return;
      }

      this.checked = !this.checked;

      if (field)
        field.setValue(this.checked);

      this._update();
      this.onChange.call(this);
      this.onChangeText.call(this);

      if (this._timeout)
        clearTimeout(this._timeout);
      this.btn.focus();
    }
  },

  _onfocus: function() {
    this._oldValue = this.checked;

    this.focused = true;
    this.tdCaption.className = 'chkFont chkFocused ' + (this._getEnabled() ? 'chkEnabled' : 'chkDisabled');
  },

  _onblur: function() {
    var func = function() {
      this.focused = false;
      this.tdCaption.className = 'chkFont ' + (this._getEnabled() ? 'chkEnabled' : 'chkDisabled');
    }

    this._timeout = setTimeout(func.bind(this), 10);
  },

  _onkeydown: function(keyCode, evt) {
    if (keyCode == 32)
      this._onclick();
    else
      if (keyCode == 13)
        this.onSubmit.call();

    this.onKeyDown.call(keyCode, evt);
  },

  _onFieldChange: function() {
    this._update();
  },

  _onAfterScroll: function() {
    this._update();
  },

  _getEnabled: function() {
    var enable = !this.dataset;

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname);
      enable = (this.dataset.recno >= 0) && field && field.enable;
    }

    return (enable == null) ? false : enable && this.fixedEnabled;
  },

  _update: function() {
    var enable = this._getEnabled();

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname);

      if ((this.dataset.recno >= 0) && field)
        this.checked = field.getValue()+'' == 'true';
    }

    this.img.src = this._getImage(this.checked ? (enable ? 1 : 2) : 0);
  }
}


/********** radio.js **********/


UI.Comps.Radio = Class.create();

UI.Comps.Radio.SubDir = 'Radio/';
UI.Comps.Radio.Images = ['Radio_01.gif', 'Radio_02.gif', 'Radio_03.gif', 'Radio_04.gif'];

UI.Comps.Radio.prototype = {

  container: null,
  dataset: null,
  fieldname: '',
  caption: null,
  value: null,
  enabled: true,
  fixedEnabled: true,
  focused: false,
  width: 0,
  height: 15,

  onChange: null,
  onSubmit: null,
  onChangeText: null,
  onKeyDown: null,

  initialize: function(container, options) {
    this.container = (typeof container == 'string') ? $(container) : container;

    if (!this.container) {
      this._containerCreated = true;
      this.container = document.createElement('div');
    }

    this.btn = null;
    this.imgs = new Array();
    this.tdCaptions = new Array();
    this._timeout = null;
    this._oldValue = null;
    
    this.onChange = new UI.Comps.Listener();
    this.onSubmit = new UI.Comps.Listener();
    this.onChangeText = new UI.Comps.Listener();
    this.onKeyDown = new UI.Comps.Listener();

    if (options) {
      if (typeof options.ds == 'object')
        this.setDataset(options.ds);

      if (typeof options.fieldname == 'string')
        this.fieldname = options.fieldname;

      if (typeof options.caption == 'string')
        this.caption = options.caption;

      if (typeof options.enabled == 'boolean')
        this.enabled = options.enabled;
    }

    if ((this.caption == null) && this.dataset) {
      var field = this.dataset.findField(this.fieldname);

      if (field) {
        this.caption = field.title;
        this._oldValue = field.getValue();
      }
    }

    this.caption = this.caption || '';
    this._createControl();
  },

  dispose: function() {
    this.setDataset(null);

    if (this._containerCreated && this.container.parentNode)
      this.container.parentNode.removeChild(this.container);

    this.onChangeText.dispose();
    this.onChangeText = null;
    this.onSubmit.dispose();
    this.onSubmit = null;
    this.onChange.dispose();
    this.onChange = null;
    this.onKeyDown.dispose();
    this.onKeyDown = null;
    
    this.tdCaptions.length = 0;
    this.tdCaptions = null;
    this.imgs.length = 0;
    this.imgs = null;
    this.btn = null;
    this.container = null;
  },

  setDataset: function(dataset) {
    if (this.dataset != dataset) {
      if (this.dataset) {
        this.dataset.removeAfterScrollListener(this);
        this.dataset.removeFieldChangeListener(this);
      }

      this.dataset = dataset;

      if (dataset) {
        dataset.addAfterScrollListener(this, this._onAfterScroll);
        dataset.addFieldChangeListener(this, this._onFieldChange);

        this._update();
      }
    }
  },

  confirm: function(func) {
    var field = this.dataset && this.dataset.findField(this.fieldname);

    if (field)
      field.setValue(this.value);
  },

  cancel: function() {
    var field = this.dataset && this.dataset.findField(this.fieldname);

    if (field)
      field.setValue(this._oldValue);
  },

  focus: function() {
    this.btn.focus();
  },

  setEnabled: function(value) {
    if (this.enabled != value) {
      this.enabled = value;

      for (var i = 0; i < this.tdCaptions.length; i++)
        this.tdCaptions[i].className = 'radFont ' + (this._getEnabled() ? 'radEnabled' : 'radDisabled');

      this._updateFocused();
      this._update();
    }
  },

  setFixedEnabled: function(value) {
    if (this.fixedEnabled != value) {
      this.fixedEnabled = value;
      this._updateFocused();
      this._update();
    }
  },

  addChangeListener: function(obj, event) {
    this.onChange.addListener(obj, event);
  },

  removeChangeListener: function(obj) {
    this.onChange.removeListener(obj);
  },

  addSubmitListener: function(obj, event) {
    this.onSubmit.addListener(obj, event);
  },

  removeSubmitListener: function(obj) {
    this.onSubmit.removeListener(obj);
  },

  addChangeTextListener: function(obj, event) {
    this.onChangeText.addListener(obj, event);
  },

  removeChangeTextListener: function(obj) {
    this.onChangeText.removeListener(obj);
  },

  addKeyDownListener: function(obj, event) {
    this.onKeyDown.addListener(obj, event);
  },

  removeKeyDownListener: function(obj) {
    this.onKeyDown.removeListener(obj);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.Radio, index);
  },

  _getTextWidth: function(caption) {
    var owner = document.createElement('div');
    owner.display = 'none';

    document.body.appendChild(owner);
    var w = UI.getTextWidth(caption, owner, 'radFont');
    document.body.removeChild(owner);

    return w;
  },

  _createControl: function() {
    while (this.container.childNodes.length > 0)
      this.container.removeChild(this.container.childNodes[0]);

    var field = this.dataset && this.dataset.findField(this.fieldname);
    var mask = (field ? field.mask : ' ') || ' ';

    var table = UI.createTable({width: '100%'});
    var s = '';
    var n = 0;
    var maxWidth = 0;
    
    while (mask.length > 0) {
      if (mask.indexOf(';') > -1) {
        s = mask.substring(0, mask.indexOf(';'));
        mask = mask.substring(s.length+1, mask.length);
      } else {
        s = mask;
        mask = '';
      }
      
      var key = s;
      var value = s;
      
      if (key.indexOf('=') > -1) {
        value = key.substring(key.indexOf('=')+1);
        key = key.substring(0, key.indexOf('='));
      }
      
      var tr = UI.createTableElement(table, 'tr');
      var tds = UI.createTableElement(tr, 'td', 2);

      if (this.caption != '')
        table.style.height = '100%';

      tds[0].style.width = '15px';
      UI.disableSelection(tds[0]);
      UI.disableSelection(tds[1]);

      this.imgs[n] = document.createElement('img');
      this.imgs[n].key = key;
      this.imgs[n].value = value;
      this.imgs[n].src = this._getImage(this.value == key ? (this.enabled ? 1 : 3) : (this.enabled ? 0 : 2));
      this.imgs[n].onclick = this._onclick.bind(this, this.imgs[n]);
      UI.disableSelection(this.imgs[n]);
      tds[0].appendChild(this.imgs[n]);

      this.tdCaptions[n] = tds[1];
      this.tdCaptions[n].key = key;
      this.tdCaptions[n].value = value;
      this.tdCaptions[n].className = 'radFont ' + (this._getEnabled() ? 'radEnabled' : 'radDisabled');
      this.tdCaptions[n].innerHTML = '&nbsp;' + value;
      this.tdCaptions[n].style.display = (value == '') ? 'none' : UI.defaultDisplay;
      this.tdCaptions[n].onclick = this._onclick.bind(this, this.tdCaptions[n]);
      
      maxWidth = Math.max(maxWidth, this._getTextWidth(this.tdCaptions[n].innerHTML, 'radFont'));
      n++;
    }
    
    this.width = 15 + maxWidth;

    this.container.style.width = this.width;
    this.container.appendChild(table);

    this.btn = document.createElement('input');
    this.btn.type = 'button';
    this.btn.style.position = 'absolute';
    this.btn.style.top = -1000;
    this.btn.onkeydown = function(evt) {
      var keyCode = window.event ? window.event.keyCode : evt.charCode ? evt.charCode : evt.which;
      return this._onkeydown(keyCode, window.event || evt);
    }.bind(this);
    this.btn.onfocus = this._onfocus.bind(this);
    this.btn.onblur = this._onblur.bind(this);
    this.container.appendChild(this.btn);

    this._update();
  },

  _setFieldValue: function(value) {
    var field = null;

    if (this.dataset) {
      field = this.dataset.findField(this.fieldname);

      if ((this.dataset.recno < 0) || !field || !field.enable)
        return;
    }

    if (this.value != value) {
      this.value = value;

      if (field)
        field.setValue(this.value);
    }
  },

  _onclick: function(obj) {
    if (this.enabled) {
      this._setFieldValue(obj.key);
      this._updateFocused();
      this._update();
      this.onChange.call(this);
      this.onChangeText.call(this);

      if (this._timeout)
        clearTimeout(this._timeout);
      this.btn.focus();
    }
  },

  _onfocus: function() {
    this._oldValue = this.value;
    this.focused = true;
    this._updateFocused();
  },

  _onblur: function() {
    var func = function() {
      this.focused = false;
      this._updateFocused();
    }

    this._timeout = setTimeout(func.bind(this), 10);
  },
  
  _updateFocused: function() {
    for (var i = 0; i < this.tdCaptions.length; i++) {
      var focused = (this.focused && (this.value == this.tdCaptions[i].key));
      
      if (this.focused && !this.value && (i == 0))
        focused = true;

      if (focused)
        this.tdCaptions[i].className = 'radFont radFocused ' + (this._getEnabled() ? 'radEnabled' : 'radDisabled');
      else
        this.tdCaptions[i].className = 'radFont ' + (this._getEnabled() ? 'radEnabled' : 'radDisabled');
    }
  },

  _onkeydown: function(keyCode, evt) {
    if ((keyCode == 32) && !this.value)
      this._onclick(this.tdCaptions[0]);
    else
      if (keyCode == 13)
        this.onSubmit.call();
      else
        if ((keyCode == 37) || (keyCode == 38))
          this._selectPrev();
        else
          if ((keyCode == 39) || (keyCode == 40))
            this._selectNext();

    this.onKeyDown.call(keyCode, evt);
  },

  _onFieldChange: function() {
    this._update();
  },

  _onAfterScroll: function() {
    this._update();
  },

  _selectPrev: function() {
    var founded = false;
    var idx = 0;
    
    for (var i = 0; i < this.imgs.length; i++)
      if (this.imgs[i].key == this.value) {
        idx = i-1;
        break;
      }

    if (idx == -1)
      idx = this.imgs.length - 1;

    if ((idx >= 0) && (this.imgs.length > idx)) {
      this._setFieldValue(this.imgs[idx].key);
      this._updateFocused();
      this._update();
      this.onChange.call(this);
      this.onChangeText.call(this);
    }
  },

  _selectNext: function() {
    var founded = false;
    var idx = 0;
    
    for (var i = 0; i < this.imgs.length; i++)
      if (this.imgs[i].key == this.value)
        founded = true;
      else
        if (founded) {
          idx = i;
          break;
        }

    if (this.imgs.length > idx) {
      this._setFieldValue(this.imgs[idx].key);
      this._updateFocused();
      this._update();
      this.onChange.call(this);
      this.onChangeText.call(this);
    }
  },

  _getEnabled: function() {
    var enable = !this.dataset;

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname);
      enable = (this.dataset.recno >= 0) && field && field.enable;
    }

    return (enable == null) ? false : enable && this.fixedEnabled;
  },

  _update: function() {
    var enable = this._getEnabled();

    if (this.dataset) {
      var field = this.dataset.findField(this.fieldname);

      if ((this.dataset.recno >= 0) && field)
        this.value = field.getValue();
    }

    for (var i = 0; i < this.imgs.length; i++)
      this.imgs[i].src = this._getImage(this.value == this.imgs[i].key ? (enable ? 1 : 3) : (enable ? 0 : 2));
  }
}


/********** time.js **********/


UI.Comps.Time = Class.create();

UI.Comps.Time.prototype = UI.extend(UI.Comps.Edit, {

  value: '',

  initialize: function(container, options) {
    this.timeFormat = UI.timeMask.replace('hh', 99).replace('nn', '99');

    options = options || [];
    options.mask = this.timeFormat;

    this.superclass2.initialize.call(this, container, options);

    this.ignoreBlurEvent = false;
    this.timeoutblur = null;
  },

  _createControls: function() {
    var field = this.dataset ? this.dataset.findField(this.fieldName) : null;
    if (field)
      this.value = field.getDisplayValue();

    this.superclass2._createControls.call(this);
  },

  _updateEnable: function() {
    if (this.enabled && this.fixedEnabled && this.focused)
      this.focus();

    this.superclass2._updateEnable.call(this);
  },

  _setText: function(text) {
    text = this._checkTime(text);
    this.superclass2._setText.call(this, text);
  },

  _setValue: function(value) {
    this.value = value;
  },

  _checkTime: function(value) {
    if (value == '')
      return '';

    return UI.timeToStr(UI.strToTime(value));
  },

  _getPreferredWidth: function() {
    return Math.round(UI.timeMask.length * 8);
  },

  _getWidth: function() {
    return this.container.offsetWidth;
  },

  _setFieldValue: function(field, value) {
    if (!field)
      return value;

    if ((typeof value == 'string') && (value != '')) {
      var dt = UI.strToTime(value);

      if (!isNaN(dt.getHours()) && !isNaN(dt.getMinutes()))
        value = UI.timeToStr(dt, true);
    }

    return this.superclass2._setFieldValue.call(this, field, value);
  },

  _dokeydown: function(key, evt) {
    if ((key >= 48) && (key <= 57))
      if ((document.selection) && (document.activeElement == this.edit)) {
        var range = document.selection.createRange();

        if (range.text.length > 0)
          this.edit.value = '';
      }

    this.superclass2._dokeydown.call(this, key, evt);
  }
});


/********** date.js **********/


UI.Comps.Date = Class.create();

UI.Comps.Date.SubDir = 'Date/';
UI.Comps.Date.Images = ['Date_01.gif', 'Date_02.gif'];

UI.Comps.Date.prototype = UI.extend(UI.Comps.Edit, {

  popup: null,
  btnPopup: null,
  value: '',

  initialize: function(container, options) {
    this.dateFormat = UI.dateMask.replace('dd', 99).replace('mm', '99').replace('yyyy', '9999');

    options = options || [];
    options.mask = this.dateFormat;

    this.superclass2.initialize.call(this, container, options);

    this.btnPopup = this._addButton(this._getImage(0, UI.Comps.Combo), 
      this._getImage(1, UI.Comps.Combo), '', this._onButtonClick.bind(this));

    this.popup = new UI.Comps.PopupDate(this);
    this.ignoreBlurEvent = false;
    this.timeoutblur = null;
  },

  dispose: function() {
    this.btnPopup = null;

    this.superclass2.dispose.call(this);
  },

  _getImage: function(index, cls) {
    return UI.getImage(cls || UI.Comps.Date, index);
  },

  _createControls: function() {
    var field = this.dataset ? this.dataset.findField(this.fieldName) : null;
    if (field)
      this.value = field.getDisplayValue();

    this.superclass2._createControls.call(this);
  },

  _updateEnable: function() {
    if (this.enabled && this.fixedEnabled && this.focused)
      try {
        this.focus();
      } catch(e) {
      }

    this.superclass2._updateEnable.call(this);
  },

  _setText: function(text) {
    text = this._checkDate(text);
    this.superclass2._setText.call(this, text);
  },

  _setValue: function(value) {
    this.value = value;
  },

  _checkDate: function(value) {
    if (value == '')
      return '';

    return UI.dateToStr(UI.strToDate(value));
  },

  _getPreferredWidth: function() {
    return Math.round(UI.dateMask.length * 8);
  },

  _getWidth: function() {
    return this.container.offsetWidth;
  },

  _setFieldValue: function(field, value) {
    if (!field)
      return value;

    if ((typeof value == 'string') && (value != '')) {
      var dt = UI.strToDate(value);

      if (!isNaN(dt.getDate()) && !isNaN(dt.getMonth()) && !isNaN(dt.getYear()))
        value = UI.dateToStr(dt, true);
    }

    return this.superclass2._setFieldValue.call(this, field, value);
  },

  _dofocusEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    this.superclass2._dofocusEvent.call(this);
  },

  _doblurEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    if (this.ignoreBlurEvent)
      return;

    var f = function() {
      if (!this.popup.showing && this.focused)
        this.superclass2._doblurEvent.call(this);
    }

    this.timeoutblur = setTimeout(f.bind(this), 100);
  },

  _dokeypress: function(key) {
    return this.superclass2._dokeypress.call(this, key);
  },

  _dokeydown: function(key, evt) {
    if ((key >= 48) && (key <= 57))
      if ((document.selection) && (document.activeElement == this.edit)) {
        var range = document.selection.createRange();

        if (range.text.length > 0)
          this.edit.value = '';
      }

    this.superclass2._dokeydown.call(this, key, evt);

    if (evt.ctrlKey || evt.altKey)
      if ((key == 40) && !this.popup.showing)
        this._onButtonClick();
  },

  _onkeydown: function(key, evt) {
    if (this.popup.showing) {
      if (key == 27) {
        this._onButtonClick();
        this.edit.focus();
      }
    }
  },

  _onButtonClick: function() {
    if (!this.popup.showing) {
      var p = UI.getAbsolutePosition(this.container);

      this.edit.focus();
      this.popup.Show(p.x, p.y+this.container.offsetHeight, this.container.offsetWidth);
    } else
      this.popup.Close();
  }
});

UI.Comps.PopupDate = Class.create();

UI.Comps.PopupDate.prototype = UI.extend(UI.Comps.Popup, {

  date: null,

  initialize: function(date) {
    this.superclass.initialize.call(this);

    this.date = date;
    this.popup = new UI.Comps.PopupDateCalendar(this, null, '', date);
  }
});

UI.Comps.PopupDateCalendar = Class.create();

UI.Comps.PopupDateCalendar.SubDir = 'Date/';
UI.Comps.PopupDateCalendar.Images = ['Date_01.gif', 'Date_02.gif', 'Date_03.gif', 'Date_04.gif'];

UI.Comps.PopupDateCalendar.prototype = UI.extend(UI.Comps.PopupItem, {

  date: null,
  height: 100,

  initialize: function(popup, parent, caption, date) {
    this.superclass.initialize.call(this, popup, parent, caption);

    this.date = date;
    this.div = null;

    this.tdTitle = null;
    this.btnsNav = null;
    this.btnsDays = null;
  },

  dispose: function() {
    this.btnsNav = null;
    this.tdTitle = null;

    this.div = null;

    this.superclass.dispose.call(this);
  },

  _getWidth: function() {
    return 150;
  },

  _getHeight: function() {
    return 165;
  },

  _createContents: function(doc) {
    var css = doc.createElement("link");
    css.rel = "stylesheet";
    css.href = UI.arqStyles;
    css.type = "text\/css";
    doc.body.appendChild(css);

    var div = doc.createElement('div');
    div.style.width = '100%';
    div.style.height = '100%';
    div.style.overflow = 'auto';
    div.style.marginTop = '-2px';
    div.className = 'comboPopupBackground';
    this.div = div;
    this._createCalendar(doc, div);
    UI.disableSelection(div);
    div.onclick = function() {
      this.date.ignoreBlurEvent = true;
      this.btn.focus();
    }.bind(this);

    doc.body.appendChild(div);
    doc.body.className = 'comboPopupBorder';

    div.onfocus = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);

    div.onmousedown = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);
  },

  _destroyContents: function() {
    this.div.onclick = null;
    this.div = null;

    this.btnToday.dispose();
    this.btnToday = null;

    this.btnClear.dispose();
    this.btnClear = null;

    for (var i = 0; i < this.btnsNav.length; i++) {
      this.btnsNav[i].dispose();
      this.btnsNav[i] = null;
    }

    for (var i = 0; i < this.btnsDays.length; i++) {
      for (var j = 0; j < this.btnsDays[i].length; j++) {
        this.btnsDays[i][j].dispose();
        this.btnsDays[i][j] = null;
      }

      this.btnsDays[i].length = 0;
      this.btnsDays[i] = null;
    }

    this.btnsDays.length = 0;
    this.btnsDays = null;

    this.btnsNav.length = 0;
    this.btnsNav = null;
  },

  _createCalendar: function(doc, dv) {
    var table = UI.createTable({doc: doc, width: '100%', height: '100%'});
    var tr = UI.createTableElement(table, 'tr', 3, doc);

    tr[0].style.height = '15px';
    var tds = UI.createTableElement(tr[0], 'td', 5, doc);
    this._createCalendarHeader(doc, tds);

    this._createCalendarDays(doc, UI.createTableElement(tr[1], 'td', 1, doc));

    tr[2].style.height = '15px';
    this._createCalendarFooter(doc, UI.createTableElement(tr[2], 'td', 1, doc));

    dv.appendChild(table);
  },

  _createCalendarHeader: function(doc, tds) {
    var btn1 = this._createButton(tds[0], {document: doc, image: 0, action: 'back_year'});
    var btn2 = this._createButton(tds[1], {document: doc, image: 1, action: 'back_month'});
    this.tdTitle = tds[2];
    this.tdTitle.align = 'center';
    this.tdTitle.className = 'dateTitle';
    this.tdTitle.innerHTML = '&nbsp;';
    var btn3 = this._createButton(tds[3], {document: doc, image: 2, action: 'next_month'});
    var btn4 = this._createButton(tds[4], {document: doc, image: 3, action: 'next_year'});

    btn1.onClick = this._onButtonHeaderClick.bind(this, btn1);
    btn2.onClick = this._onButtonHeaderClick.bind(this, btn2);
    btn3.onClick = this._onButtonHeaderClick.bind(this, btn3);
    btn4.onClick = this._onButtonHeaderClick.bind(this, btn4);

    tds[0].style.width = '15px';
    tds[1].style.width = '15px';
    tds[2].style.width = '90px';
    tds[3].style.width = '15px';
    tds[4].style.width = '15px';

    this.btnsNav = [];
    this.btnsNav.push(btn1);
    this.btnsNav.push(btn2);
    this.btnsNav.push(btn3);
    this.btnsNav.push(btn4);
  },

  _createCalendarDays: function(doc, owner) {
    this.btnsDays = [];
    owner.colSpan = 5;

    var table = UI.createTable({doc: doc, width: '100%', height: '100%'});
    var tr = UI.createTableElement(table, 'tr', 6, doc);

    for (var i = 0; i < 6; i++) {
      this.btnsDays[i] = [];
      var tds = UI.createTableElement(tr[i], 'td', 7, doc);

      for (var j = 0; j < 7; j++) {
        var btn = this._createButton(tds[j], {document: doc, width: 20, height: 20});
        btn.onClick = this._onButtonDayClick.bind(this, btn);
        btn.action = '';

        this.btnsDays[i].push(btn);
      }
    }

    owner.appendChild(table);
  },

  _createCalendarFooter: function(doc, owner) {
    owner.colSpan = 5;

    var table = UI.createTable({doc: doc, width: '100%', height: '100%'});
    var tr = UI.createTableElement(table, 'tr', 1, doc);
    var tds = UI.createTableElement(tr, 'td', 2, doc);

    this.btnToday = this._createButton(tds[0], {document: doc, caption: '@today', width: 74, height: 18});
    this.btnToday.onClick = this._onButtonTodayClick.bind(this);

    this.btnClear = this._createButton(tds[1], {document: doc, caption: '@clear', width: 74, height: 18});
    this.btnClear.onClick = this._onButtonClearClick.bind(this);

    owner.appendChild(table);
  },

  _updateDate: function() {
    var sd = this.selectedDate;
    var dt = new Date(this.actualDate);
    dt.setDate(1);

    dt.setDate(dt.getDate() - dt.getDay());

    var y = this.actualDate.getYear() + '';
    if (y.length <= 2)
      y = '19' + UI.padl(y, 2, '0');

    this.tdTitle.innerHTML = UI.months[this.actualDate.getMonth()] + ' ' + y;

    for (var j = 0; j < 6; j++) {
      for (var i = 0; i < 7; i++) {
        var btn = this.btnsDays[j][i];
        var cl = dt.getMonth() == this.actualDate.getMonth() ? dt.getDay() == 0 ? 'red' : 'black' : '#C0C0C0';
        var same = (dt.getDate() == sd.getDate()) && (dt.getMonth() == sd.getMonth()) && (dt.getYear() == sd.getYear());

        btn.setBtnOverClass(same ? 'buttonDown' : null);
        btn.setBtnUpClass(same ? 'buttonDown' : null);
        btn.setBtnDownClass(same ? 'buttonDown' : null);

        btn.action = UI.dateToStr(dt);
        btn.setCaption(UI.padl(dt.getDate()+'', 2));
        btn.hideBorder();

        btn.setFontColor(cl);

        dt.setDate(dt.getDate() + 1);
      }
    }
  },

  _onButtonHeaderClick: function(btn) {
    this.date.ignoreBlurEvent = true;
    this.btn.focus();

    switch (btn.action) {
      case 'back_month':
        this.actualDate.setMonth(this.actualDate.getMonth()-1);
        this._updateDate();
        break;
      case 'next_month':
        this.actualDate.setMonth(this.actualDate.getMonth()+1);
        this._updateDate();
        break;
      case 'back_year':
        var y = this.actualDate.getYear();
        this.actualDate.setYear(y == 0 ? 99 : y-1);
        this._updateDate();
        break;
      case 'next_year':
        var y = this.actualDate.getYear();
        this.actualDate.setYear(y == 99 ? 2000 : y+1);
        this._updateDate();
        break;
    }
  },

  _onButtonDayClick: function(btn) {
    this.popup.Close();

    this.date._setText(btn.action);
    setTimeout((function() {this.date.focus();}).bind(this), 0);
  },

  _onButtonTodayClick: function() {
    this.popup.Close();

    this.date._setText(UI.dateToStr(new Date()));
    setTimeout((function() {this.date.focus();}).bind(this), 0);
  },

  _onButtonClearClick: function() {
    this.popup.Close();
    this.date.clear();
    setTimeout((function() {this.date.focus();}).bind(this), 0);
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.PopupDateCalendar, index);
  },

  _createButton: function(owner, options) {
    if (!options.width)
      options.width = 18;
    if (!options.height)
      options.height = 18;

    options.parent = owner;

    if (typeof options.image == 'number')
      options.image = this._getImage(options.image);

    if (typeof options.caption != 'string')
      options.caption = '';

    var btn = new UI.Comps.Button(null, options);
    btn.ignoreBlur = true;
    btn.hideBorder();

    if (typeof options.action == 'string')
      btn.action = options.action;

    if (options.onclick)
      btn.onClick = options.onclick;

    return btn;
  },

  _show: function(x, y, objWidth, objHeight) {
    this.actualDate = UI.strToDate(this.date.value, new Date());
    this.selectedDate = new Date(this.actualDate);
    this._updateDate();

    this.superclass._show.call(this, x, y, objWidth, objHeight);

    document.body.unselectable = "off";
  },

  _hide: function() {
    this.actualDate = null;
    document.body.unselectable = "on";
    this.superclass._hide.call(this);

    this.date._doblurEvent();
  },

  _onkeydown: function(key, evt) {
    this.date._onkeydown(key, evt);
  },

  _onItemClick: function(index, td) {
    this.date.ignoreBlurEvent = true;
    this.popup.Close();

    setTimeout((function() { this.date.edit.focus(); }).bind(this), 0);
    setTimeout((function() { this.date.ignoreBlurEvent = false; }).bind(this), 1);
  }
});


/********** memo.js **********/


UI.Comps.Memo = Class.create();

UI.Comps.Memo.prototype = UI.extend(UI.Comps.Edit, {

  popup: null,
  btnPopup: null,
  btnClear: null,
  value: '',

  initialize: function(container, options) {
    options = options || [];

    this.superclass2.initialize.call(this, container, options);

    this.btnClear = this._addButton(this._getImage(0, UI.Comps.Lookup),
      this._getImage(1, UI.Comps.Lookup), '', this._onClearClick.bind(this));

    this.btnPopup = this._addButton(this._getImage(0, UI.Comps.Combo),
      this._getImage(1, UI.Comps.Combo), '', this._onButtonClick.bind(this));

    this.popup = new UI.Comps.PopupMemo(this);
    this.ignoreBlurEvent = false;
    this.timeoutblur = null;
  },

  dispose: function() {
    this.btnClear = null;
    this.btnPopup = null;

    this.superclass2.dispose.call(this);
  },

  _getImage: function(index, cls) {
    return UI.getImage(cls || UI.Comps.Memo, index);
  },

  _createControls: function() {
    var field = this.dataset ? this.dataset.findField(this.fieldName) : null;
    if (field)
      this.value = field.getDisplayValue();

    this.superclass2._createControls.call(this);

    if (this.value.indexOf(UI.chr(10)) > -1)
      this.edit.value = this.value.substring(0, this.value.indexOf(UI.chr(10)));
  },

  _setEditValue: function(value) {
    if (value.indexOf(UI.chr(10)) > -1)
      value = value.substring(0, value.indexOf(UI.chr(10)));

    this.superclass2._setEditValue.call(this, value);
  },

  _setValue: function(value) {
    if (value.indexOf(UI.chr(10)) > -1)
      value = value.substring(0, value.indexOf(UI.chr(10)));

    this.value = value;
  },

  _getWidth: function() {
    return this.container.offsetWidth;
  },

  _setFieldValue: function(field, value) {
    if (!field)
      return value;

    var s = field.getDisplayValue() || '';

    if (s.indexOf(UI.chr(10)) > -1)
      value = value + s.substring(s.indexOf(UI.chr(10)));

    return this.superclass2._setFieldValue.call(this, field, value);
  },

  _dofocusEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    this.superclass2._dofocusEvent.call(this);
  },

  _doblurEvent: function() {
    if (this.timeoutblur) {
      clearTimeout(this.timeoutblur);
      this.timeoutblur = null;
    }

    if (this.ignoreBlurEvent)
      return;

    var f = function() {
      if (!this.popup.showing && this.focused)
        this.superclass2._doblurEvent.call(this);
    }

    this.timeoutblur = setTimeout(f.bind(this), 100);
  },

  _dokeypress: function(key) {
    return this.superclass2._dokeypress.call(this, key);
  },

  _dokeydown: function(key, evt) {
    this.superclass2._dokeydown.call(this, key, evt);

    if (evt.ctrlKey || evt.altKey)
      if ((key == 40) && !this.popup.showing) {
        var field = this.dataset ? this.dataset.findField(this.fieldName) : null;

        if (field) {
          var s = field.getValue() || '';

          if (s.indexOf(UI.chr(10)) > -1)
            s = this.edit.value + s.substring(s.indexOf(UI.chr(10)));
          else
            s = this.edit.value;

          field.setValue(s);
        }

        this._onButtonClick();
      }
  },

  _onkeydown: function(key, evt) {
    if (this.popup.showing) {
      if (key == 27) {
        this._onButtonClick();
        this.edit.focus();
      }
    }
  },

  _onButtonClick: function() {
    if (!this.popup.showing) {
      var p = UI.getAbsolutePosition(this.container);

      this.edit.focus();
      this.popup.Show(p.x, p.y+this.container.offsetHeight, this.container.offsetWidth);
    } else
      this.popup.Close();
  },

  _onClearClick: function() {
    var field = this.dataset ? this.dataset.findField(this.fieldName) : null;

    if (field)
      field.setValue(null);
  }
});

UI.Comps.PopupMemo = Class.create();

UI.Comps.PopupMemo.prototype = UI.extend(UI.Comps.Popup, {

  memo: null,

  initialize: function(memo) {
    this.memo = memo;
    this.superclass.initialize.call(this);

    this.popup = new UI.Comps.PopupMemoItem(this, null, '', memo);
  }
});

UI.Comps.PopupMemoItem = Class.create();

UI.Comps.PopupMemoItem.SubDir = 'Memo/';
UI.Comps.PopupMemoItem.Images = ['Memo_01.gif'];

UI.Comps.PopupMemoItem.prototype = UI.extend(UI.Comps.PopupItem, {

  memo: null,
  edtMemo: null,
  height: 100,

  initialize: function(popup, parent, caption, memo) {
    this.superclass.initialize.call(this, popup, parent, caption);

    this.memo = memo;
    this.div = null;
    this.focusing = false;
  },

  dispose: function() {
    this.div = null;
    this.superclass.dispose.call(this);
  },

  _getWidth: function() {
    return Math.max(this.memo.width, 200);
  },

  _getHeight: function() {
    return 140;
  },

  _createContents: function(doc) {
    var css = doc.createElement("link");
    css.rel = "stylesheet";
    css.href = UI.arqStyles;
    css.type = "text\/css";
    doc.body.appendChild(css);

    var div = doc.createElement('div');
    div.style.width = '100%';
    div.style.height = '100%';
    div.style.overflow = 'auto';
    div.style.marginTop = '-2px';
    div.className = 'comboPopupBackground';
    this.div = div;
    this._createMemo(doc, div);
    UI.disableSelection(div);

    doc.body.appendChild(div);
    doc.body.className = 'comboPopupBorder';

    div.onfocus = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);

    div.onmousedown = function() {
      if (this.timeout) {
        clearTimeout(this.timeout);
        this.btn.focus();
      }
    }.bind(this);
  },

  _destroyContents: function() {
    this.edtMemo = null;

    this.div.onclick = null;
    this.div = null;
  },

  _createMemo: function(doc, dv) {
    var table = UI.createTable({doc: doc, width: '100%', height: '100%'});
    var tr = UI.createTableElement(table, 'tr', 1, doc);
    var td = UI.createTableElement(tr, 'td', 1, doc);

    var edtMemo = doc.createElement('textarea');
    this.edtMemo = edtMemo;
    edtMemo.className = 'memoBackground';
    edtMemo.style.width = '100%';
    edtMemo.style.height = '100%';
    edtMemo.style.border = '0';

    edtMemo.onblur = function() {
      var field = this.memo.dataset ? this.memo.dataset.findField(this.memo.fieldName) : null;

      if (field)
        field.setValue(this.edtMemo.value);

      this.popup.Close();
    }.bind(this);

    td.appendChild(edtMemo);
    dv.appendChild(table);
  },

  _updateMemo: function() {
    var field = this.memo.dataset ? this.memo.dataset.findField(this.memo.fieldName) : null;

    if (field)
      this.edtMemo.value = field.getValue() || '';
  },

  _getImage: function(index) {
    return UI.getImage(UI.Comps.PopupMemoItem, index);
  },

  _createButton: function(owner, options) {
    if (!options.width)
      options.width = 18;
    if (!options.height)
      options.height = 18;

    options.parent = owner;

    if (typeof options.image == 'number')
      options.image = this._getImage(options.image);

    if (typeof options.caption != 'string')
      options.caption = '';

    var btn = new UI.Comps.Button(null, options);
    btn.ignoreBlur = true;
    btn.hideBorder();

    if (typeof options.action == 'string')
      btn.action = options.action;

    if (options.onclick)
      btn.onClick = options.onclick;

    return btn;
  },

  _show: function(x, y, objWidth, objHeight) {
    this._updateMemo();

    this.superclass._show.call(this, x, y, objWidth, objHeight);
    document.body.unselectable = "off";

    this.focusing = true;
    setTimeout((function() { this.edtMemo.focus(); }).bind(this), 1);
  },

  _onblur: function() {
    if (!this.focusing)
      this.superclass._onblur.call(this);

    this.focusing = false;
  },

  _hide: function() {
    document.body.unselectable = "on";
    this.superclass._hide.call(this);

    this.memo._doblurEvent();
  },

  _onkeydown: function(key, evt) {
    this.memo._onkeydown(key, evt);
  },

  _onItemClick: function(index, td) {
    this.memo.ignoreBlurEvent = true;
    this.popup.Close();

    setTimeout((function() { this.memo.edit.focus(); }).bind(this), 0);
    setTimeout((function() { this.memo.ignoreBlurEvent = false; }).bind(this), 1);
  }
});


/********** layoutmanager.js **********/


UI.Comps.LayoutManager = Class.create();

UI.Comps.LayoutManager.prototype = {

  container: null,
  items: null,
  autoSize: true,

  initialize: function(container, options) {
    if (typeof container == 'string')
      this.container = $(container);
    else
      if ((typeof container == 'object') && container)
        this.container = container;
      else {
        this.containerCreated = true;
        this.container = document.createElement('div');
      }

    this.items = new Array();

    if (options) {
      if (typeof options.autoResize == 'boolean')
        this.autoResize = options.autoResize;

      if (typeof options.width == 'number') {
        this.container.style.width = options.width + 'px';
        this.autoSize = false;
      }
      if (typeof options.width == 'string') {
        this.container.style.width = options.width;
        this.autoSize = false;
      }

      if (typeof options.height == 'number') {
        this.container.style.height = options.height + 'px';
        this.autoSize = false;
      }
      if (typeof options.height == 'string') {
        this.container.style.height = options.height;
        this.autoSize = false;
      }

      if (typeof options.attrs == 'object')
        for (var i = 0; i < options.attrs.length; i++) {
          this.items.push(options.attrs[i]);
          options.attrs[i].manager = this;
        }
    }

    this._update();
  },

  dispose: function() {
    this.clear();
    this.items = null;

    if (this.containerCreated && this.container.parentNode)
      this.container.parentNode.removeChild(this.container);

    this.container = null;
  },

  addAttribute: function(attr) {
    this.items.push(attr);
    attr.manager = this;
    this._update();
  },

  removeAttribute: function(attr) {
    for (var i = 0; i < this.items.length; i++)
      if (this.items[i] == attr) {
        attr.manager = null;

        for (var n = i+1; n < this.items.length; n++)
          this.items[n-1] = this.items[n];

        this.items.length--;
        break;
      }
    this._update();
  },

  clear: function() {
    for (var i = 0; i < this.items.length; i++)
      this.items[i].manager = null;

    this.items.length = 0;
    this._update();
  },

  _getMaxLabelWidth: function(column) {
    var maxWidth = 0;

    for (var i = 0; i < this.items.length; i++)
      if (this.items[i].column == column)
        maxWidth = Math.max(this.items[i].width, maxWidth);

    return maxWidth;
  },

  _getAttributeHeight: function(attribute) {
    switch (attribute.type) {
      case UI.Comps.Attribute.AttributeType.AT_COMBO:
        return attribute.container.clientHeight;
      case UI.Comps.Attribute.AttributeType.AT_CHECKBOX:
        return attribute.height;
      default:
        return attribute.container.clientHeight;
    }
  },

  _update: function() {
    while (this.container.childNodes.length > 0)
      this.container.removeChild(this.container.childNodes[0]);

    var table = UI.createTable({width: '100%', height: '100%'});
    var colCount = 0;
    var rowCount = 0;
    var lastCol = 1000;
    var td, tr = null;
    var lblWidth = [];
    var maxHeight = [];

    for (var i = 0; i < this.items.length; i++)
      colCount = Math.max(colCount, this.items[i].column+1);

    this.container.appendChild(table);

    for (var i = 0; i < this.items.length; i++) {
      var firstElement = false;

      if (lastCol >= this.items[i].column) {
        if ((tr != null) && (i > 0) && (colCount - this.items[i-1].column > 1))
          td.colSpan = colCount - this.items[i-1].column;

        tr = UI.createTableElement(table, 'tr');
        rowCount++;
        firstElement = true;
      }

      td = UI.createTableElement(tr, 'td');
      td.vAlign = 'top';
      lastCol = this.items[i].column;
      if (firstElement && (lastCol > 0)) {
        td.colSpan = lastCol;
        td.innerHTML = '&nbsp;';
        td = UI.createTableElement(tr, 'td');
      }

      if ((i+1 < this.items.length) && ((this.items[i].column == 0) || (this.items[i+1].column > this.items[i].column)))
        td.style.width = this.items[i].width + 'px';
      else
        td.style.width = '100%';

      this.items[i].setParent(td);

      lblWidth[lastCol] = Math.max(lblWidth[lastCol] || 0, this.items[i].getLabelWidth());
      maxHeight[rowCount] = Math.max(maxHeight[rowCount] || 0, this._getAttributeHeight(this.items[i]));

      if ((i+1 < this.items.length) && (this.items[i+1].column > lastCol))
        td.colSpan = this.items[i+1].column - lastCol;
      else
        if (i+1 == this.items.length)
          td.colSpan = colCount - this.items[i].column;

      if (this.items[i].column > 0)
        td.style.paddingLeft = '4px';
    }

    var contHeight = 0;

    for (var i = 0; i < rowCount; i++)
      contHeight += maxHeight[i+1];

    for (var i = 0; i < this.items.length; i++)
      this.items[i].setLabelWidth(lblWidth[this.items[i].column]);

    var func = function() {
      if (table.childNodes[0].childNodes.length > 0)
        this.container.style.width = table.childNodes[0].childNodes[0].offsetWidth;
    }
    setTimeout(func.bind(this), 1);

    this.container.style.width = '10px';
    this.container.style.height = contHeight + 'px';
  }
}