/**
* DYNAX - DHTML and Ajax suite.
* @author Vladan Antic
* @date January-December 2007.
* @version 1.3.10
* @note this is a library of DHTML and AJAX components - it requires both prototype.js and dynamic.js files.
*/

var DYNAX = {
    version: '1.3.9'
}

// global variables
var DYNAX_dummyInd   = 0;
var DYNAX_dBoxIndex  = 0;
var DYNAX_dBoxActive = false;

DYNAX.Base = function() {
    // common variables...
    this.imagePath      = 'images/';
    this.iconPath       = 'images/icons/';
    this.iconEmpty      = 'empty.gif';
    this.image1         = '1.gif';
    this.elmIframe      = '<iframe id="dummyFrame" src="/blank.html" style="display: block; position: absolute; top: 0px; left: 0px; width: 2000px; height: 1600px; z-index: -1; filter: mask(); overflow: none;"></iframe>';
    this.diffX          = 0;
    this.diffY          = 0;
    this.body           = false;
}

DYNAX.Base.prototype = {

    setVar: function(vr, vl) {
        var cs = "this." + vr + " = ";
        cs += isString(vr) ? "'" + vl + "'" : vl;
        eval(cs);
    },

    setOption: function(vr, vl) {
        var cs = "this.options." + vr + " = ";
        cs += isString(vr) ? "'" + vl + "'" : vl;
        eval(cs);
    },

    iniLayer: function(id) {
        // get body element needed to set real position of this layer (by including scroll values)
        this.body = document.getElementsByTagName('body')[0];

        new Insertion.Top(this.body, '<div id="' + id + '"></div>');
        return $(id);
    },

    iniIframe: function(obj) {
        new Insertion.Before(obj, this.elmIframe);
        return $('dummyFrame');
    },

    setDummyLayer: function(ind, zIdx, tpe) {
        ind = ind || ''; // letter indicator to DHTML object (Calendar, ContextMenu, DialogBox, ...)
        zIdx = zIdx || 0;
        tpe = tpe || false;
        var bL = 'blurLayer' + ind;
        var dL = 'dummyLayer' + ind;
        var id = tpe ? bL : dL;
        var scrl = (isIE) ? 20 : 16;
        if (!$(id)){
            var dmy = this.iniLayer(id);
            dmy.style.width  = getDocumentWidth() - scrl + 'px';
            dmy.style.height = getDocumentHeight() - 5 + 'px';
            dmy.className = tpe ? 'blurLayer' : 'dummyLayer';
            if (zIdx > 0) dmy.style.zIndex = zIdx;

            return dmy;
        } else return $(id);
    },

    unsetDummyLayer: function(ind) {
        ind = ind || '';
        var bL = 'blurLayer' + ind;
        var dL = 'dummyLayer' + ind;
        if ($(bL)) Element.remove(bL);
        if ($(dL)) Element.remove(dL);
    },

    detachDummyEvent: function(ind, event) {
        ind = ind || '';
        var bL = 'blurLayer' + ind;
        var dL = 'dummyLayer' + ind;
        var elm = null;
        if ($(bL)) elm = $(bL);
        if ($(dL)) elm = $(dL);
        if (elm) eval("elm.on"+event+" = null");
    },


    buildParameterString: function(parameterList) {
        var ajaxParameters = parameterList || '';
        var re = new RegExp("(\\{[^,]*\\})", 'g'); // should retrieve each {} group
        var results = ajaxParameters.match(re);
        if (results != null) {
            for (var r=0; r<results.length; r++) {
                var nre = new RegExp(results[r], 'g');
                var field = $(results[r].substring(1, results[r].length-1));
                ajaxParameters = replaceWithValue(ajaxParameters, nre, field);
            }
        }
        return ajaxParameters;
    },

    attachEvent: function(element, event, listener, obj) {
        eval("element.on"+event+" = listener.bindAsEventListener(obj)");
    },

    detachEvent: function(element, event) {
        eval("element.on"+event+" = null");
    },


    /**
    * getCookie()
    * @param name - name of cookie.
    * @return - the value of a cookie.
    */
    getCookie: function(name) {
       var start = document.cookie.indexOf(name+"=");
       var len = start+name.length+1;
       if ((!start) && (name != document.cookie.substring(0,name.length))) return null;
       if (start == -1) return null;
       var end = document.cookie.indexOf(";",len);
       if (end == -1) end = document.cookie.length;
       return unescape(document.cookie.substring(len,end));
    },

    /**
    * setCookie()
    * @param name - name of cookie.
    * @param value - value of cookie
    * @param expires - timestamp of days
    * @param path - path for cookie
    * @param domain - cookie domain
    * @param secure - secure cookie (SSL)
    */
    setCookie: function(name, value, expires, path, domain, secure) {
        expires = expires * 60*60*24*1000;
        var today = new Date();
        var expires_date = new Date( today.getTime() + (expires) );
        var cookieString = name + "=" +escape(value) +
           ( (expires) ? ";expires=" + expires_date.toGMTString() : "") +
           ( (path) ? ";path=" + path : "") +
           ( (domain) ? ";domain=" + domain : "") +
           ( (secure) ? ";secure" : "");
        document.cookie = cookieString;
    },

    /**
    * Dragging and mouse functions
    */
    handleMouseDown: function(oEvent, objId) {
        if ($(objId)) {
            var oDiv = $(objId);
            this.diffX = oEvent.clientX - oDiv.offsetLeft;
            this.diffY = oEvent.clientY - oDiv.offsetTop;
            oDiv.style.cursor = 'move';

            this.attachEvent(document.body, 'mousemove', function(){this.handleMouseMove(oEvent, oDiv)}, this);
            this.attachEvent(document.body, 'mouseup', function(){this.handleMouseUp(oEvent, oDiv)}, this);
        }
    },

    handleMouseMove: function(oEvent, oDiv) {
        oDiv.style.left = oEvent.clientX - this.diffX + 'px';
        oDiv.style.top = oEvent.clientY - this.diffY + 'px';
    },

    handleMouseUp: function(oEvent, oDiv) {
        oDiv.style.cursor = 'default';
        this.detachEvent(document.body, 'mousemove');
        this.detachEvent(document.body, 'mouseup');
    },

    handleOver: function(elm, clss) {
        if (elm && $(elm)){
            $(elm).className = clss;
        } else {
            elm.className = clss;
        }
    },

    refreshHandling: function(act, objInst, appl) {
        obj = eval(objInst);
        if(appl == 'greeting') {
            if(act == 'open') {
                obj.editGrid = 'true';
                obj.autoReloadStatus.src = this.iconPath + 'autoreload_inactive.gif';
            } else if(act == 'close') {
                obj.editGrid = 'false';
                obj.prepChBox();
            }
        }
    }

}


/**
* Calendar class.
* @author Vladan Antic.
* @date 2.2007.
* @version 1.4.
* @note calendar tool referenced on HTML element or created as layer; default date format: dd.mm.yyyy; forbiden dates format: yyyymmdd
* @version 1.5.
* @note improved date getting from a target element
* @version 1.5.1
* @note fixed bug on Days navigation, in case when are opened 2/more calendars
*/

DYNAX.Calendar = Class.create();
DYNAX.Calendar.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(id, options, allowed, forbiden) {
        if (!id) return false;

        this.id       = id;
        this.allowed = allowed || false;
        this.forbiden = forbiden || false;

        this.calendar        = false;
        this.targetDate      = false;
        this.dummyLayer      = false;
        this.dummyFrame      = false;
        this.today           = new Date();
        this.caleYear        = false;
        this.caleMonth       = false;
        this.labels          = false;
        this.dateRegExp      = /[\.\-\/\ ]/; // included: ., -, / and space character as date separator

        options = options || new Array();
        this.setOptions(options);

        switch (this.options.language){
            case 'de': // germany (deutsch)
                var days    = (this.options.dayNames == 'short') ? ['Mo','Di','Mi','Do','Fr','Sa','So'] : ['Mon','Die','Mit','Don','Fre','Sam','Son'];
                var months  = (this.options.monthNames == 'short') ? ['Jan','Feb','Mar','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'] : ['Januar','Februar','M�rz','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
                this.labels = {
                    days: days,
                    months: months,
                    nextYear: 'n�chstes Jahr',
                    nextMonth: 'n�chster Monat',
                    prevYear: 'vorheriges Jahr',
                    prevMonth: 'vorheriger Monat',
                    today: 'Heute',
                    deleteDate: 'Datum l�schen',
                    closeCalendar: 'Kalendar schliessen'
                };
                break;
            case 'fr': // french
                var days    = (this.options.dayNames == 'short') ? ['Lu','Ma','Me','Je','Ve','Sa','Di'] : ['Lun','Mar','Mer','Jeu','Ven','Sam','Dim'];
                var months  = (this.options.monthNames == 'short') ? ['Jan','Fev','Mar','Avr','Mai','Jun','Jul','Aou','Sep','Oct','Nov','Dec'] : ['Janvier','F�vrier','Mars','Avril','Mai','Juin','Juillet','Ao�t','Septembre','Octobre','Novembre','D�cembre'];
                this.labels = {
                    days: days,
                    months: months,
                    nextYear: 'Next Year',
                    nextMonth: 'Next Month',
                    prevYear: 'Previous Year',
                    prevMonth: 'Previous Month',
                    today: 'Aujourd',
                    deleteDate: 'Delete Date',
                    closeCalendar: 'Close Calendar'
                };
                break;
            case 'it': // italian
                var days    = (this.options.dayNames == 'short') ? ['Lu','Ma','Me','Gi','Ve','Sa','Do'] : ['Lun','Mar','Mer','Gio','Ven','Sab','Dom'];
                var months  = (this.options.monthNames == 'short') ? ['Gen','Feb','Mar','Apr','Mag','Giu','Lugl','Ago','Set','Ott','Nov','Dic'] : ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno','Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'];
                this.labels = {
                    days: days,
                    months: months,
                    nextYear: 'Next Year',
                    nextMonth: 'Next Month',
                    prevYear: 'Previous Year',
                    prevMonth: 'Previous Month',
                    today: 'Oggi &egrave; il',
                    deleteDate: 'Delete Date',
                    closeCalendar: 'Close Calendar'
                };
                break;
            case 'sr': // srpski
                var days    = (this.options.dayNames == 'short') ? ['Po', 'Ut', 'Sr', '&#268;e', 'Pe', 'Su', 'Ne'] : ['Ponedeljak', 'Utorak', 'Sreda', '&#268;etvrtak', 'Petak', 'Subota', 'Nedelja'];
                var months  = (this.options.monthNames == 'short') ? ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Avg', 'Sep', 'Okt', 'Nov', 'Dec'] : ['Januar', 'Februar', 'Mart', 'April', 'Maj', 'Juni', 'Juli', 'Avgust', 'Septembar', 'Oktobar', 'Novembar', 'Decembar'];
                this.labels = {
                    days: days,
                    months: months,
                    nextYear: 'Slede&#263;a Godina',
                    nextMonth: 'Slede&#263;i Mesec',
                    prevYear: 'Predhodna Godina',
                    prevMonth: 'Predhodni Mesec',
                    today: 'Danas',
                    deleteDate: 'Brisanje Datuma',
                    closeCalendar: 'Zatvori Kalendar'
                };
                break;
            default: // english
            var days    = (this.options.dayNames == 'short') ? [_text('Mo'), _text('Tu'), _text('We'), _text('Th'), _text('Fr'), _text('Sa'), _text('Su')] : [_text('Monday'), _text('Tuesday'), _text('Wednesday'), _text('Thursday'), _text('Friday'), _text('Saturday'), _text('Sunday')];
            var months  = (this.options.monthNames == 'short') ? [_text('Jan_3'), _text('Feb_3'), _text('Mar_3'), _text('Apr_3'), _text('May_3'), _text('Jun_3'), _text('Jul_3'), _text('Aug_3'), _text('Sep_3'), _text('Oct_3'), _text('Nov_3'), _text('Dec_3')] : [_text('January'), _text('February'), _text('March'), _text('April'), _text('May'), _text('June'), _text('July'), _text('August'), _text('September'), _text('October'), _text('November'), _text('December')];
                this.labels = {
                    days: days,
                    months: months,
                    nextYear: _text('next_year'),
                    nextMonth: _text('next_month'),
                    prevYear: _text('previous_year'),
                    prevMonth: _text('previous_month'),
                    today: _text('today'),
                    deleteDate: _text('delete_date'),
                    closeCalendar: _text('close_calendar')
                };
        };
    },

    setOptions: function(options) {
        this.options = Object.extend({
            width: options.width ? options.width : 160,
            targetElem: options.target ? $(options.target) : false,
            separator: options.separator ? options.separator : '.',
            format: options.format ? options.format : false,
            language: options.language ? options.language : 'en',
            dayNames: options.dayNames ? options.dayNames : 'short',
            monthNames: options.monthNames ? options.monthNames : 'long',
            onChangeFunction: options.onChangeFunction ? options.onChangeFunction : false,
            postFunction: options.postFunction ? options.postFunction : false,
            workDays: options.workDays ? options.workDays : '1,2,3,4,5,6,7'
        }, options || {});

        if (this.options.targetElem){
            // get a date from the target element by using given or default (dd.mm.yyyy) date format
            var date_ = this.options.targetElem.value.split(this.dateRegExp);

            var day = this.today.getDate();
            var month = this.today.getMonth() + 1;
            var year = this.today.getFullYear();

            if (this.options.format){
                if (date_.length == 3){
                    var format_ = this.options.format.split(this.dateRegExp, 3);
                    eval("var formatDate = {" + format_[0] + ":date_[0], " + format_[1] + ":date_[1], " + format_[2] + ":date_[2]}");
                    day = parseInt(formatDate.dd, 10);
                    month = parseInt(formatDate.mm, 10);
                    year = parseInt(formatDate.yyyy, 10);
                    if (year < 1900) year += 2000;
                } else { // use given format without known seprator
                    var dd_idx = this.options.format.indexOf('dd');
                    var mm_idx = this.options.format.indexOf('mm');
                    var yy_idx = this.options.format.indexOf('yyyy');
                    day = parseInt(this.options.targetElem.value.substr(dd_idx, 2), 10);
                    month = parseInt(this.options.targetElem.value.substr(mm_idx, 2), 10);
                    year = parseInt(this.options.targetElem.value.substr(yy_idx, 4), 10);
                    if (year < 1900) year += 2000;
                }
            } else {
                if (date_.length == 3) {
                    day = parseInt(date_[0], 10);
                    month = parseInt(date_[1], 10);
                    year = parseInt(date_[2], 10);
                    if (year < 1900) year += 2000;
                }
            }

            if (this.checkDate(year, month, day)) {
                this.targetDate = {year: year, month: month, day: day};
            }
        }
    },

    setForbiden: function(forbiden) {
        this.forbiden = forbiden || false;
    },

    setAllowed: function(allowed) {
        this.allowed = allowed || false;
    },

    checkDate: function(year, month, day){
        var success = true;

        if (isNaN(day) || isNaN(month) || isNaN(year)) {
            success = false;
        } else {
            if (day < 1 || day > this.getDaysInMonth(year, month)) success = false;
            if (month < 1 || month > 12) success = false;
            if (year < 1900 || year > 2099) success = false;
        }
        return success;
    },

    setDate: function(year, month, day) {
        this.targetDate = {year: year, month: month, day: day};
    },

    getYear: function() {
        var year = null;
        if (this.caleYear)
            year = this.caleYear.value;
        else if (this.targetDate)
            year = this.targetDate.year;
        else
            year = this.today.getFullYear();
        return this.padZero(year);
    },

    getMonth: function() {
        var month = null;
        if (this.caleMonth)
            month = this.caleMonth.value;
        else if (this.targetDate)
            month = this.targetDate.month;
        else
            month = this.today.getMonth() + 1;
        return this.padZero(month);
    },

    display: function (obj) {
        var elmPos = false;

        if (obj){ // indicate popUp calendar
            this.calendar = this.iniLayer(this.id);
            elmPos = getPosition(obj);

            this.calendar.style.top  = elmPos.y + this.body.scrollTop + 'px';
            this.calendar.style.left = elmPos.x + this.body.scrollLeft + obj.offsetWidth + 2 + 'px';
            this.calendar.style.width = this.options.width + 'px';
            if (isIE) this.calendar.style.position = 'absolute';
            else this.calendar.style.position = 'fixed';
            this.calendar.style.zIndex = 900;

            this.dummyLayer = this.setDummyLayer('C', 880);
            this.attachEvent(this.dummyLayer, 'click', this.closeCalendar, this);

            if (isIE) this.dummyFrame = this.iniIframe(this.calendar);

        } else if ($(this.id)){ // reference to the HTML object
            this.calendar = $(this.id);

        } else if (!this.calendar) return false;

        this.calendar.style.width = this.options.width + 'px';
        this.calendar.className = 'calendar';

        if (this.targetDate){
            this.makeCalendar(this.targetDate.year, this.targetDate.month, this.targetDate.day);
        } else {
            this.makeCalendar();
        }
    },

    makeCalendar: function (year, month, day) {
        year  = year || this.today.getFullYear();
        month = month || this.today.getMonth() + 1;

        var out = '';

        // calendar navigation (months, years, icons...)
        out += '<table border="0" cellPadding="0" cellSpacing="1" align="center">';
        out += '<tr>';
        out += '<td width="99%" align="center">';

        var listOfMonths = '<select id="' + this.id + 'Month" class="calendar_field">';
        for (var i=0; i<12; i++){
            listOfMonths += '<option value="' + (i + 1) + '"';
            if (i == (month - 1)) listOfMonths += "selected";
            listOfMonths += '>' + this.labels.months[i] + '</option>';
        }
        listOfMonths += '</select>';
        out += listOfMonths + '&nbsp;';

        out += '<input id="' + this.id + 'Year" value="' + year + '" maxlength="4" class="calendar_field" style="width: 36px" >';
        out += '</td>';
        if (this.dummyLayer){
            out += '<td valign="middle"><img src="images/icons/close.gif" id="' + this.id + 'Close" style="cursor: pointer" title="' + this.labels.closeCalendar + '" />';
            out += '</tr>';
        }
        out += '</table>';

        out += '<table border="0" cellPadding="1" cellSpacing="0">';
        out += '<tr>';
        out += '<td class="calendar_navi"><img src="images/icons/prev.gif" id="' + this.id + 'PrevYear" style="cursor: pointer;" title="' + this.labels.prevYear + '" /></td>';
        out += '<td class="calendar_navi"><img src="images/icons/left.gif" id="' + this.id + 'PrevMonth" style="cursor: pointer;" title="' + this.labels.prevMonth + '" /></td>';
        out += '<td class="calendar_navi" width="50%" align="center"><div id="' + this.id + 'Today" style="cursor: pointer;">' + this.labels.today + '</div></td>';
        out += '<td class="calendar_navi" width="30%" align="center"><img src="images/icons/delete.gif" id="' + this.id + 'Delete" style="cursor: pointer;" title="' + this.labels.deleteDate + '" /></td>';
        out += '<td class="calendar_navi"><img src="images/icons/right.gif" id="' + this.id + 'NextMonth" style="cursor: pointer;" title="' + this.labels.nextMonth + '" /></td>';
        out += '<td class="calendar_navi"><img src="images/icons/next.gif" id="' + this.id + 'NextYear" style="cursor: pointer;" title="' + this.labels.nextYear + '" /></td>';
        out += '</tr>';
        out += '</table>';

        var cale_navi = document.createElement('div');
        cale_navi.className = 'calendar_headline';
        cale_navi.innerHTML = out;
        cale_navi.style.textAlign = 'center';

        this.caleDays = document.createElement('div');
        this.caleDays.id = this.id + 'Days';

        this.calendar.appendChild(cale_navi);
        this.calendar.appendChild(this.caleDays);

        this.caleMonth = $(this.id + 'Month');
        this.caleYear  = $(this.id + 'Year');

        this.attachEvent(this.caleMonth, 'change', function(){this.changeMonth()}, this);
        this.attachEvent(this.caleYear, 'blur', function(event){this.changeYear(event, 0)}, this);
        this.attachEvent(this.caleYear, 'keyup', function(event){this.changeYear(event, 1)}, this);
        if (this.dummyLayer)
            this.attachEvent($(this.id + 'Close'), 'click', function(){this.closeCalendar()}, this);

        this.attachEvent($(this.id + 'PrevYear'), 'click', function(){this.naviCalendar(-1, 0)}, this);
        this.attachEvent($(this.id + 'PrevMonth'), 'click', function(){this.naviCalendar(0, -1)}, this);
        this.attachEvent($(this.id + 'Today'), 'click', function(){this.setToday()}, this);
        this.attachEvent($(this.id + 'Delete'), 'click', function(){this.clearDate()}, this);
        this.attachEvent($(this.id + 'NextMonth'), 'click', function(){this.naviCalendar(0, 1)}, this);
        this.attachEvent($(this.id + 'NextYear'), 'click', function(){this.naviCalendar(1, 0)}, this);

        this.renderDaysOfMonth(year, month);

        if (this.dummyFrame) {
            this.dummyFrame.style.top = this.calendar.offsetTop + 'px';
            this.dummyFrame.style.left = this.calendar.offsetLeft + 'px';
            this.dummyFrame.style.width = this.calendar.offsetWidth;
            this.dummyFrame.style.height = this.calendar.offsetHeight;
            this.dummyFrame.style.display = "block";
            this.dummyFrame.style.zIndex = 890;
        }
    },

    renderDaysOfMonth: function(year, month) {
        var daysInMonth = this.getDaysInMonth(year, month);
        var currDay = new Date(year, month - 1, 1);
        var out = '';

        // calendar days...
        out += '<table width="100%" border="0" cellPadding="1" cellSpacing="0">';
        out += '<tr align="center">';

        var span  = '';
        var _span = '';

        for (var i=0; i<7; i++){
            if (i == 6){
                span  = '<span class="calendar_sunday">';
                _span = '</span>';
            }
            out += '<td class="calendar_head" width="14%">' + span + this.labels.days[i] + _span + '</td>';
        }
        out += '</tr>';
        out += '<tr>';

        var dayInWeek = currDay.getDay();
        if (dayInWeek == 0) dayInWeek = 7;

        // first, fill blank cells...
        for (var i=1; i<dayInWeek; i++)
            out += '<td align="center" class="calendar_day">&nbsp;</td>';

        _span = '</span>';
        var currPrefix = '';

        // then, fill days of the month...
        for (var i=1; i<=daysInMonth; i++){
            currDay.setDate(i);

            if (currDay.getDay() == 0){
                span  = '<span class="calendar_sunday">';
            } else {
                span  = '<span class="calendar_day">';
            }

            if (currDay.getFullYear() == this.today.getFullYear() && currDay.getMonth() == this.today.getMonth() && currDay.getDate() == this.today.getDate()){
                currPrefix = 'current_';
            } else {
                currPrefix = '';
            }

            var actionString = '';
            var mouseOver    = '';
            var classSfx     = 'out_';

            if (this.allowed){
                var alwDate = parseInt(currDay.getFullYear() + this.padZero(currDay.getMonth()+1) + this.padZero(currDay.getDate()));
                for (var j=0; j<this.allowed.length; j++){
                    if (alwDate >= parseInt(this.allowed[j].from) && alwDate <= parseInt(this.allowed[j].to)){
                        actionString = 'true';
                        mouseOver    = 'true';
                        classSfx     = 'out';

                    }
                }

            }else{
                actionString = 'true';
                mouseOver    = 'true';
                classSfx     = 'out';
            }
            if (this.options.workDays){
                var wDay = currDay.getDay();
                if (wDay == 0) wDay = 7;
                if (this.options.workDays.indexOf(wDay) == -1){
                    actionString = '';
                    mouseOver    = '';
                    classSfx     = 'out_';

                }

            }
            if (this.forbiden){
                var frbDate = parseInt(currDay.getFullYear() + this.padZero(currDay.getMonth()+1) + this.padZero(currDay.getDate()));
                for (var j=0; j<this.forbiden.length; j++){
                    if (frbDate >= parseInt(this.forbiden[j].from) && frbDate <= parseInt(this.forbiden[j].to)){
                        actionString = '';
                        mouseOver    = '';
                        classSfx     = 'out_';
                    }
                }

            }

            out += '<td id="' + this.id + 'Day_' + i + '" align="center" class="calendar_' + currPrefix + classSfx + '" actionString="' + actionString + '" mouseOver="' + mouseOver + '" currPrefix="' + currPrefix + '">' + span + i + _span + '</td>';

            if (currDay.getDay() == 0){
                out += '</tr><tr>';
            }
        }

        out += '</tr>';
        out += '</table>';

        this.caleDays.innerHTML = out;

        // attach day events...
        eval("window.ref2" + this.id + " = this");

        for (var i=1; i<=daysInMonth; i++){
            var day = $(this.id + 'Day_' + i);
            if (day.getAttribute('actionString') != '') {
                eval("day.onclick = function(){window.ref2" + this.id + ".chooseDay(" + i + ")}");
            }
            if (day.getAttribute('mouseOver') != '') {
                var cssOver = day.getAttribute('currPrefix') + 'over';
                var cssOut  = day.getAttribute('currPrefix') + 'out';
                eval("day.onmouseover = function(){window.ref2" + this.id + ".mouseHandle(this,  '" + cssOver + "')}");
                eval("day.onmouseout  = function(){window.ref2" + this.id + ".mouseHandle(this,  '" + cssOut + "')}");
            }
        }
    },

    closeCalendar: function() {
        this.unsetDummyLayer('C');
        Element.remove(this.id);
        if (this.dummyFrame) Element.remove(this.dummyFrame);
        this.dummyLayer = false;
        this.dummyFrame = false;
    },

    chooseDay: function(day){
        var year  = this.caleYear.value;
        var month = this.caleMonth.value;
        var selDate = (this.options.format) ? this.formatDate(year, month, day) : this.makeDefaultDate(year, month, day);

        if (this.options.targetElem) this.options.targetElem.value = selDate;
        if (this.options.postFunction) this.options.postFunction();

        if (this.dummyLayer)
            this.closeCalendar();
    },

    changeYear: function(e, ind){
        var year  = parseInt(this.caleYear.value);
        var month = parseInt(this.caleMonth.value);
        var key = 0;

        if (this.options.onChangeFunction) this.options.onChangeFunction();

        if (e.keyCode) { key = e.keyCode; }

        if (ind == 0 || (ind == 1 && key == 13)) {
            if (year >= 1900 && year < 2100){
                this.renderDaysOfMonth(year, month);
            } else {
                this.caleYear.value = this.today.getFullYear();
            }
        }
    },

    changeMonth: function(){
        var year  = parseInt(this.caleYear.value);
        var month = parseInt(this.caleMonth.value);

        if (this.options.onChangeFunction) this.options.onChangeFunction();

        this.renderDaysOfMonth(year, month);
    },

    naviCalendar: function(yy, mm){
        var year  = parseInt(this.caleYear.value);
        var month = parseInt(this.caleMonth.value);

        if ((month == 1 && mm < 0 && year == 1900) || (month == 12 && mm > 0 && year == 2099) || (yy < 0 && year == 1900) || (yy > 0 && year == 2099)){
            return false;
        }

        if (month == 1 && mm < 0){
            month = 12;
            yy = -1;
        } else if (month == 12 && mm > 0){
            month = 1;
            yy = 1;
        } else if (mm != 0) {
            month += mm;
        }

        year += yy;

        this.caleYear.value = year;
        this.caleMonth.value = month;

        if (this.options.onChangeFunction) this.options.onChangeFunction();

        this.renderDaysOfMonth(year, month);
    },

    setToday: function(){
        var year  = this.today.getFullYear();
        var month = this.today.getMonth() + 1;
        var day   = this.today.getDate();
        var selDate = (this.options.format) ? this.formatDate(year, month, day) : this.makeDefaultDate(year, month, day);

        this.caleYear.value = year;
        this.caleMonth.value = month;

        if (this.options.onChangeFunction) this.options.onChangeFunction();

        this.renderDaysOfMonth(year, month);

        if (this.options.targetElem) this.options.targetElem.value = selDate;
        if (this.options.postFunction) this.options.postFunction();

    },

    refresh: function(){
        var year  = parseInt(this.caleYear.value);
        var month = parseInt(this.caleMonth.value);
        this.renderDaysOfMonth(year, month);
    },

    clearDate: function(){
        if (this.options.targetElem)
            this.options.targetElem.value = '';
    },

    makeDefaultDate: function(year, month, day){
        day   = this.padZero(day);
        month = this.padZero(month);

        return (day + this.options.separator + month + this.options.separator + year);
    },

    formatDate: function(year, month, day){
        var sel_date = new Date(year,month-1,day);
        var dayInWeek = sel_date.getDay();
        dayInWeek = dayInWeek === 0 ? 7 : dayInWeek;
        var dayInWeekLabel = this.labels.days[dayInWeek-1];
        day   = this.padZero(day);
        month = this.padZero(month);

        var date_ = this.options.format;
        date_ = date_.replace(/dw/g, dayInWeekLabel);
        date_ = date_.replace(/dd/g, day);
        date_ = date_.replace(/mm/g, month);
        date_ = date_.replace(/yyyy/g, year);

        return date_;
    },

    getDaysInMonth: function(year, month){
        var daysInMonthArray = [31,28,31,30,31,30,31,31,30,31,30,31];
        var daysInMonth = daysInMonthArray[month-1];
        if (daysInMonth == 28){
            if (this.isLeapYear(year))daysInMonth = 29;
        }
        return daysInMonth/1;
    },

    isLeapYear: function(inputYear) {
        if (inputYear%400==0||(inputYear%4==0&&inputYear%100!=0)) return true;
        return false;
    },

    padZero: function(x) {
        x = (x < 10) ? '0' + x : '' + x;
        return x;
    },

    mouseHandle: function (elm, pfx) {
        elm.className = 'calendar_' + pfx;
    }

});


/**
* ContextMenu class.
* @author Vladan Antic.
* @date 1.2007.
* @version 2.0.
* @note context menu are based on list of hidden fields which contains menu/items description
*/

DYNAX.ContextMenu = Class.create();
DYNAX.ContextMenu.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(e, elm, options, obj) {
        if (!elm) return false;

        this.cmEvent = e;
        this.cmItems = document.getElementsByName(elm); // get all items (hidden fields) of a context menu
        this.cmObject = obj;

        this.id = 'contextMenu';
        this.refToElement = false;

        options = options || new Array();
        this.setOptions(options);

        this.contextMenu();
    },

    setOptions: function(options) {
        this.options = Object.extend({
            width: options.width ? options.width : 160,
            closeEvent: options.closeEvent ? options.closeEvent : 'click',
            orientation: options.orientation ? options.orientation : 'down',
            className: options.className ? options.className : 'contextMenu',
            closeFunction: options.closeFunction ? options.closeFunction : false
        }, options || {});
    },

    contextMenu: function() {
        var pxCor  = isOpera ? 4 : 2;
        var top_c  = 0;
        var left_c = 0;

        if ($('contextMenu')) Element.remove('contextMenu');

        // make context menu if there are cmItems...
        if (this.cmItems.length > 0) {
            var cm_div = this.iniLayer(this.id);
            var cm_main = document.createElement('div');
            cm_main.className   = 'main';
            cm_main.style.width = this.options.width;

            for (i=0; i<this.cmItems.length; i++) {
                if (this.cmItems[i].getAttribute('isSpan')) {
                    var div = document.createElement('span');
                } else {
                    var div = document.createElement('div');
                }
                cm_icon   = this.cmItems[i].getAttribute('icon');
                cm_iconID = this.cmItems[i].getAttribute('iconID');
                cm_text   = (this.cmItems[i].getAttribute('label')) ? this.cmItems[i].getAttribute('label') : "Context Menu";
                cm_action = this.cmItems[i].getAttribute('actions');
                cm_sep    = this.cmItems[i].getAttribute('sep');
                if (cm_action) {
                    div.className   = 'item';
                    div.setAttribute('onclick', cm_action, 0);
                    div.setAttribute('onmouseover', "this.className = 'over';", 0);
                    div.setAttribute('onmouseout', "this.className = 'item';", 0);

                    ico = new Image(16, 16);
                    if (cm_icon) {
                        if (cm_iconID) ico.id = cm_iconID;
                        ico.src   = this.iconPath + cm_icon;
                    } else {
                        ico.src   = this.iconPath + this.iconEmpty;
                    }
                    ico.align = 'absmiddle';
                    div.appendChild(ico);
                    div.innerHTML += '&nbsp;';
                } else {
                    div.className = 'text';
                }
                div.innerHTML += cm_text;
                cm_main.appendChild(div);

                if (cm_sep) {
                    var sep = document.createElement('DIV');
                    sep.className = 'sep';
                    sep.innerHTML = '<img src="' + this.imagePath + this.image1 + '">';
                    cm_main.appendChild(sep);
                }
            }

            if (isIE) cm_main.innerHTML += this.elmIframe;
            cm_div.appendChild(cm_main);

            if (this.cmObject != null) {
                // get position of given element...
                var elmPos = getPosition(this.cmObject);
                if (this.options.orientation == 'down') {
                    top_c  = elmPos.y + this.cmObject.offsetHeight + pxCor;
                    left_c = elmPos.x;
                } else {
                    top_c  = elmPos.y;
                    left_c = elmPos.x + this.cmObject.offsetWidth + 2;
                }
            } else {
                top_c  = Event.pointerY(this.cmEvent) - 2;
                left_c = Event.pointerX(this.cmEvent) - 2;
            }

            oX = left_c + cm_div.offsetWidth;
            oW = getWindowWidth();

            cm_div.style.padding  = '1px';

            if (this.cmObject){
                cm_div.style.top  = top_c + this.body.scrollTop + 'px';
                cm_div.style.left = left_c + this.body.scrollLeft + 'px';
            } else {
                cm_div.style.top  = top_c + 'px';
                cm_div.style.left = left_c + 'px';
            }

            // left this.options.orientation if cM is out of screen
            if (oX > oW)
                cm_div.style.left = left_c - (oX - oW) - 24 + 'px';

            cm_div.style.visibility = 'visible';

            var dmy = this.setDummyLayer('CM', 980);
            this.attachEvent(dmy, this.options.closeEvent, this.closeContextMenu, this);
            this.attachEvent(cm_div, 'mouseup', this.closeContextMenu, this);
        }
    },

    closeContextMenu: function() {
        this.unsetDummyLayer('CM');
        $('contextMenu').style.display = 'none';
        if (this.options.closeFunction) eval(this.options.closeFunction + '()');
    }
});


/**
* AjaxDataGrid class.
* @author Vladan Antic.
* @date Jan-Dec 2007.
* @version 1.0
* @note AjaxDataGrid class is based on gridState variables instanced by using php class DataGrid; datagrid.inc.php is required.
* @version 1.1
* @note this version creates header by using THEAD rows as template, grid rows by using TBODY row as template and, optional, page navigation.
* @version 1.2
* @note supported array content into a cell of datagrid.
* @version 2.0
* @note improved rendering of grid rows - included buffering, different attributes and inner content maintenance.
*       a field description MUST BE in format: (*field:name*) or (*:name*) or with attributes: (*:name|truncate:40|suffix:...|empty:"none"*)
* @version 2.1
* @note made posibility to reload datagrid and switch to Base/Extedned mode preview.
* @version 2.2
* @note added "exact" for truncate, where it determines whether or not to trancate at the exact character: (*:email|truncate:24|exact*)
* @version 2.3
* @note added possibility to choose Normal or Small font size
* @version 2.4
* @note included filter options
* @version 2.5.1
* @note added IF clause in command section and AutoReload options
* @version 2.6.1
* @note implemented "id" attribute of a grid cell
* @version 2.6.2
* @note supported style attributes (backgroundColor, ...)
* @version 2.6.3
* @note in the list of formating attributes, added "wrap", like (*:name|wrap:30|suffix:<br>*)
* @version 2.6.3.1
* @note in the list of formating attributes, added "custom_js_encode", like (*:name|custom_js_encode*)
*/

DYNAX.AjaxDataGrid = Class.create();
DYNAX.AjaxDataGrid.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(id, state, url, options) {
        if (!(id && state && url)) return false;

        this.id = id;
        this.state = state;
        this.ajaxUrl = url;

        this.grid = false;
        this.xml = null;
        this.iconSortAsc  = "sort_asc.gif";
        this.iconSortDesc = "sort_desc.gif";
        this.pageSizes = new Array(1, 10, 20, 50, 100, 200, 500);
        this.z = 0; // zebra style indicator...
        this.fieldRegExp = /[(*][*)]/; // regular expression for db fields
        this.head_rows_len = false;
        this.smallFont = false;
        this.addCharacters = (isIE) ? 3 : 5;
        this.autoReload = 0;
        this.intervalID = false;
        this.editGrid = false;
        this.setRefreshIcon = false;

        options = options || new Array();
        this.setOptions(options);

        // get extendedMode...
        if (this.options.extendedMode){
            this.cookieName = this.id + 'extendedMode';
            var cookieValue = this.getCookie(this.cookieName);
            this.extendedMode = (cookieValue && cookieValue == 'true') ? true : false;
        }

        this.setState('pagination', (this.options.pagination) ? 1 : 0);

        if (this.options.searchField){
            this.search = $(this.id + '_' + this.options.searchField);
            this.searchIcon = $(this.id + '_' + this.options.searchField + '_icon');
            this.attachEvent(this.search, 'keydown', function(e){this.searchData(e, 'K')}, this);
            this.attachEvent(this.searchIcon, 'click', function(e){this.searchData(e, 'M')}, this);
            this.setState('search', encodeEscChr(this.search.value));
        }

        // initialize and create datagrid
        this.initDataGrid();
        this.createHeader();
        this.makeDataGrid();
        this.createNavigation();
        if(this.options.autoReload != false) {
            this.setAutoReload(this.options.autoReload);
        }
    },

    initDataGrid: function() {
        // initialize grid, head and body properties...
        if (!this.grid){
            this.grid = $(this.id);
            this.grid.className = this.options.classGrid;
            this.grid.parentNode.className = this.options.classGrid + '_frame';
            this.grid.border = 0;
            this.grid.cellPadding = 0;
            this.grid.cellSpacing = 0;
        }

        // define thead and tbody elements
        this.thead      = this.grid.getElementsByTagName('thead')[0];
        this.head_rows  = this.thead.getElementsByTagName('tr');
        if (!this.head_rows_len) this.head_rows_len = this.head_rows.length;

        this.tbody      = this.grid.getElementsByTagName('tbody')[0];
        this.tbody.rows[0].style.display = 'none'; // 1st row is used as template - don't show it, just...
        // get cell attributes of a row
        this.item_props = this.tbody.rows[0].getElementsByTagName('td');
        this.row_template = this.getRowTemplate(this.tbody.rows[0]);

        // save extendedMode
        this.setCookie(this.cookieName, this.extendedMode, 100000);
    },

    setOptions: function(options) {
        this.options = Object.extend({
            keyField: options.keyField ? options.keyField : '',
            keyInd: options.keyInd ? options.keyInd : '###',
            searchField: options.searchField ? options.searchField : false,
            emptyContent: options.emptyContent ? options.emptyContent : '&nbsp;',
            rowHeight: options.rowHeight ? options.rowHeight : 20,
            headerHeight: options.headerHeight ? options.headerHeight : 22,
            autoReload: options.autoReload ? options.autoReload : false,
            defaultAutoReload: options.defaultAutoReload ? options.defaultAutoReload : 0,
            showRowSelection: options.showRowSelection ? options.showRowSelection : false,
            showOrderNumber: options.showOrderNumber ? options.showOrderNumber : false,
            pagination: options.pagination ? options.pagination : true,
            classGrid: options.classGrid ? options.classGrid : '',
            classOver: options.classOver ? options.classOver : '',
            classEven: options.classEven ? options.classEven : '',
            classOdd: options.classOdd ? options.classOdd : '',
            filter: options.filter ? options.filter : '',
            postFunction: options.postFunction ? options.postFunction : false,
            extendedMode: options.extendedMode ? options.extendedMode : false,
            outVar: options.outVar ? options.outVar : false
        }, options || {});

        // make regular expression of keyField
        this.keyRegExp = new RegExp(this.options.keyInd, 'g');

        // don't show the message...
        if ($(this.id + '_message')){
            this.message = $(this.id + '_message');
            this.message.style.display = 'none';
        }
    },

    getRowTemplate: function(row) {
        if (!row) return null;
        var cells = row.getElementsByTagName('td');
        if (!cells) return null;

        var count = 0;
        var row_template = new Array();

        for (var i=0; i<cells.length; i++){

            if (this.extendedMode || !cells[i].getAttribute('extendedMode')){
                // get xml tags used 4 advanced content in a cell: items, tables, etc...
                var xml_tags = cells[i].getElementsByTagName('xml');

                if (xml_tags.length == 0){ // there is only HTML content in a cell
                    var inner_xml_ = false;

                    // get template content and attributes...
                    var inner_html_ = this.splitInnerHTML(cells[i].innerHTML);

                } else { // there is only XML tags in a cell
                    var inner_html_ = false;
                    var inner_xml_ = new Array();

                    // get template content and attributes for each XML tag..
                    for (var j=0; j<xml_tags.length; j++){
                        var xml_inner_html_ = this.splitInnerHTML(xml_tags[j].innerHTML);

                        inner_xml_[j] = {
                            condition: xml_tags[j].getAttribute('condition'),
                            conditionElse: xml_tags[j].getAttribute('conditionElse'),
                            foreach: xml_tags[j].getAttribute('foreach'),
                            className: xml_tags[j].getAttribute('cssStyle'),
                            backgroundColor: xml_tags[j].getAttribute('backgroundColor'),
                            actionString: xml_tags[j].getAttribute('actionString'),
                            innerHTML_: xml_inner_html_
                        };
                    }
                }

                row_template[count++] = {
                    id: cells[i].getAttribute('id'),
                    width: cells[i].getAttribute('width'),
                    height: cells[i].getAttribute('height'),
                    align: cells[i].getAttribute('align'),
                    valign: cells[i].getAttribute('valign'),
                    className: cells[i].getAttribute('cssStyle'),
                    backgroundColor: cells[i].getAttribute('backgroundColor'),
                    actionString: cells[i].getAttribute('actionString'),
                    innerHTML_: inner_html_,
                    innerXML_: inner_xml_
                };
            }
        }
        cells = null;
        return row_template;
    },

    createHeader: function() {
        var head_props = Array();
        var indShowOrderNumber = false;
        var indShowRowSelection = false;
        var grid_width = 0;

        // !!! don't clear template rows
        while (this.thead.rows.length > this.head_rows_len){
            this.thead.rows[this.thead.rows.length - 1].parentNode.removeChild(this.thead.rows[this.thead.rows.length - 1]);
        }

        // scan all thead rows used as templates...
        for (n=0; n<this.head_rows_len; n++){
            head_props[n] = this.head_rows[n].getElementsByTagName("td");
            this.head_rows[n].style.display = 'none';
        }

        // ...and create real header items
        for (n=0; n<this.head_rows_len; n++){
            var row          = this.thead.insertRow(-1);
            row.style.width  = '100%';
            row.style.height = this.options.headerHeight + 'px';

            // column with orderNumbers
            if (this.options.showOrderNumber){
                if (!indShowOrderNumber){
                    var cell = row.insertCell(-1);
                    cell.style.textAlign = 'center';
                    cell.rowSpan   = this.head_rows_len;
                    if (this.options.outVar){
                        var cell_cont = '<img src="' + this.iconPath + 'grid_settings.gif" title="Datagrid Settings" class="icon" onclick="new DYNAX.ContextMenu(event, \'' + this.id + 'Set\', {orientation: \'right\'}, this)" />';
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Reload\" icon=\"refresh.gif\" actions=\"" + this.options.outVar + ".setAutoReload(0)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 15 sec\" id=\"" + this.id + "SetAR15\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(15)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 30 sec\" id=\"" + this.id + "SetAR30\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(30)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 45 sec\" id=\"" + this.id + "SetAR45\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(45)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 1 min\" id=\"" + this.id + "SetAR60\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(60)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 5 min\" id=\"" + this.id + "SetAR300\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(300)\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Auto Reload on 10 min\" id=\"" + this.id + "SetAR600\" icon=\"empty.gif\" actions=\"" + this.options.outVar + ".setAutoReload(600)\" sep=\"1\"/>";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Normal Font\" icon=\"";
                        cell_cont += this.smallFont ? "empty.gif" : "checked.gif";
                        cell_cont += "\" actions=\"" + this.options.outVar + ".smallFont = false; " + this.options.outVar + ".initDataGrid(); " + this.options.outVar + ".createHeader(); " + this.options.outVar + ".makeDataGrid()\" />";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Small Font\" icon=\"";
                        cell_cont += this.smallFont ? "checked.gif" : "empty.gif";
                        cell_cont += "\" actions=\"" + this.options.outVar + ".smallFont = true; " + this.options.outVar + ".initDataGrid(); " + this.options.outVar + ".createHeader(); " + this.options.outVar + ".makeDataGrid()\" sep=\"1\"/>";
                        cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Base Mode\" icon=\"";
                        cell_cont += this.extendedMode ? "empty.gif" : "checked.gif";
                        cell_cont += "\" actions=\"" + this.options.outVar + ".extendedMode = false; " + this.options.outVar + ".initDataGrid(); " + this.options.outVar + ".createHeader(); " + this.options.outVar + ".makeDataGrid()\" />";

                        if (this.options.extendedMode) {
                            cell_cont += "<input type=\"hidden\" name=\"" + this.id + "Set\" label=\"Extended Mode\" icon=\"";
                            cell_cont += this.extendedMode ? "checked.gif" : "empty.gif";
                            cell_cont += "\" actions=\"" + this.options.outVar + ".extendedMode = true; " + this.options.outVar + ".initDataGrid(); " + this.options.outVar + ".createHeader(); " + this.options.outVar + ".makeDataGrid()\" />";
                        }
                    } else {
                        cell_cont = '#';
                    }
                    cell.innerHTML = cell_cont;
                    indShowOrderNumber = true;
                }
            }

            // column with checkBoxes to select rows
            if (this.options.showRowSelection){
                if (!indShowRowSelection){
                    var cell = row.insertCell(-1);
                    cell.rowSpan   = this.head_rows_len;
                    cell.innerHTML = "<img id=\""+this.id+"_selectAll\" src=\""+this.iconPath+"select_all.gif\" class=\"icon\" title=\"Select Grid Rows\" border=\"0\" align=\"absmiddle\" /><img id=\""+this.id+"_deselectAll\" src=\""+this.iconPath+"deselect_all.gif\" class=\"icon\" title=\"Deselect Grid Rows\" border=\"0\" align=\"absmiddle\" />";
                    indShowRowSelection = true;
                }
            }

            // data columns...
            for (i=0; i<head_props[n].length; i++){

                if (this.extendedMode || !head_props[n][i].getAttribute('extendedMode')){
                    var cell = document.createElement('td');
                    cell.style.textAlign = head_props[n][i].getAttribute('align');
                    cell.colSpan   = head_props[n][i].getAttribute('colSpan');
                    cell.rowSpan   = head_props[n][i].getAttribute('rowSpan');
                    cell.noWrap    = (head_props[n][i].getAttribute('nowrap') != null) ? true : false;
                    if (head_props[n][i].getAttribute('height')) cell.style.height = head_props[n][i].getAttribute('height') + 'px';
                    if (head_props[n][i].getAttribute('width')){
                        cell.style.width = head_props[n][i].getAttribute('width') + 'px';
                        grid_width += (n == 0) ? parseInt(head_props[n][i].getAttribute('width')) : 0;
                    }

                    if (this.smallFont)
                        cell.innerHTML = "<small>" + head_props[n][i].innerHTML + "</small>";
                    else
                        cell.innerHTML = head_props[n][i].innerHTML;

                    var sort_exp = head_props[n][i].getAttribute('sortExpression');

                    if (sort_exp){
                        cell.id = this.id + "_col_" + sort_exp;
                        eval("var f = function() {this.sortDataGrid('" + sort_exp + "', '" + this.getState('sort_ord') + "')}");
                        this.attachEvent(cell, 'click', f, this);

                        eval("var f = function(e) {this.handleOver('" + cell.id + "', '" + this.options.classGrid + '_head_over' + "')}");
                        this.attachEvent(cell, 'mouseover', f, this);
                        eval("var f = function(e) {this.handleOver('" + cell.id + "', null)}");
                        this.attachEvent(cell, 'mouseout', f, this);

                        var sort_ico  = "<img src=\""+this.iconPath;
                        sort_ico += (this.getState('sort_ord') == 'asc') ? this.iconSortDesc : this.iconSortAsc;
                        sort_ico += "\" align=\"absmiddle\" ";
                        sort_ico += (sort_exp == this.getState('sort')) ? "/>" : "style=\"visibility: hidden;\" />";
                        cell.innerHTML += sort_ico;
                    }
                    row.appendChild(cell);
                }
            }
        }

        // actions to (de)select grid rows...
        if (this.options.showRowSelection){
            this.attachEvent($(this.id + '_selectAll'), 'click', function(){this.selectGridRows(1)}, this);
            this.attachEvent($(this.id + '_deselectAll'), 'click', function(){this.selectGridRows(0)}, this);
        }

        this.grid.style.width = grid_width + 'px';
    },

    createNavigation: function() {
        if (!this.getState('pagination')) return false;

        // render datagrid navigation...
        var grid_navi = document.createElement('table');
        grid_navi.id = this.id + '_navigation';
        grid_navi.border = 0;
        grid_navi.cellPadding = 1;
        grid_navi.cellSpacing = 0;

        var row = grid_navi.insertRow(-1);

        // page sizes...
        var cell = row.insertCell(-1);
        cell.className = this.options.classGrid;
        cell.style.padding = '0 15 0 5';
        var page_sizes = "<select id=\""+this.id+"_page_size\" class=\"field\" style=\"width: 50px\">\n";
        for (i=0; i<this.pageSizes.length; i++){
            page_sizes += "<option value=\""+this.pageSizes[i]+"\"";
            page_sizes += (this.pageSizes[i] == this.getState('page_size')) ? " selected>" : ">";
            page_sizes += this.pageSizes[i]+"</option>\n";
        }
        cell.innerHTML = "Rows: " + page_sizes;

        // 1st and previous page icons...
        var cell = row.insertCell(-1);
        if (isMoz) cell.style.padding = '0 0 2 0';
        cell.innerHTML = "<img id=\""+this.id+"_frst_page\" src=\""+this.iconPath+"first.gif\" class=\"icon\" align=\"absmiddle\" title=\"First page\"><img id=\""+this.id+"_prev_page\" src=\""+this.iconPath+"prev.gif\" class=\"icon\" align=\"absmiddle\" title=\"Previous page\">";

        // go to page field...
        var cell = row.insertCell(-1);
        cell.className = this.options.classGrid;
        cell.style.padding = '0 10 0 10';
        cell.innerHTML = "Page: <input id=\""+this.id+"_curr_page\" type=\"text\" class=\"field\" value="+this.getState('curr_page')+" style=\"width: 40px;\"> of <span id=\""+this.id+"_totl_page\">"+this.getState('last_page')+"</span>&nbsp;<img id=\""+this.id+"_goto_page\" src=\""+this.iconPath+"go.gif\" class=\"icon\" align=\"absmiddle\" title=\"Go to page\">";

        // next and last page icons...
        var cell = row.insertCell(-1);
        if (isMoz) cell.style.padding = '0 0 2 0';
        cell.innerHTML = "<img id=\""+this.id+"_next_page\" src=\""+this.iconPath+"next.gif\" class=\"icon\" align=\"absmiddle\" title=\"Next page\"><img id=\""+this.id+"_last_page\" src=\""+this.iconPath+"last.gif\" class=\"icon\" align=\"absmiddle\" title=\"Last page\">";

        // autoreload...
        var cell = row.insertCell(-1);
        cell.style.padding = '0 0 2 12';
        cell.innerHTML = "<img id=\""+this.id+"_autoreload\" src=\""+this.iconPath+"autoreload_inactive.gif\" class=\"icon\" align=\"absmiddle\">";

        this.grid.parentNode.appendChild(grid_navi);

        // define page navi elements as global - needed to set after rows rendering
        this.pageSize = $(this.id + '_page_size');
        this.frstPage = $(this.id + '_frst_page');
        this.prevPage = $(this.id + '_prev_page');
        this.nextPage = $(this.id + '_next_page');
        this.lastPage = $(this.id + '_last_page');
        this.totlPage = $(this.id + '_totl_page');
        this.gotoPage = $(this.id + '_goto_page');
        this.currPage = $(this.id + '_curr_page');
        this.autoReloadStatus = $(this.id + '_autoreload');

        if (isMoz) this.gotoPage.style.padding = '0 0 2 0';
    },

    makeDataGrid: function() {
        // set zebra style here - each page in the same style beginning from the 1st row...
        if (this.options.classEven != "") this.z = 1;

        var prms = this.options.parameters;
        prms += (this.options.filter != '') ? this.options.filter : '';
        prms += '&grid_id=' + this.id;
        prms += '&pagination=' + this.getState('pagination');
        prms += '&page_size=' + this.getState('page_size');
        prms += '&curr_page=' + this.getState('curr_page');
        prms += '&last_page=' + this.getState('last_page');
        prms += '&search=' + this.getState('search');
        prms += '&sort=' + this.getState('sort');
        prms += '&sort_ord=' + this.getState('sort_ord');

        // get ajax request...
        var ajax = new Ajax.Request(
            this.ajaxUrl, {
                method: 'post',
                parameters: prms,
                onComplete: this.setResult.bind(this)
            });
    },

    setResult: function(request) {
        // grab xml of options
        this.xml = request.responseXML;
        var respNode = this.xml.getElementsByTagName("response")[0];
        var items = respNode.getElementsByTagName("item");

        this.clearDataRows();

        if (items.length < 1){
            this.grid.style.display = 'none';
            if ($(this.id + '_navigation')) $(this.id + '_navigation').style.display = 'none';
            if (this.message) this.message.style.display = 'block';
            return false;
        } else {
            this.grid.style.display = 'block';
            if ($(this.id + '_navigation')) $(this.id + '_navigation').style.display = 'block';
            if (this.message) this.message.style.display = 'none';
        }

        // fill data rows...
        for (var i=0; i<items.length; i++) {
            this.fillDataRow(items[i]);
        }

        // update actions of the page navigation with a new values
        var curr_page = Number(respNode.getElementsByTagName("curr_page")[0].firstChild.nodeValue);
        var last_page = Number(respNode.getElementsByTagName("last_page")[0].firstChild.nodeValue);
        prev_page = (curr_page > 1) ? curr_page - 1 : 1;
        next_page = (curr_page < last_page) ? curr_page + 1 : last_page;

        this.currPage.value = curr_page;
        this.totlPage.innerHTML = last_page;

        this.attachEvent(this.pageSize, 'change', function(){this.pageNavi(1, this.pageSize.options[this.pageSize.selectedIndex].value)}, this);
        this.attachEvent(this.frstPage, 'click', function(){this.pageNavi(1)}, this);
        this.attachEvent(this.prevPage, 'click', function(){this.pageNavi(prev_page)}, this);
        this.attachEvent(this.nextPage, 'click', function(){this.pageNavi(next_page)}, this);
        this.attachEvent(this.lastPage, 'click', function(){this.pageNavi(last_page)}, this);
        this.attachEvent(this.gotoPage, 'click', function(){this.pageNavi()}, this);
        this.attachEvent(this.currPage, 'keydown', this.keyNavi, this);

        if (this.options.postFunction) eval(this.options.postFunction + '()');

        this.prepChBox();
    },

    clearDataRows: function() {
        // !!! don't clear the 1st row - it is used as template row
        while (this.tbody.rows.length > 1){
            this.tbody.rows[this.tbody.rows.length - 1].parentNode.removeChild(this.tbody.rows[this.tbody.rows.length - 1]);
        }
    },

    fillDataRow: function(item) {
        var key_value = item.getElementsByTagName(this.options.keyField)[0].firstChild.nodeValue;
        var row = this.tbody.insertRow(-1);
        this.z *= -1;

        // set row styles...
        row.style.height = this.options.rowHeight;
        row.classOver    = this.options.classOver;
        row.classEven    = this.options.classEven;
        row.classOdd     = this.options.classOdd != '' ? this.options.classOdd : null;
        row.zebra        = this.z;
        row.onmouseover  = this.mouseOver;
        row.onmouseout   = this.mouseOut;
        row.className    = this.z > 0 ? this.options.classEven : row.classOdd;
        row.id           = this.id + '_tr[' + key_value + ']';

        // fill cells with order number and/or checkBoxes...
        if (this.options.showOrderNumber){
            var cell = row.insertCell(-1);
            cell.className = this.options.classGrid + '_column';
            cell.style.textAlign = 'right';
            cell.innerHTML = item.getElementsByTagName('nr')[0].firstChild.nodeValue;
        }
        if (this.options.showRowSelection){
            var cell = row.insertCell(-1);
            cell.className = this.options.classGrid + '_column';
            cell.style.textAlign = 'center';
            cell.innerHTML = "<input type=\"checkbox\" onclick = \"" + this.options.outVar + ".prepChBox();\" name=\"" + this.id + "_row[" + key_value + "]\">";
        }

        // fill cells defined in row template...
        for (var i=0; i<this.row_template.length; i++) {
            // create a new cell and styles of its...
            var in_cell = '';
            var cell    = row.insertCell(-1);
            cell.style.width = this.row_template[i].width;
            cell.style.height = this.row_template[i].height;
            cell.style.textAlign = this.row_template[i].align;
            cell.style.verticalAlign = this.row_template[i].valign;
            cell.className = this.row_template[i].className;

            // set ID, actionString (onclick) and others to the cell...
            if (this.row_template[i].id) cell.id = this.fillKeyValue(this.row_template[i].id, key_value);
            if (this.row_template[i].backgroundColor) cell.style.backgroundColor = this.fillKeyValue(this.row_template[i].backgroundColor, item);
            if (this.row_template[i].actionString) {
                eval("var f = function(event) {" + this.fillRealValues(this.row_template[i].actionString, item) + "}");
                this.attachEvent(cell, 'click', f, this);
                cell.style.cursor = "pointer";
            }

            // make a real content by using row template...
            if (this.row_template[i].innerHTML_){
                in_cell += this.makeInnerHTML(this.row_template[i].innerHTML_, item, key_value);

            // make a content by getting XML array...
            } else if (this.row_template[i].innerXML_){
                var inner_xml_ = this.row_template[i].innerXML_;

                var condition      = false;
                var cond_if        = false;
                var cond_else      = false;

                for (var j=0; j<inner_xml_.length; j++){
                    // command 'foreach'
                    if (inner_xml_[j].foreach){
                        var xml_items = item.getElementsByTagName(inner_xml_[j].foreach)[0].getElementsByTagName(inner_xml_[j].foreach+'item');

                        // get a content from each XML item...
                        for (var n=0; n<xml_items.length; n++){
                            if (inner_xml_[j].backgroundColor) cell.style.backgroundColor = this.fillRealValues(inner_xml_[j].backgroundColor, item);
                            if (inner_xml_[j].actionString) {
                                eval("var fx = function(event) {" + this.fillRealValues(inner_xml_[j].actionString, item) + "}");
                                this.attachEvent(cell, 'click', fx, this);
                                cell.style.cursor = "pointer";
                            }

                            in_cell += this.makeInnerHTML(inner_xml_[j].innerHTML_, xml_items[n], key_value);
                        }

                    // command 'if'
                    } else if (inner_xml_[j].condition) {
                        inner_xml_[j].condition = this.fillKeyValue(inner_xml_[j].condition, key_value);
                        condition = this.fillRealValues(inner_xml_[j].condition, item);

                        eval("cond_if = (" + condition + ") ? true : false");

                        if (cond_if) {
                            if (inner_xml_[j].backgroundColor) cell.style.backgroundColor = this.fillRealValues(inner_xml_[j].backgroundColor, item);
                            if (inner_xml_[j].actionString) {
                                eval("var fx = function(event) {" + this.fillRealValues(inner_xml_[j].actionString, item) + "}");
                                this.attachEvent(cell, 'click', fx, this);
                                cell.style.cursor = "pointer";
                            }

                            cell.className = inner_xml_[j].className;
                            in_cell += this.makeInnerHTML(inner_xml_[j].innerHTML_, item, key_value);
                        }

                    // command 'else', referenced to previous 'condition' instance
                    } else if (inner_xml_[j].conditionElse && condition) {
                        cond_else = !cond_if;
                        if (cond_else) {
                            if (inner_xml_[j].backgroundColor) cell.style.backgroundColor = this.fillRealValues(inner_xml_[j].backgroundColor, item);
                            if (inner_xml_[j].actionString) {
                                eval("var fx = function(event) {" + this.fillRealValues(inner_xml_[j].actionString, item) + "}");
                                this.attachEvent(cell, 'click', fx, this);
                                cell.style.cursor = "pointer";
                            }

                            cell.className = inner_xml_[j].className;
                            in_cell += this.makeInnerHTML(inner_xml_[j].innerHTML_, item, key_value);
                        }

                    // no command into XML tag
                    } else {
                        if (inner_xml_[j].backgroundColor) cell.style.backgroundColor = this.fillRealValues(inner_xml_[j].backgroundColor, item);
                        if (inner_xml_[j].actionString) {
                            eval("var fx = function(event) {" + this.fillRealValues(inner_xml_[j].actionString, item) + "}");
                            this.attachEvent(cell, 'click', fx, this);
                            cell.style.cursor = "pointer";
                        }

                        in_cell += this.makeInnerHTML(inner_xml_[j].innerHTML_, item, key_value);
                    }
                }
            }

            cell.innerHTML = (in_cell.length == 0) ? this.options.emptyContent : in_cell;
        }
    },

    makeInnerHTML: function(inner_html_, item, key_val) {
        if (!inner_html_ || !item) return null;
        var inner_html = (this.smallFont) ? "<small>" : "";

        for (var i=0; i<inner_html_.length; i++){

            // dataField replacement...
            if (isArray(inner_html_[i])){
                var cont = "";
                if (inner_html_[i].field && item.getElementsByTagName(inner_html_[i].field)[0]) cont = item.getElementsByTagName(inner_html_[i].field)[0].firstChild.nodeValue;

                if (trimString(cont) == ""){
                    cont = (inner_html_[i].empty) ? inner_html_[i].empty : this.options.emptyContent;
                } else {
                    if (inner_html_[i].truncate){
                        var trunc = parseInt(inner_html_[i].truncate);
                        trunc += (this.smallFont) ? this.addCharacters : 0;
                        cont = truncateString(cont, trunc, inner_html_[i].suffix, inner_html_[i].exact);
                    }
                    if (inner_html_[i].wrap){
                        var wrap = parseInt(inner_html_[i].wrap);
                        wrap += (this.smallFont) ? this.addCharacters : 0;
                        cont = wrapString(cont, wrap, inner_html_[i].suffix);
                    }
                }
                if (inner_html_[i].encode) cont = encodeHtml(cont);

                //custom_encode for js function argument
                if (inner_html_[i].custom_js_encode) cont = custom_js_encode(cont);


                inner_html += cont;

            // keyField replacement...
            } else {
                inner_html += inner_html_[i].replace(this.keyRegExp, key_val);
            }
        }

        inner_html += (this.smallFont) ? "</small>" : "";

        return inner_html;
    },

    splitInnerHTML: function(inner_html) {
        if (!inner_html) return null;

        // convert esc codes to solve <A href...> problem...
        if (inner_html.indexOf('href') != -1) {
            inner_html = inner_html.replace(/\%28/g, "(");
            inner_html = inner_html.replace(/\%29/g, ")");
        }

        // explode cell.innerHTML to array of cell content (exm: ID=(*:id*) will be explode to {'ID=', id, ''})
        var inner_html_ = inner_html.split(this.fieldRegExp);

        // create a field mask (field name, truncate size, suffix, truncate exact indicator, empty/default content, ...) for each "field" set...
        for (var i=0; i<inner_html_.length; i++){

            if (inner_html_[i].indexOf(':') == 0){
                var field_mask = new Array();
                var field_ = inner_html_[i].split('|');

                for (var n=0; n<field_.length; n++){
                    var tmp_arr = field_[n].split(':');
                    var sign    = isString(tmp_arr[1]) ? '"' : '';
                    if (tmp_arr[0] == '') tmp_arr[0] = 'field';
                    if (!tmp_arr[1] || tmp_arr[1] == 'true') tmp_arr[1] = true;
                    var fm_string = "field_mask." + tmp_arr[0] + " = " + sign + tmp_arr[1] + sign;
                    eval(fm_string.replace(/""/g, '"'));
                }
                inner_html_[i] = field_mask;
            }
        }
        return inner_html_;
    },

    fillKeyValue: function(str, key_val) {
        var r_str = str.replace(this.keyRegExp, key_val);
        return r_str;
    },

    fillRealValues: function(str, item) {
        var str_ = this.splitInnerHTML(str);
        var real_str = '';
        for (i=0; i<str_.length; i++){
            real_str += (str_[i].field == undefined) ? str_[i] : trimString(item.getElementsByTagName(str_[i].field)[0].firstChild.nodeValue);
        }
        return real_str;
    },

    sortDataGrid: function(sort, sort_ord) {
        var buf_sort = this.getState('sort');
        var buf_sort_ord = this.getState('sort_ord');

        if (sort != buf_sort){
            var cur_ico = $(this.id + "_col_" + buf_sort).getElementsByTagName("img")[0];
            cur_ico.style.visibility = 'hidden';
            sort_ord = 'desc';
        }

        var sort_elm = $(this.id + "_col_" + sort);
        var ico = sort_elm.getElementsByTagName("img")[0];
        var sort_ico = this.iconPath;
        sort_ico += (sort_ord == 'asc') ? this.iconSortAsc : this.iconSortDesc;
        ico.src   = sort_ico;
        ico.style.visibility = 'visible';

        sort_ord = (sort_ord == 'asc') ? 'desc' : 'asc';
        eval("var f = function() {this.sortDataGrid('" + sort + "', '" + sort_ord + "')}");
        this.attachEvent(sort_elm, 'click', f, this);

        this.setState('curr_page', 1);
        this.setState('sort', sort);
        this.setState('sort_ord', sort_ord);

        this.makeDataGrid();
    },

    pageNavi: function(curr_page, page_size) {
        curr_page = curr_page || this.currPage.value;
        this.setState('curr_page', curr_page);
        if (page_size) this.setState('page_size', page_size);

        this.makeDataGrid();
    },

    searchData: function(e, tpe) {
        if (tpe == 'M'){
            this.setState('curr_page', 1);
            this.setState('search', encodeEscChr(this.search.value));
            this.makeDataGrid();
        } else {
            var key = 0;
            if (e.keyCode) { key = e.keyCode; }
            else if (typeof(e.which) != 'undefined') { key = e.which; }

            if (key == 27) this.search.value = '';

            // enter or tab...
            if (key == 13 || key == 9) {
                this.setState('curr_page', 1);
                this.setState('search', encodeEscChr(this.search.value));
                this.makeDataGrid();
                this.search.focus();
                return false;
            }
        }
    },

    keyNavi: function(e) {
        var key = 0;
        if (e.keyCode) { key = e.keyCode; }
        else if (typeof(e.which) != 'undefined') { key = e.which; }

        // enter
        if (key == 13) {
            this.pageNavi($F(this.currPage));
        }
    },

    setFilter: function(flt) {
        if (flt && flt.substring(0, 1) == '&') { this.options.filter = flt };
    },

    setState: function(nme, val, mke) {
        mke = mke || false;
        this.state[nme] = val;
        if (mke) { this.makeDataGrid() };
    },

    getState: function(nme) {
        return this.state[nme];
    },

    mouseOver: function() {
        this.className = this.classOver;
    },

    mouseOut: function() {
        this.className = this.zebra > 0 ? this.classEven : this.classOdd;
    },

    selectGridRows: function(ind) {
        if (this.options.showRowSelection){
            this.tbody      = this.grid.getElementsByTagName('tbody')[0];
            var elms = this.tbody.getElementsByTagName('input');
            var row_pfx = this.id + '_row';

            for(var i=0; i<elms.length; i++) {
                elm = elms[i];
                if (elm.type == 'checkbox' && elm.name != null && elm.name.indexOf(row_pfx) >= 0){
                    elm.checked = (ind == 1) ? true : false;
                }
            }
        }
        this.prepChBox();
    },

    countGridRows: function() {
        var counter = 0;
        if (this.options.showRowSelection){
            this.tbody      = this.grid.getElementsByTagName('tbody')[0];
            var elms = this.tbody.getElementsByTagName('input');
            var row_pfx = this.id + '_row';

            for(var i=0; i<elms.length; i++) {
                elm = elms[i];
                if (elm.type == 'checkbox' && elm.name != null && elm.name.indexOf(row_pfx) >= 0 && elm.checked){
                    counter++;
                }
            }
        }
        return counter;
    },

    prepChBox: function() {
        var counter = this.countGridRows();
        if(counter > 0) {
            this.editGrid = true;
        } else {
            this.editGrid = false;
        }

        if(this.options.defaultAutoReload == 1) {
            if(this.editGrid) {
                this.autoReloadStatus.src = this.iconPath + 'autoreload_inactive.gif';
            } else {
                this.autoReloadStatus.src = this.iconPath + 'autoreload_active.gif';
            }
        }
    },

    setAutoReload: function(sec) {
        var ar_seconds = new Array(15, 30, 45, 60, 300, 600);
        var ar_set     = false;

        if (sec > 0 && sec != this.autoReload) ar_set = true;

        // 1st, clear time interval and decheck active option...
        for (i=0; i<ar_seconds.length; i++){
            var cfgElm = $(this.id + 'SetAR' + ar_seconds[i]);
            cfgElm.setAttribute('icon', 'empty.gif');

            if (this.intervalID){
                clearInterval(this.intervalID);
                this.intervalID = false;
                this.autoReload = 0;
            }
        }

        // then, set autoReload option and make datagrid...
        if (ar_set > 0){
            var outVar = this.options.outVar;
            this.intervalID = setInterval(function(){autoReloadDataGrid(outVar)}, sec * 1000);
            this.autoReload = sec;

            var cfgElm = $(this.id + 'SetAR' + this.autoReload);
            cfgElm.setAttribute('icon', 'checked.gif');
            if (this.autoReloadStatus) this.autoReloadStatus.src = this.iconPath + 'autoreload_active.gif';
        } else{
            if (this.autoReloadStatus) this.autoReloadStatus.src = this.iconPath + 'autoreload_inactive.gif';
        }
        this.makeDataGrid();
    }

});

/**
* AutoReload DataGrid object
* @note this function is used to reload datagrid on each 'n' seconds
*/
function autoReloadDataGrid(obj){
    var clas = eval(obj);
    if (obj) {
        if(clas.editGrid == false) {
            eval(obj + ".makeDataGrid()");
        }
    }
}

/**
* DialogBox class.
* @author Vladan Antic.
* @date 1.2007.
* @version 1.2.
* @note this creates a popUp element to display given content (HTML code, text, ...)
*/

DYNAX.DialogBox = Class.create();
DYNAX.DialogBox.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(title, options) {

        ++DYNAX_dBoxIndex;
        this.title     = title || 'Dialog Box';
        this.name      = 'dialogBox';
        this.id        = this.name + DYNAX_dBoxIndex;
        this.buttons   = Array();

        options = options || new Array();
        this.setOptions(options);
    },

    setOptions: function(options) {
        this.options = Object.extend({
            saveState: options.saveState ? options.saveState : false,
            dummyLayer: options.dummyLayer ? options.dummyLayer : true,
            dummyClose: options.dummyClose ? options.dummyClose : false,
            blurScreen: options.blurScreen ? options.blurScreen : false,
            draggable: options.draggable ? options.draggable : false,
            minimize: options.minimize ? options.minimize : false,
            className: options.className ? options.className : 'dialogBox',
            box_status: options.box_status ? options.box_status : 'close',
            appl: options.appl ? options.appl : '',
            gridInst: options.gridInst ? options.gridInst : '',
            left: options.left ? options.left : null,
            top: options.top ? options.top : null,
            width: options.width ? options.width : null,
            height: options.height ? options.height : null,
            closeFunction: options.closeFunction ? options.closeFunction : false
        }, options || {});
    },

    addButton: function(lbl, act, wd) {
        wd = wd || 65;
        this.buttons[this.buttons.length] = '<input type="button" class="button" value="' + lbl + '" onclick="' + act + '" style="width:' + wd + 'px;" />';
    },

    display: function(content) {
        content = content || '';

        // create dialogBox layer...
        window.ref2this = this;
        var dBox = this.iniLayer(this.id);
        dBox.index = this.index;
        dBox.className = this.options.className;
        dBox.onmousedown = function(){ window.ref2this.setActive(this) };

        var out = '';
        out += '<table id="' + this.id + 'Table" width="120" border="0" cellPadding="2" cellSpacing="1">';
        out += '<tr>';
        out += '<td id="' + this.id + 'Head" height="19" class="head" nowrap>';
        out += '<div id="' + this.id + 'Title" class="title"></div>';
        out += '<div class="icons">';
        if (this.options.minimize)
            out += '<img id="' + this.id + 'Minimize" src="' + this.iconPath + 'minimize.gif" style="padding-right: 2px; cursor: pointer;">';
        out += '<img id="' + this.id + 'Close" src="' + this.iconPath + 'close.gif" style="cursor: pointer;">';
        out += '</td>';
        out += '</tr>';
        out += '<tr>';
        out += '<td height="1" align="left" valign="top" class="main">';
        out += '<div id="' + this.id + 'Main"></div>';
        out += '<div id="' + this.id + 'Buttons" align="right" style="padding-top: 5px;"></div>';
        out += '</td>';
        out += '</tr>';
        out += '</table>';
        if (isIE) out += this.elmIframe;

        dBox.innerHTML = out;

        // attach actions to icons...
        if ($(this.id + 'Minimize')) this.attachEvent($(this.id + 'Minimize'), 'click', function(){this.minimizeBox()}, this);
        this.attachEvent($(this.id + 'Close'), 'click', function(){this.closeDialog()}, this);

        // set dragging...
        if (this.options.draggable){
            var dBoxHead = $(this.id + 'Head');
            dBoxHead.style.padding = '0 2 0 0';
            dBoxHead.style.cursor = 'move';
            this.attachEvent(dBoxHead, 'mousedown', function(event){this.handleMouseDown(event, this.id)}, this);
            this.attachEvent(dBoxHead, 'mouseup', function(){this.setState(this.id)}, this);
        }

        // fill dialogBox with a real content...
        $(this.id + 'Title').innerHTML = this.title;
        $(this.id + 'Main').innerHTML = content;

        var btns = '';
        for (i=0; i<this.buttons.length; i++)
            btns += this.buttons[i];
        $(this.id + 'Buttons').innerHTML = btns;

        var d_wd  = this.options.width || getElementWidth(this.id);
        var d_hi  = this.options.height || Element.getHeight(this.id);
        var y_new = Math.round(getWindowHeight()/2 + getWindowYOffset() - d_hi/2 - 30);
        if (isIE) y_new += this.body.scrollTop;
        if (y_new < 0) y_new = 1;

        // save state of the panel...
        if (this.options.saveState){
            var state = '';
            var cookieName = 'cookie_' + this.id;
            var cookieValue = this.getCookie(cookieName);
            if (cookieValue) state = cookieValue.split(';');
            this.options.top  = state[0] || this.options.top;
            this.options.left = state[1] || this.options.left;
        }

        $(this.id).style.left = (this.options.left || (getWindowWidth()/2 - d_wd/2) + this.body.scrollLeft) + 'px';
        $(this.id).style.top  = (this.options.top || y_new) + 'px';
        $(this.id).style.visibility = 'visible';
        $(this.id + 'Table').style.width = d_wd + 'px';

        // set the box as active...
        this.setActive(dBox);

        // dummyLayer...
        if (this.options.dummyLayer || this.options.blurScreen){
            DYNAX_dummyInd++;
            var dmy = this.setDummyLayer('DB', 80, this.options.blurScreen);

            if (this.options.dummyClose)
                this.attachEvent(dmy, 'mouseup', this.closeDialog, this);
        }
    },

    setActive: function(obj) {
        var idx = obj.id.replace(/[^0-9]/g, '');
        if (DYNAX_dBoxActive){
            var i = DYNAX_dBoxActive.id.replace(/[^0-9]/g, '');
            if ($(this.name + i)) {
                $(this.name + i + 'Head').className = "head_";
                $(this.name + i).style.zIndex    = "100";
            }
        }
        if ($(this.name + idx)) {
            $(this.name + idx + 'Head').className = "head";
            $(this.name + idx).style.zIndex    = "101";
        }

        DYNAX_dBoxActive = obj;
    },

    minimizeBox: function() {
        iObj = $(this.id + 'Minimize');
        if (iObj.src.indexOf('minimize') >= 0) {
            $(this.id + 'Main').style.display = "none";
            $(this.id + 'Buttons').style.display = "none";
            iObj.src = iObj.src.replace('minimize','maximize');
        } else {
            $(this.id + 'Main').style.display = "block";
            $(this.id + 'Buttons').style.display = "block";
            iObj.src = iObj.src.replace('maximize','minimize');
        }
    },

    closeDialog: function() {
        if(this.options.appl == 'greeting') {
            this.refreshHandling('close', this.options.gridInst, this.options.appl);
        }
        Element.remove(this.id);
        if (--DYNAX_dummyInd < 1) {
            this.unsetDummyLayer('DB');
            DYNAX_dBoxActive = false;
        }
        if (this.options.dummyClose) this.detachDummyEvent('DB', 'mouseup');
        if (this.options.closeFunction) eval(this.options.closeFunction + '()');
    },

    setState: function() {
        var top  = $(this.id).offsetTop;
        var left = $(this.id).offsetLeft;
        if (this.options.saveState) this.setCookie('cookie_' + this.id, top + ';' + left, 100000);
    }
});

/**
* DynamicList class.
* @author Vladan Antic.
* @date 1.2007.
* @version 1.1.
* @note
*/

DYNAX.DynamicList = Class.create();
DYNAX.DynamicList.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(url, options) {
        this.ajaxUrl = url;
        this.xml = null;

        this.id      = options.id ? options.id : 'dynamicList';
        this.idItem  = options.idItem ? options.idItem : 'dlOption';
        this.currentIndex = 0;
        this.listLength   = 0;
        this.timeoutID    = 0;  
        this.suggestList  = new Array();
        this.currentLetters = new Array();

        this.setOptions(options);

        this.dynList = this.iniLayer(this.id);
        if (isIE) this.iniIframe($(this.id));

        this.dynList.className = this.options.className;
        this.hidePopup();

        this.options.sourceElem.setAttribute('autocomplete', 'off');
        this.attachEvent(this.options.sourceElem, this.options.eventField, this.makeList, this);
        this.attachEvent(this.options.sourceElem, this.options.eventPopup, this.keyNavi, this);
        this.attachEvent(this.options.sourceElem, 'blur', this.emptyField, this);
    },

    setOptions: function(options) {
        this.options = Object.extend({
            sourceElem: $(options.source),
            targetElem: options.target ? $(options.target) : false,
            eventField: options.eventField ? options.eventField : 'keyup',
            className: options.className ? options.className : 'dynamicList',
            eventPopup: 'keydown',
            appendSeparator: options.appendSeparator || '#',
            appendValue: evalBoolean(options.appendValue),
            fillSource: options.fillSource ? options.fillSource : 'selection',
            minChars: options.minChars ? options.minChars : 1,
            maxItems: options.maxItems ? options.maxItems : 0,
            maxHeight: options.maxHeight ? options.maxHeight : 198,
            timeout: options.timeout ? options.timeout : 500
        }, options || {});

        this.cssOption = 'option';
        this.cssOver   = 'over';
    },

    makeList: function(e) {
        var key = 0;
        if (e.keyCode) { key = e.keyCode; }
        else if (typeof(e.which)!= 'undefined') { key = e.which; }

        var fieldLength = $F(this.options.sourceElem).length;

        if (fieldLength == 0 || fieldLength < this.options.minChars){
            this.dynList.innerHTML = '';
            this.hidePopup();
            statusMessage();

        } else if (key != 38 && key != 40 && key != 13 && key != 9 && key != 27 && key != 37 && key != 39 && key != 17 && key != 18) {
            this.setProgressStyle();

            var prms = arrayToParameterString(this.buildParameterString(this.options.parameters).split(','));
            if (this.options.maxItems > 0) prms += '&maxItems=' + this.options.maxItems;
            prms += '&utfDecode=no';

            // get ajax request...
            if(this.timeoutID != 0){
                try{
                    clearTimeout(this.timeoutID);
                }finally{
                    this.timeoutID = 0;
                }
            }
                       
            var _self = this;
            var f = function(){var ajax = new Ajax.Request(_self.ajaxUrl, {method: 'post',parameters: prms,onComplete: _self.setResult.bind(_self)});}
            this.timeoutID = setTimeout(f, this.options.timeout);
        }
    },

    setResult: function(request) {
        this.timeoutID = 0;
        this.xml = request.responseXML;
        this.dynList.innerHTML = '';
        this.hidePopup();

        this.listLength   = 0;
        this.currentIndex = 0;

        // grab xml of options...
        var respNode = this.xml.getElementsByTagName('response')[0];
        var items = respNode.getElementsByTagName('item');

        for (var i=0; i<items.length; i++) {
            var div = document.createElement('div');
            div.id = this.idItem + i;
            div.index = i;
            div.className = this.cssOption;
            div.onmouseover = this.handleOver.bindAsEventListener(this);
            div.onclick = this.handleClick.bindAsEventListener(this);
            if (this.options.targetElem)
                div.value = items[i].getElementsByTagName('value')[0].firstChild.nodeValue;
            div.innerHTML = items[i].getElementsByTagName('name')[0].firstChild.nodeValue;
            this.dynList.appendChild(div);

            // if number of max items is defined...
            if (this.options.maxItems > 0 && (i + 1) >= this.options.maxItems){
                i++;
                var div = document.createElement('div');
                div.className = this.cssOption;
                div.innerHTML = '-- more...';
                this.dynList.appendChild(div);
                break;
            }
        }

        this.listLength = i;

        if (this.listLength > 0){
            $(this.idItem + this.currentIndex).className = this.cssOver;
            Element.show(this.id);
            this.setPopupStyles();
        }

        statusMessage(respNode.getElementsByTagName('status')[0].firstChild.nodeValue);
    },

    keyNavi: function(e) {
        var key = 0;
        if (e.keyCode) { key = e.keyCode; }
        else if (typeof(e.which) != 'undefined') { key = e.which; }

        //up arrow
        if (key == 38) {
            if (this.currentIndex > 0) {
                $(this.idItem + this.currentIndex).className = this.cssOption;
                this.currentIndex--;
                $(this.idItem + this.currentIndex).className = this.cssOver
                $(this.idItem + this.currentIndex).scrollIntoView(false);
            }

        //down arrow
        } else if (key == 40) {
            if (this.currentIndex < this.listLength - 1) {
                $(this.idItem + this.currentIndex).className = this.cssOption;
                this.currentIndex++;
                $(this.idItem + this.currentIndex).className = this.cssOver
                $(this.idItem + this.currentIndex).scrollIntoView(false);
            }

        //enter
        } else if (key == 13 && this.dynList.style.display != 'none') {
            this.fillField($(this.idItem + this.currentIndex));
            Event.stop(e);
            this.executePostFunction();

        //tab
        } else if (key == 9) {
            this.hidePopup();

        //escape
        } else if (key == 27) {
            this.hidePopup();
            Event.stop(e);
        }
    },

    executePostFunction: function() {
        if (this.options.postFunction) {
            this.options.postFunction(this.xml);
        }
    },

    hidePopup: function() {
        this.resetProgressStyle();
        if ($(this.id)) {
            this.detachEvent(document.documentElement, 'click');
            Element.hide(this.id);
        }
        if (isIE && $('dummyFrame')) $('dummyFrame').style.display = 'none';
    },

    setProgressStyle: function() {
        if (this.options.progressStyle != null) {
          Element.addClassName(this.options.sourceElem, this.options.progressStyle);
        }
    },

    resetProgressStyle: function() {
        if (this.options.progressStyle != null) {
          Element.removeClassName(this.options.sourceElem, this.options.progressStyle);
        }
    },

    fillField: function(selection) {
        if (this.options.fillSource == 'selection') this.options.sourceElem.value = decodeHtml(selection.innerHTML);
        if (this.options.targetElem) {
            // fill source with target value (id, ...) to make a search...
            if (this.options.fillSource == 'target') this.options.sourceElem.value = selection.value;
            if (this.options.appendValue == 'false') {
                this.options.targetElem.value = selection.value;
            } else {
                if (this.options.targetElem.value.length > 0)
                    this.options.targetElem.value += this.options.appendSeparator;
                this.options.targetElem.value += selection.value;
            }
        }
        this.hidePopup();
    },

    emptyField: function() {
        if (this.options.sourceElem.value == "" || this.listLength < 1) {
            if (this.options.targetElem) this.options.targetElem.value = "";
            statusMessage();
        }
    },

    handleClick: function(e) {
        this.fillField(Event.element(e));
        this.executePostFunction();
    },

    handleOver: function(e) {
        $(this.idItem + this.currentIndex).className = this.cssOption;
        this.currentIndex = Event.element(e).index;
        $(this.idItem + this.currentIndex).className = this.cssOver;
    },

    setPopupStyles: function() {
        var elmPos = getPosition(this.options.sourceElem);
        var pxTop   = isOpera ? 5 : 0;
        var pxLeft  = isOpera ? 3 : isIE ? 1 : 0;

        if (this.dynList.offsetHeight < this.options.maxHeight) {
            this.dynList.style.overflow = 'hidden';
        } else if (isMoz) {
            this.dynList.style.maxHeight = this.options.maxHeight + 'px';
            this.dynList.style.overflow = '-moz-scrollbars-vertical';
        } else {
            this.dynList.style.height = this.options.maxHeight + 'px';
            if (isOpera) {
                this.dynList.style.overflow = 'auto';
            } else {
                this.dynList.style.overflowY = 'auto';
            }
        }

        this.dynList.scrollTop = 0;
        this.dynList.style.top = (elmPos.y + this.options.sourceElem.offsetHeight + pxTop + this.body.scrollTop) + "px";
        this.dynList.style.left = elmPos.x + pxLeft + this.body.scrollLeft + "px";

        if (isIE) {
            this.dynList.style.width = this.options.sourceElem.offsetWidth + "px";
        } else {
            this.dynList.style.minWidth = this.options.sourceElem.offsetWidth + "px";
        }

        if (isIE) {
            dmyF = $('dummyFrame');
            dmyF.style.top = (elmPos.y + this.options.sourceElem.offsetHeight) + "px";
            dmyF.style.left = elmPos.x + "px";
            dmyF.style.width = this.dynList.offsetWidth;
            dmyF.style.height = this.dynList.offsetHeight;
            dmyF.style.display = "block";
            dmyF.style.zIndex = 90;
        }
        this.attachEvent(document.documentElement, 'click', this.hidePopup, this);
    }
});

/**
* InfoPanel class.
* @author Vladan Antic.
* @date 1.2007.
* @version 1.0.
* @note
*/

DYNAX.InfoPanel = Class.create();
DYNAX.InfoPanel.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(id, options) {
        this.id = id;
        this.iconUp   = "up.gif";
        this.iconDown = "down.gif";

        this.infoPanels  = new Array();
        this.cookieNames = new Array();
        this.currExpandedPanel = false;
        this.expandedPanel = false;

        this.setOptions(options);

        $(this.id).style.width = this.options.panelWidth + 'px';
//        if (this.options.panelHeight) $(this.id).style.height = this.options.panelHeight + 'px';
    },

    setOptions: function(options) {
        this.options = Object.extend({
            panelWidth: options.panelWidth ? options.panelWidth : 200,
//            panelHeight: options.panelHeight ? options.panelHeight : 0,
            onlyOnePanel: options.onlyOnePanel ? options.onlyOnePanel : false,
            saveState: options.saveState ? options.saveState : true,
            classPanel: options.classPanel ? options.classPanel : 'infoPanel'
        }, options || {});
    },


    addPanel: function(id, state, width){
        var i = this.infoPanels.length;
        this.infoPanels[i] = [id, state, width];
    },

    infoPanel: function(){
        // get all panels...
        for(var no=0; no<this.infoPanels.length; no++){
            var panelId    = this.infoPanels[no][0];
            var panelState = this.infoPanels[no][1];
            var panelWidth = this.infoPanels[no][2];

            var tmpDiv     = $(panelId);
            var panelTitle = $(panelId).getAttribute("panelTitle");
            var content    = tmpDiv.innerHTML;
            tmpDiv.className  = this.options.classPanel;
            tmpDiv.innerHTML  = "";
            if (panelWidth) tmpDiv.style.width = panelWidth;

            // create content of a panel...
            var contDiv = document.createElement('DIV');
            contDiv.id  = this.id + 'Content' + no;
            contDiv.className = 'content';
            contDiv.innerHTML = content;

            // create topBar of a panel...
            var topBar = document.createElement('DIV');
            topBar.id  = this.id + 'TopBar' + no;
            topBar.className = "topBar";
            topBar.style.position = 'relative';
            window.ref2Panel = this;
            topBar.onclick = function(){ window.ref2Panel.showHideContent(this) };

            var span = document.createElement('SPAN');
            span.innerHTML = panelTitle;
            topBar.appendChild(span);

            var img = document.createElement('IMG');
            img.id = this.id + 'Icon' + no;

            // save state of the panel...
            if (this.options.saveState){
                var cookieName = 'cookie_' + panelId;
                var cookieValue = this.getCookie(cookieName);
                if (cookieValue) panelState = (cookieValue == 1) ? true : false;
                this.cookieNames[this.cookieNames.length] = cookieName;
            }
            if (this.options.onlyOnePanel && this.currExpandedPanel) panelState = false;

            // show/hide panel initially...
            if (panelState){
                this.currExpandedPanel = topBar;
                contDiv.style.display = 'block';
                img.src = this.iconPath + this.iconUp;
            } else {
                contDiv.style.display = 'none';
                img.src = this.iconPath + this.iconDown;
            }
            topBar.appendChild(img);

            tmpDiv.appendChild(topBar);
            tmpDiv.appendChild(contDiv);
        }
    },

    showHideContent: function(iObj){
        var img = iObj.getElementsByTagName('IMG')[0];
        var numericId = img.id.replace(/[^0-9]/g, '');
        var obj = document.getElementById(this.id + 'Content' + numericId);
        var state = '';

        if (img.src.toLowerCase().indexOf('up') >= 0){ // hide content...
            this.currExpandedPanel = false;
            img.src = img.src.replace('up','down');
            obj.style.display = 'none';
            state = '0';
        } else { // show content...
            if (iObj){
                if (this.currExpandedPanel && this.options.onlyOnePanel) this.showHideContent(this.currExpandedPanel);
                this.currExpandedPanel = iObj;
            }
            img.src = img.src.replace('down','up');
            obj.style.display = 'block';
            state = '1';
        }
        if (this.cookieNames[numericId]) this.setCookie(this.cookieNames[numericId], state, 100000);

        return true;
    }
});


/**
* MessageBox class.
* @author Vladan Antic.
* @date 2.2007.
* @version 1.1.
* @note messageBox will display a message in alert, error, info or warning style
*       this tool is based on DYNAX.DialogBox class
*/

DYNAX.MessageBox = Class.create();
DYNAX.MessageBox.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(message, type, options) {
        message = message || '';
        type = type || 'A';

        this.dbox = false;

        options = options || new Array();
        this.setOptions(options);

        var title  = '';
        var icon = '';
        var style = '';

        switch (type) {
        case 'E':
            title  = 'Error';
            icon = 'message_error.gif';
            style = 'style="color: #dd1100;"';
            break;
        case 'I':
            title  = 'Information';
            icon = 'message_info.gif';
            break;
        case 'W':
            title  = 'Warning';
            icon = 'message_warning.gif';
            break;
        default :
            title  = 'Alert';
            icon = 'message_alert.gif';
            break;
        }

        var out = '';
        out += '<table width="' + this.options.width + '" border="0" cellPadding="0" cellSpacing="0">';
        out += '<td height="70" align="left"><div id="messageBoxText"' + style + '>' + message + '</div>';
        out += '<div id="messageBoxIcon"><img src="' + this.imagePath + icon + '" border="0"></div>';
        out += '</td>';
        out += '</tr>';
        out += '<tr>';
        out += '<td align="center"><input type="button" id="messageButton" class="button" value="OK" style="width: 60px;"></td>';
        out += '</tr>';
        out += '</table>';

        this.dbox = new DYNAX.DialogBox(title, this.options);
        this.dbox.display(out);

        this.attachEvent($('messageButton'), 'click', this.closeMessage, this);
    },

    setOptions: function(options) {
        this.options = Object.extend({
            left: options.left ? options.left : null,
            top: options.top ? options.top : null,
            width: options.width ? options.width : 400,
            height: options.height ? options.height : null
        }, options || {});
    },

    closeMessage: function(){
        if (this.dbox)
            this.dbox.closeDialog()
    }

});


/**
* Tab Panel.
* @author Vladan Antic.
* @date 9.2007.
* @version 1.2
* @note this class will display a content into tabbed panels
* @note the fisrt tab couldn't be closed
* @version 1.3
* @note supported postFunction and condFunction (condition func.) which they are runing on Tab clicking
*       - if condFunction is defined, the tab will be opened only if condFunction returns "true"
*       - call function without parameters:     postFunction: doSomething
*       - call function with parameters:     condFunction: function () {return doSomething(1)}
*/

DYNAX.TabPanel = Class.create();
DYNAX.TabPanel.prototype = Object.extend(new DYNAX.Base(), {

    initialize: function(panel_id, options) {
        if (!panel_id) return false;

        this.panelId  = panel_id;
        this.tabPanel = $(panel_id);
        this.maxNumberOfTabs = 9;
        this.tabLength = 0;

        options = options || new Array();
        this.setOptions(options);

        // set the tabPanel
        this.tabPanel.className = 'tabPanel';

        // create a hidden field to save activeTab index, also needed in source files
        var hField   = document.createElement('INPUT');
        hField.type  = "hidden"
        hField.id    = this.panelId + 'ActiveTab';
        hField.name  = this.panelId + 'ActiveTab';
        hField.value = 0;
        this.tabPanel.appendChild(hField);
    },

    setOptions: function(options) {
        this.options = Object.extend({
            width: options.width ? options.width : null,
            height: options.height ? options.height : null,
            condFunction: options.condFunction ? options.condFunction : false,
            postFunction: options.postFunction ? options.postFunction : false
        }, options || {});
    },

    display: function() {
        // create tabGroup element
        var tabGroup = document.createElement('DIV');
        tabGroup.id = this.panelId + 'Group';
        tabGroup.className = 'tabGroup';

        // load content tabs...
        var tabDivs   = this.tabPanel.getElementsByTagName('div');
        var firstTab  = tabDivs[0];
        var tabIndex  = 0;
        var activeTab = this.getActiveTab();

        for (i=0; i<tabDivs.length; i++){
            if (tabDivs[i].getAttribute('name') == this.panelId && tabIndex <= this.maxNumberOfTabs){
                var tabTitle = tabDivs[i].getAttribute('title');
                tabTitle = tabTitle || 'Tab' + tabIndex;

                // create main part of the tab
                var divM = document.createElement('DIV');
                divM.id = this.panelId + 'Tab' + tabIndex;
                divM.className = 'tabInactive';
                divM.innerHTML = '<span>' + tabTitle + '</span>';

                // create right corner of the tab
                var divR = document.createElement('DIV');
                divR.id = this.panelId + 'TabR' + tabIndex;
                divR.className = 'tabInactiveR';
                divR.innerHTML = '<img src="images/1.gif">';

                // set content div
                tabDivs[i].id = this.panelId + 'Content' + tabIndex;;
                tabDivs[i].className = 'tabContent';
                tabDivs[i].style.width  = this.options.width;
                tabDivs[i].style.height = this.options.height;

                // attach tab action
                eval("window." + this.panelId + "ActTab = this");
                eval("divM.onclick = function(){window." + this.panelId + "ActTab.showTab('" + this.panelId + "', " + tabIndex + ", 1)}");
                eval("divR.onclick = function(){window." + this.panelId + "ActTab.showTab('" + this.panelId + "', " + tabIndex + ", 1)}");

                tabGroup.appendChild(divM);
                tabGroup.appendChild(divR);
                tabIndex++;
            }
        }

        tabIndex--;
        this.tabLength = tabIndex;

        // set active tab
        if (activeTab < 0 || activeTab > tabIndex){
            activeTab = 0;
        }

        this.tabPanel.insertBefore(tabGroup, firstTab);
        this.showTab(this.panelId, activeTab);
    },

    openTab: function(idx) {
        if (idx < 0 || idx > this.tabLength){
            return false;
        }

        this.showTab(this.panelId, idx);
        return true;
    },

    closeTab: function(idx) {
        if (idx < 1 || idx > this.tabLength){
            return false;
        }

        // close the tab
        var divM = $(this.panelId + 'Tab' + idx);
        var divR = $(this.panelId + 'TabR' + idx);
        divM.style.display = 'none';
        divR.style.display = 'none';

        this.showTab(this.panelId, 0);
        return true;
    },

    visibleTab: function(idx) {
        if (idx < 1 || idx > this.tabLength){
            return false;
        }

        // make the tab visible
        var divM = $(this.panelId + 'Tab' + idx);
        var divR = $(this.panelId + 'TabR' + idx);
        divM.style.display = 'block';
        divR.style.display = 'block';

        return true;
    },

    setWidth: function(width) {
        this.options.width = width;
    },

    setHeight: function(height) {
        this.options.height = height;
    },

    setActiveTab: function(idx) {
        $(this.panelId + 'ActiveTab').value = idx;
    },

    getActiveTab: function() {
        return $(this.panelId + 'ActiveTab').value;
    },

    showTab: function(elm, idx, indClick) {
        var showTab = false;

        if (indClick){
            if (this.options.condFunction) {
                if (this.options.condFunction()) showTab = true;
            } else {
                showTab = true;
            }
        } else {
            showTab = true;
        }

        if (showTab){
            var tabPanel = $(elm);
            var activeTab = $(elm + 'ActiveTab').value;

            // close opened tab...
            if (activeTab != idx && $(elm + 'Tab' + activeTab)){
                var divM = $(elm + 'Tab' + activeTab);
                var divR = $(elm + 'TabR' + activeTab);
                divM.className = 'tabInactive';
                divR.className = 'tabInactiveR';

                // attach tab action
                eval("window." + this.panelId + "ActTab = this");
                eval("divM.onclick = function(){window." + this.panelId + "ActTab.showTab('" + elm + "', " + activeTab + ", 1)}");
                eval("divR.onclick = function(){window." + this.panelId + "ActTab.showTab('" + elm + "', " + activeTab + ", 1)}");

                if (indClick) this.executePostFunction();

                var divC = $(elm + 'Content' + activeTab);
                divC.style.display = 'none';
            }

            // open needed tab
            if ($(elm + 'TabR' + idx)){
                var divM = $(elm + 'Tab' + idx);
                var divR = $(elm + 'TabR' + idx);
                divM.className = 'tabActive';
                divR.className = 'tabActiveR';
                divM.style.display = 'block';
                divR.style.display = 'block';

                this.detachEvent(divM, 'click');
                this.detachEvent(divR, 'click');

                var divC = $(elm + 'Content' + idx);
                divC.style.display = 'block';

                $(elm + 'ActiveTab').value = idx;
            }
        }
    },

    executePostFunction: function() {
        if (this.options.postFunction) this.options.postFunction();
    }
});

