var Famark = Famark || {};
Famark._changesNotSaved = 'Changes not saved.';
Famark._continuePrinting = 'Continue printing?';

Famark.pageLoad = function () {

    Famark._invalidFieldPrefix = 'invalid field: ';
    Famark._requiredFieldPrefix = 'required field: ';
    Famark._invalidFormatPrefix = 'invalid format: ';
    Famark._invalidFilterPrefix = 'invalid filter: ';
    Famark._invalidEntityPrefix = 'invalid entity: ';
    Famark._savedMessage = 'saved!';

    Famark._saveTitle = 'save (ctrl + enter)';
    Famark._saveAndNewTitle = 'save and new (ctrl + alt + enter)';
    Famark._saveAndCloseTitle = 'save and close (ctrl + shift + enter)';
    Famark._copyTitle = 'copy (ctrl + <)';
    Famark._pasteTitle = 'paste (ctrl + >)';
    Famark._printTitle = 'print (ctrl + :)';
    Famark._saveRecordBeforeUsingLookup = 'Save the record before using this lookup.\nClick OK to save.';

    Famark._lookupAddHTML = "<svg class='icon'><use href='Attachment/all-icons.svg#lookup-add'></use></svg>";
    Famark._lookupEditHTML = "<svg class='icon'><use href='Attachment/all-icons.svg#lookup-edit'></use></svg>";
    Famark._reqFields = [];
    Famark._reqFieldRules = [];
    Famark._formFields = [];
    Famark._default = {};
    Famark._record = {};
    Famark._buttons = [];
    Famark._preventCreateFields = [];
    Famark._preventUpdateFields = [];
    Famark._relatedEntityId = [];
    Famark._relatedEntityName = [];

    //Famark._divTools = document.getElementById('divTools');
    Famark._divData = document.getElementById('divData');
    Famark._messageLabel = document.getElementById('MessageLabel');

    Famark.initButton('btnSave', Famark._saveTitle, Famark.saveClicked, true, true);
    Famark.initButton('btnSNew', Famark._saveAndNewTitle, Famark.saveNewClicked, true, true);
    Famark.initButton('btnSClose', Famark._saveAndCloseTitle, Famark.saveCloseClicked, true, true);

    var rid = Famark._divData.getAttribute('data-rid');
    var isEdit = (rid != '');
    Famark.initButton('btnCopy', Famark._copyTitle, Famark.copyClicked, isEdit, false);
    Famark.initButton('btnPaste', Famark._pasteTitle, Famark.pasteClicked, !isEdit, true);
    Famark.initButton('btnPrint', Famark._printTitle, Famark.printClicked, isEdit, false);

    var ddSelector = document.getElementById('ddSelector');

    if (ddSelector != null) {
        ddSelector.value = Famark._divData.getAttribute('data-form');
        if (ddSelector.options.length < 2) {
            ddSelector.className = 'hidden';
        } else {
            ddSelector.onchange = function () {
                var entity = Famark._divData.getAttribute('data-entity');
                var key = entity + '.form.';
                Famark.setCookie(key, ddSelector.value, 60);
                var url = 'Form.ashx?entity=' + entity + '&form=' + ddSelector.value;
                if (isEdit)
                    url += '&rid=' + rid;
                window.location.replace(url);
            };
        }
    }

    Famark.addHandler(document, 'keyup', Famark.shortKey);
    Famark.addHandler(window, 'resize', Famark.screenLoad);
    Famark.addHandler(window, 'beforeunload', Famark.beforeUnload);
    Famark.screenLoad();

    Famark.initDateTimeFields();

    if (!Famark.loadDefault || !Famark.loadForm || !Famark.loadEventBindings) {
        alert('Error in form script.');
        return;
    }

    Famark.loadDefault();
    Famark.loadData();
    Famark.loadForm();
    Famark.loadEventBindings();
    window.setTimeout(function () { Famark.setDefaultFocus(); }, 200);
};

Famark.initButton = function(btnId, title, handler, show, save) {
    var btn = document.getElementById(btnId);
    if (btn != null) {
        btn.title = title;
        Famark.addHandler(btn, 'click', handler);
        if (!show)
            btn.style.display = 'none';
        if (save)
            Famark._buttons.push(btn);
    }
};
Famark.shortKey = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (!e.ctrlKey)
        return;
    var btn = null;
    if (e.keyCode == 13) {
        var btnId = e.shiftKey ? 'btnSClose' : (e.altKey ? 'btnSNew' : 'btnSave');
        btn = document.getElementById(btnId);
    } else if (e.keyCode == 188) {
        btn = document.getElementById('btnCopy');
    } else if (e.keyCode == 190) {
        btn = document.getElementById('btnPaste');
    } else if (e.keyCode == 186) {
        btn = document.getElementById('btnPrint');
    }

    if (btn != null && btn.disabled != true && btn.style.display != 'none') {
        btn.focus();
        btn.click();
    }
};
Famark._resizeTimeout = null;
Famark.screenLoad = function() {
    if (Famark._resizeTimeout)
        window.clearTimeout(Famark._resizeTimeout);
    Famark._resizeTimeout = window.setTimeout(function() {
        window.setTimeout(function() {
            Famark._divData.style.height = (document.body.clientHeight - Famark._divData.offsetTop) + 'px';
        }, 40);
        Famark._resizeTimeout = null;
    }, 100);
};
Famark.beforeUnload = function () {
    if (Famark._isWorking && Famark._preventUnloadMessage)
        return Famark._preventUnloadMessage;
    return undefined;
};
Famark.onFocusBlur = function (el, defVal) {
    Famark.addHandler(el, 'focus', function () {
        if (el.value == defVal)
            el.value = '';
    });
    Famark.addHandler(el, 'blur', function () {
        if (el.value == '')
            el.value = defVal;
    });
};
Famark.getDateValue = function (el) {
    if (el.value == '' || el.value == 'yyyy-mm-dd') {
        el.className = 'el';
        return '';
    }
    var comp = el.value.split('-');
    if (comp.length != 3) {
        el.className = 'elError';
        return null;
    }
    var y = parseInt(comp[0], 10);
    var m = parseInt(comp[1], 10) - 1;
    var d = parseInt(comp[2], 10);

    var dp = new Date(y, m, d);
    if (!isFinite(dp) || dp.getFullYear() != y || dp.getMonth() != m || dp.getDate() != d) {
        el.className = 'elError';
        return null;
    }
    el.className = 'el';
    return el.value;
};
Famark.getTimeValue = function(el) {
    if (el.value == '' || el.value == 'hh:mm AM') {
        el.className = 'el';
        return '';
    }
    var tp = el.value.replace(' ', ':').split(':');
    if (tp.length < 2 || tp.length > 3) {
        el.className = 'elError';
        return null;
    }
    var hh = parseInt(tp[0], 10);
    var mm = parseInt(tp[1], 10);
    if (isNaN(hh) || isNaN(mm)) {
        el.className = 'elError';
        return null;
    }
    if (hh < 0 || hh > 23 || mm < 0 || mm > 59) {
        el.className = 'elError';
        return null;
    }
    if (tp.length < 3) {
        el.className = 'el';
        return (hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm;
    }
    var ss = parseInt(tp[2], 10);
    if (!isNaN(ss)) {
        if (ss < 0 || ss > 59) {
            el.className = 'elError';
            return null;
        }
        el.className = 'el';
        return (hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm + ':' + (ss < 10 ? '0' : '') + ss;
    }
    var am = tp[2].toUpperCase();
    if (hh > 12 || (am != 'AM' && am != 'PM')) {
        el.className = 'elError';
        return null;
    }
    if (hh == 12)
        hh = 0;
    if (am == 'PM')
        hh += 12;

    el.className = 'el';
    return (hh < 10 ? '0' : '') + hh + ':' + (mm < 10 ? '0' : '') + mm;
};
Famark._tzVals = ['-12:00', '-11:00', '-10:00', '-09:30', '-09:00', '-08:00', '-07:00', '-06:00', '-05:00', '-04:30', '-04:00', '-03:30', '-03:00', '-02:00', '-01:00', '+00:00',
    '+01:00', '+02:00', '+03:00', '+03:30', '+04:00', '+04:30', '+05:00', '+05:30', '+05:45', '+06:00', '+06:30', '+07:00', '+08:00', '+08:45', '+09:00', '+09:30', '+10:00',
    '+10:30', '+11:00', '+11:30', '+12:00', '+12:45', '+13:00', '+14:00'];
Famark.initDateTime = function (el) {
    var wrapper = document.createElement('div');
    wrapper.id = 'dt_' + el.id.substring(3);
    el.parentNode.appendChild(wrapper);
    el.style.display = 'none';
    var dt = document.createElement('input');
    dt.setAttribute('type', 'date');
    dt.setAttribute('value', 'yyyy-mm-dd');
    dt.className = 'el';
    dt.style.width = '136px';
    dt.style.paddingRight = '2px';
    wrapper.appendChild(dt);
    Famark.onFocusBlur(dt, 'yyyy-mm-dd');
    var tm = document.createElement('input');
    tm.setAttribute('type', 'time');
    tm.setAttribute('value', 'hh:mm AM');
    tm.className = 'el';
    tm.style.width = '100px';
    tm.style.paddingRight = '2px';
    wrapper.appendChild(tm);
    Famark.onFocusBlur(tm, 'hh:mm AM');
    var tz = document.createElement('select');
    for (var i = 0; i < Famark._tzVals.length; i++) {
        var op = document.createElement('option');
        op.innerHTML = Famark._tzVals[i];
        op.value = Famark._tzVals[i];
        tz.appendChild(op);
    }
    Famark.setTimezone(tz, Famark.getTimezone());
    tz.className = 'el';
    tz.style.width = '64px';
    tz.style.paddingLeft = '0';
    tz.style.paddingRight = '0';
    tz.style.verticalAlign = 'bottom';
    tz.style.fontSize = '0.8em';
    wrapper.appendChild(tz);

    function setEmpty(txdt) {
        if (txdt.value == '')
            return null;
        txdt.value = '';
        Famark.triggerChange(txdt);
        return null;
    }

    function getDateTimePart(txdt, dPart, tPart) {
        var datePart = Famark.getDateValue(dPart);
        var timePart = Famark.getTimeValue(tPart);
        if (datePart == null || timePart == null || (datePart == '' && timePart == ''))
            return setEmpty(txdt);

        if (datePart == '' && timePart != '') {
            dt.className = 'elError';
            return setEmpty(txdt);
        }

        if (datePart != '' && timePart == '') {
            tm.className = 'elError';
            return setEmpty(txdt);
        }

        if (timePart.length < 6)
            timePart += ':00';
        return datePart + 'T' + timePart;
    }

    var onDateTimeChange = function () {
        var dateTime = getDateTimePart(el, dt, tm);
        if (dateTime == null)
            return;
        var dp = dateTime.replace(/[T:]/g, '-').split('-');
        var obj = new Date(dp[0], dp[1] - 1, dp[2], dp[3], dp[4], dp[5]);
        Famark.setTimezone(tz, Famark.getTimezone(obj));
        var newDate = Famark.getDateFromIso(dateTime + tz.value);
        var newVal = Famark.getIsoString(newDate);
        if (el.value != newVal) {
            el.value = newVal;
            Famark.triggerChange(el);
        }
    };

    var onTimeZoneChange = function () {
        var dateTime = getDateTimePart(el, dt, tm);
        if (dateTime == null)
            return;
        var newDate = Famark.getDateFromIso(dateTime + tz.value);
        var newVal = Famark.getIsoString(newDate);
        if (el.value != newVal) {
            el.value = newVal;
            Famark.triggerChange(el);
        }
    };

    Famark.addHandler(dt, 'change', onDateTimeChange);
    Famark.addHandler(tm, 'change', onDateTimeChange);
    Famark.addHandler(tz, 'change', onTimeZoneChange);
};
Famark.initDateTimeFields = function () {
    if (!document.querySelectorAll)
        return;
    var i, len;
    var dateTimes = document.querySelectorAll('input[data-datetime="datetime"]');
    len = dateTimes.length;
    if (len > 0 && dateTimes[0].type != 'datetime') {
        for (i = 0; i < len; i++)
            Famark.initDateTime(dateTimes[i]);
    }
    var dates = document.querySelectorAll('input[data-datetime="date"]');
    len = dates.length;
    if (len > 0 && dates[0].type != 'date') {
        for (i = 0; i < len; i++) {
            var dt = dates[i];
            dt.value = 'yyyy-mm-dd';
            Famark.onFocusBlur(dt, 'yyyy-mm-dd');
            Famark.addHandler(dt, 'change', function () {
                Famark.getDateValue(dt);
            });
        }
    }
    var times = document.querySelectorAll('input[data-datetime="time"]');
    len = times.length;
    if (len > 0 && times[0].type != 'time') {
        for (i = 0; i < len; i++) {
            var tm = times[i];
            tm.value = 'hh:mm AM';
            Famark.onFocusBlur(tm, 'hh:mm AM');
            Famark.addHandler(tm, 'change', function () {
                Famark.getTimeValue(tm);
            });
        }
    }
};
Famark.loadData = function () {
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    var rid = Famark._divData.getAttribute('data-rid');

    if (rid == '') { //Add
        Famark.setAllFieldValues(fields, Famark._default, true);
        if (!Famark._hasCreateAccess)
            Famark.disableSaveAction(true);
        Famark.disableFields(Famark._preventCreateFields);
        var spnCaptcha = document.getElementById('spnCaptcha');
        if (spnCaptcha != null && spnCaptcha.firstChild != null)
            Famark.refreshCaptcha(spnCaptcha.firstChild.id);
        return;
    }

    if (!Famark._hasUpdateAccess)
        Famark.disableSaveAction(true);

    if (rid.indexOf(',') > 0) {
        for (var r = 0; r < Famark._reqFields.length; r++) {
            var label = document.getElementById('lb_' + Famark._reqFields[r]);
            var lastPos = label.innerHTML.length - 1;
            if (label.innerHTML[lastPos] == '*')
                label.innerHTML = label.innerHTML.substring(0, lastPos);
        }

        Famark.disableFields(Famark._preventUpdateFields);
        return;
    }

    var entity = Famark._divData.getAttribute('data-entity');
    var url = 'Data.ashx?entity=' + entity + '&rid=' + rid + '&columns=*';
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();

    var result = Famark.parseJSON(http.responseText);

    if (result.ErrorMessage == null || result.ErrorMessage == '') {
        for (var i = 0; i < result.Output.Fields.length; i++)
            Famark._record[result.Output.Fields[i].Key] = result.Output.Fields[i].Value;

        Famark.setAllFieldValues(fields, Famark._record, false);
        if (Famark._lookupDisplayField != '') {
            var display = Famark._record[Famark._lookupDisplayField];
            if (display != null)
                document.title = Famark.getLookupDisplay(display) + ' › ' + document.title;
        }

        if (Famark._solutionLockedEntityFields)
            Famark.solutionLockDisableFields(entity, rid);
    } else {
        Famark._messageLabel.innerHTML = result.ErrorMessage;
        Famark._messageLabel.className = 'errorMessageLabel';
        if (Famark._messageLabel.offsetWidth > Famark._divData.offsetWidth)
            Famark.adjustErrorLabel(Famark._messageLabel, Famark._divData.offsetWidth);
    }

    Famark.disableFields(Famark._preventUpdateFields);
};
Famark.getLookupDisplay = function (display) {
    var formattedDisplay = null;

    var el = document.getElementById('el_' + Famark._lookupDisplayField);
    if (el != null) {
        var dtType = el.getAttribute('data-datetime');
        if (dtType != null && display != '') {
            formattedDisplay = Famark.getDisplayDateTime(dtType, display);
        } else if (el.nodeName == 'SELECT') {
            for (var o = 0; o < el.options.length; o++) {
                if (el.options[o].value == display) {
                    formattedDisplay = el.options[o].text;
                    break;
                }
            }
        }
    }

    if (formattedDisplay == null) {
        if (display == null)
            return '';
        if (typeof display != 'string')
            return display.toString();
        formattedDisplay = display;
    }
    
    return formattedDisplay.replace(/&/g, '&amp;').replace(/\>/g, '&gt;').replace(/\</g, '&lt;');
};
Famark.hideSaveAction = function (isHidden) {
    var display = (isHidden === undefined || isHidden) ? 'none' : '';
    for (var i = 0; i < Famark._buttons.length; i++)
        Famark._buttons[i].style.display = display;
};
Famark.disableSaveAction = function (isDisabled) {
    isDisabled = (isDisabled === undefined || isDisabled);

    for (var i = 0; i < Famark._buttons.length; i++)
        Famark._buttons[i].disabled = isDisabled;
};
Famark.setAllFieldValues = function (fields, values, isModify) {
    var field, value;
    for (var i = 0; i < fields.length; i++) {
        field = fields[i].getAttribute('data-field');
        value = values[field];
        if (field != null && value != null)
            Famark.setValue(field, value, isModify);
    }
    Famark._isWorking = false;
    Famark._preventUnloadMessage = null;
};
Famark.setWorking = function (isWorking) {
    if (isWorking === undefined || isWorking) {
        Famark._isWorking = true;
        Famark._preventUnloadMessage = Famark._changesNotSaved;
    } else {
        Famark._isWorking = false;
        Famark._preventUnloadMessage = null;
    }
};
Famark.makeSelect = function (field, options) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    if (el.nodeName == 'SELECT')
        return;
    
    if (el.nodeName != 'INPUT') {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    
    var sel = document.createElement('select');
    sel.id = el.id;
    sel.className = el.className;
    sel.onchange = el.onchange;
    var attrs = ['pattern', 'placeholder', 'data-custom', 'data-datetime'];
    for (var i = 0; i < attrs.length; i++) {
        var atVal = el.getAttribute(attrs[i]);
        if (atVal != null)
            sel.setAttribute(attrs[i], atVal);
    }
    var parent = el.parentNode;
    parent.removeChild(el);
    parent.appendChild(sel);
    for (i = 0; i < options.length; i++) {
        var op = document.createElement('option');
        op.text = options[i];
        op.value = options[i];
        sel.appendChild(op);
    }
};
Famark.makePassword = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.nodeName != 'INPUT') {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    el.type = 'password';
};
Famark.setDefaultFocus = function () {
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    for (var i = 0; i < fields.length; i++) {
        var field = fields[i].getAttribute('data-field');
        if (Famark.setFocus(field))
            return;
    }
};
Famark.setFocus = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return false;
    }

    var tx = document.getElementById('tx_' + field);
    var pt = document.getElementById('pt_' + field);
    var focusField;
    if (tx != null)
        focusField = tx;
    else if (pt != null)
        focusField = pt;
    else
        focusField = el;

    if (focusField.disabled)
        return false;

    focusField.focus();
    return true;
};
Famark.solutionLockDisableFields = function (entity, rid) {
    var solId = (entity.toUpperCase() == 'SYSTEM_SOLUTION') ? rid : Famark._record['SolutionId'];
    if (solId == null || solId == '')
        return;

    var url = 'Data.ashx?entity=System_Solution&rid=' + solId + '&columns=IsLocked';
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();
    var result = Famark.parseJSON(http.responseText);
    if (result.Output != null && result.Output.Fields != null && result.Output.Fields.length > 0) {
        if (result.Output.Fields[0].Value) {
            for (var i = 0; i < Famark._solutionLockedEntityFields.length; i++)
                Famark.setDisabled(Famark._solutionLockedEntityFields[i], true);
        }
    }
};
Famark.adjustErrorLabel = function (el, max) {
    var fullContent = el.innerHTML.replace(/'/g, "\"").replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r");
    var btn = "<input type='button' value='...' style='width:30px;' onclick='alert(\"" + fullContent + "\");'/>";
    var content = el.innerHTML;
    max = max - 30;
    while (el.offsetWidth > max) {
        var cut = (el.offsetWidth - max) / 10;
        if (cut <= 0) {
            el.innerHTML = content + btn;
            break;
        }
        content = content.substring(0, content.length - cut);
        el.innerHTML = content + btn;
    }
};
Famark.getModifiedData = function () {
    var modified = Famark._divData.getAttribute('data-modified');
    if (modified == null || modified == '')
        return null;

    var fields = modified.split(',');
    var data = '';
    for (var i = 0; i < fields.length; i++)
        data += fields[i] + '=' + Famark.getValue(fields[i]).toString().replace(/&/g, '&&') + '&';
    data = data.substring(0, data.length - 1);
    return data;
};
Famark.copyClicked = function () {
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    var field, data = '';
    for (var i = 0; i < fields.length; i++) {
        field = fields[i].getAttribute('data-field');
        if (field != null)
            data += '&' + field + '=' + window.encodeURIComponent(Famark.getValue(field));
    }
    if (window.top.Famark != null) {
        window.top.Famark.clipboardData = data;
        window.top.Famark.clipboardEntity = Famark._divData.getAttribute('data-entity');
    }
};
Famark.pasteClicked = function () {
    if (window.top.Famark != null && window.top.Famark.clipboardData != null && window.top.Famark.clipboardData != '') {
        var sourceEntity = window.top.Famark.clipboardEntity;
        var dataFields = window.top.Famark.clipboardData.split('&');
        for (var i = 0; i < dataFields.length; i++) {
            var eqPos = dataFields[i].indexOf('=');
            var field = dataFields[i].substr(0, eqPos);
            field = Famark.getMappedField(sourceEntity, field);
            if (field == null || field == '')
                continue;
            var value = dataFields[i].substr(eqPos + 1);
            value = window.decodeURIComponent(value);
            if (value == '' || value == '********')
                continue;
            var el = document.getElementById('el_' + field);
            if (el != null && Famark.getValue(field) == '') {
                Famark.setValue(field, value, true);
                Famark.triggerChange(el);
            }
        }
    }
};
Famark.getMappedField = function (sourceEntity, sourceField) {
    return sourceField;
};
Famark.setFootprint = function (text) {
    var spnFootprint = document.getElementById('spnFootprint');
    if (spnFootprint != null)
        spnFootprint.setAttribute('data-footprint', text);
};
Famark.getFootprint = function () {
    var spnFootprint = document.getElementById('spnFootprint');
    if (spnFootprint != null)
        return spnFootprint.getAttribute('data-footprint');
    return null;
};
Famark.setPrintTemplate = function (url, options) {
    var spnFootprint = document.getElementById('spnFootprint');
    if (spnFootprint != null) {
        spnFootprint.setAttribute('data-winUrl', url);
        if (options != null)
            spnFootprint.setAttribute('data-winOptions', options);
    }
};
Famark.getPrintTemplate = function () {
    var spnFootprint = document.getElementById('spnFootprint');
    if (spnFootprint != null) {
        var template = {};
        template.url = spnFootprint.getAttribute('data-winUrl');
        template.options = spnFootprint.getAttribute('data-winOptions');
        return template;
    }
    return null;
};
Famark.printClicked = function () {
    var spnFootprint = document.getElementById('spnFootprint');
    if (spnFootprint == null) {
        window.print();
        return true;
    }
    var url = spnFootprint.getAttribute('data-winUrl');
    if (url == null || url == '') {
        window.print();
        return true;
    }
    var rid = Famark._divData.getAttribute('data-rid');
    if (rid == null || rid == '') {
        alert(Famark._changesNotSaved);
        return false;
    }
    if (Famark._isWorking) {
        if (!confirm(Famark._changesNotSaved + '\r\n' + Famark._continuePrinting))
            return false;
    }
    url += url.indexOf('?') > -1 ? '&' : '?';
    url += 'id=' + rid;
    var ops = spnFootprint.getAttribute('data-winOptions');
    if (ops == null)
        ops = '';
    var printWindow = window.open(url, "printWindow", ops, true);
    printWindow.focus();
    return false;
};
Famark.saveClicked = function () {
    var rid = Famark._divData.getAttribute('data-rid');

    if (rid.indexOf(',') < 0 && !Famark.validateRequired())
        return false;
    if (!Famark.validateFormat())
        return false;

    Famark._messageLabel.innerHTML = '';

    if (!Famark.savingRecord) {
        alert('Error in form script.');
        return false;
    }

    var proceed = Famark.savingRecord();
    if (proceed !== undefined && !proceed)
        return false;

    var data = Famark.getModifiedData();
    if (data == null)
        return true;

    if (rid == '') {
        data = 'entity=' + Famark._divData.getAttribute('data-entity') +
            '&work=CreateRecord&data=' + window.encodeURIComponent(data);
    }
    else {
        data = 'entity=' + Famark._divData.getAttribute('data-entity') +
            '&work=UpdateRecord&rid=' + rid + '&data=' + window.encodeURIComponent(data);
    }

    var http = new XMLHttpRequest();
    http.open('POST', 'Work.ashx', false);
    http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    http.send(data);
    var result = Famark.parseJSON(http.responseText);

    if (result.ErrorMessage == null || result.ErrorMessage == '') {
        Famark._messageLabel.innerHTML = Famark._savedMessage;
        Famark._messageLabel.className = 'successMessageLabel';
        var entity = Famark._divData.getAttribute('data-entity');
        if (rid == '') {
            rid = result.Output;
            Famark._divData.setAttribute('data-rid', rid);
            if (window.top.Famark != null && window.top.Famark.formRecordCreated != null)
                window.top.Famark.formRecordCreated(entity, rid, data);

            if (Famark._lookupDisplayField != '') {
                var el = document.getElementById('el_' + Famark._lookupDisplayField);
                if (el != null) {
                    var url = 'Data.ashx?entity=' + entity + '&rid=' + rid + '&columns=' + Famark._lookupDisplayField;
                    http.open("GET", url, false);
                    http.send();
                    result = Famark.parseJSON(http.responseText);
                    if (result.ErrorMessage != null && result.ErrorMessage != '') {
                        alert(result.ErrorMessage);
                    } else {
                        el.value = result.Output.Fields[0].Value;
                    }

                    document.title = Famark.getLookupDisplay(el.value) + ' › ' + document.title;
                    if (document.onTitleChange)
                        document.onTitleChange();
                }
            }

            var divCaptcha = document.getElementById('divCaptcha');
            if (divCaptcha != null)
                divCaptcha.parentNode.removeChild(divCaptcha);

            var btnCopy = document.getElementById('btnCopy');
            if (btnCopy != null)
                btnCopy.style.display = 'inline-block';
            var btnPaste = document.getElementById('btnPaste');
            if (btnPaste != null)
                btnPaste.style.display = 'none';
            var btnPrint = document.getElementById('btnPrint');
            if (btnPrint != null)
                btnPrint.style.display = 'inline-block';
        }
        else {
            if (window.top.Famark != null && window.top.Famark.formRecordUpdated != null)
                window.top.Famark.formRecordUpdated(entity, rid, data);
        }

        if (!Famark._hasUpdateAccess)
            Famark.disableSaveAction(true);

        Famark.disableFields(Famark._preventUpdateFields);

        Famark._divData.setAttribute('data-modified', '');
        Famark._isWorking = false;
        Famark._preventUnloadMessage = null;
        return true;
    }

    Famark._messageLabel.innerHTML = result.ErrorMessage;
    Famark._messageLabel.className = 'errorMessageLabel';
    if (Famark._messageLabel.offsetWidth > Famark._divData.offsetWidth)
        Famark.adjustErrorLabel(Famark._messageLabel, Famark._divData.offsetWidth);
    return false;
};
Famark.saveNewClicked = function () {
    if (Famark.saveClicked()) {
        var i;
        Famark._messageLabel.innerHTML = '';
        Famark._divData.setAttribute('data-rid', '');

        if (Famark._solutionLockedEntityFields) {
            for (i = 0; i < Famark._solutionLockedEntityFields.length; i++)
                Famark.setDisabled(Famark._solutionLockedEntityFields[i], false);
        }

        Famark.disableSaveAction(!Famark._hasCreateAccess);

        Famark.enableFields(Famark._preventUpdateFields);

        var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
        var field;
        for (i = 0; i < fields.length; i++) {
            field = fields[i].getAttribute('data-field');
            if (field != null) {
                Famark.setValue(field, null, false);
                Famark.setVisible(field, true);
                Famark.setDisabled(field, false);
            }
        }

        var titSep = document.title.lastIndexOf(' › ');
        if (titSep >= 0) {
            document.title = document.title.substring(titSep + 3);
            if (document.onTitleChange)
                document.onTitleChange();
        }
        Famark.setAllFieldValues(fields, Famark._default, true);
        Famark.disableFields(Famark._preventCreateFields);
        if (Famark.loadForm)
            Famark.loadForm();

        var btnCopy = document.getElementById('btnCopy');
        if (btnCopy != null)
            btnCopy.style.display = 'none';
        var btnPaste = document.getElementById('btnPaste');
        if (btnPaste != null)
            btnPaste.style.display = 'inline-block';
        var btnPrint = document.getElementById('btnPrint');
        if (btnPrint != null)
            btnPrint.style.display = 'none';
        Famark.setDefaultFocus();
    }
};
Famark.saveCloseClicked = function () {
    if (Famark.saveClicked())
        Famark.closeFormWindow();
};
Famark.closeFormWindow = function () {
    if (window.top.Famark != null && window.top.Famark.closeWindow != null)
        window.top.Famark.closeWindow(window);
    else
        window.close();
};
Famark.setFormHeight = function (val) {
    if (window.top.Famark != null && window.top.Famark.getWindow != null) {
        window.setTimeout(function () {
            var win = window.top.Famark.getWindow(window);
            if (win != null)
                win.setContentHeight(val);
        }, 500);
    }
};
Famark.validateRequired = function () {

    var isValid = true;
    var missing = '';
    var firstField = null;
    for (var i = 0; i < Famark._reqFields.length; i++) {
        var reqFieldName = Famark._reqFields[i];
        var reqField = document.getElementById('el_' + reqFieldName);
        var label = document.getElementById('lb_' + reqFieldName);
        var tx = document.getElementById('tx_' + reqFieldName);
        var pc = document.getElementById('pc_' + reqFieldName);

        var reqVal = (reqField.isRichInput !== undefined && reqField.isRichInput != null) ? reqField.getRichValue() : reqField.value;

        if (reqVal == '') {
            var reqFieldRule = Famark._reqFieldRules[i];
            if (reqFieldRule) {
                var reqFieldRuleFields = reqFieldRule.replace(/^\|+|\|+$/g, '').split('|');
                var isRuleValid = false;
                for (var j = 0; j < reqFieldRuleFields.length; j++) {
                    var reqRuleFieldName = reqFieldRuleFields[j];
                    var reqRuleFieldValue = Famark.getValue(reqRuleFieldName);
                    if (reqRuleFieldValue !== null && reqRuleFieldValue !== '') {
                        isRuleValid = true;
                        break;
                    }
                }

                if (isRuleValid) {
                    label.className = 'lb';
                    if (tx != null)
                        tx.className = 'tx';
                    else if (pc != null)
                        pc.className = 'pipeContainer';
                    else
                        reqField.className = 'el';
                    continue;
                }
            }

            label.className = 'lbError';

            if (tx != null)
                tx.className = 'elError';
            else if (pc != null)
                pc.className = 'pipeContainerError';
            else
                reqField.className = 'elError';

            missing += label.innerHTML + ', ';

            if (firstField == null) {
                if (tx != null)
                    firstField = tx;
                else if (pc != null)
                    firstField = document.getElementById('pt_' + reqFieldName);
                else
                    firstField = reqField;
            }
            isValid = false;
        }
        else {
            label.className = 'lb';
            if (tx != null)
                tx.className = 'tx';
            else if (pc != null)
                pc.className = 'pipeContainer';
            else
                reqField.className = 'el';
        }
    }

    if (!isValid) {
        missing = missing.substr(0, missing.length - 2);
        Famark._messageLabel.innerHTML = Famark._requiredFieldPrefix + missing;
        Famark._messageLabel.className = 'errorMessageLabel';
        if (firstField != null && firstField.disabled == false)
            firstField.focus();
    }

    return isValid;
};
Famark.validateFormat = function () {
    var isValid = true;
    var wrong = '';
    var firstField = null;

    function setError(el, lb) {
        el.className = 'elError';
        lb.className = 'lbError';
        wrong += lb.innerHTML + ', ';
        if (firstField == null)
            firstField = el;
        isValid = false;
    }

    var isBulkEdit = (Famark.getFormMode() == 'BULK-EDIT');
    
    for (var i = 0; i < Famark._formFields.length; i++) {
        var formField = document.getElementById('el_' + Famark._formFields[i]);
        if (isBulkEdit && formField.value == '')
            continue;
        
        var label = document.getElementById('lb_' + Famark._formFields[i]);
        var dtType = formField.getAttribute('data-datetime');
        if (dtType != null) {
            Famark.validateDateTime(formField, label, dtType, setError);
            continue;
        }
        var format = formField.getAttribute('pattern');
        var pattern = new RegExp(format);
        var matchResult = formField.value.match(pattern);
        if (matchResult == null) {
            setError(formField, label);
            continue;
        }
        formField.className = 'el';
        label.className = 'lb';
    }
    
    if (!isValid) {
        wrong = wrong.substr(0, wrong.length - 2);
        Famark._messageLabel.innerHTML = Famark._invalidFormatPrefix + wrong;
        Famark._messageLabel.className = 'errorMessageLabel';
        if (firstField != null && firstField.disabled == false)
            firstField.focus();
    }

    return isValid;
};
Famark.validateDateTime = function (formField, label, dtType, setError) {
    if (dtType == 'date') {
        if (Famark.getDateValue(formField) == null)
            setError(formField, label);
        else
            label.className = 'lb';
        return;
    }
    if (dtType == 'time') {
        if (Famark.getTimeValue(formField) == null)
            setError(formField, label);
        else
            label.className = 'lb';
        return;
    }
    if (dtType == 'datetime') {
        var wrapper = document.getElementById('dt_' + formField.id.substring(3));
        if (wrapper == null)
            return;
        var datePart = Famark.getDateValue(wrapper.childNodes[0]);
        var timePart = Famark.getTimeValue(wrapper.childNodes[1]);
        if (datePart == null || (datePart == '' && timePart != '')) {
            setError(wrapper.childNodes[0], label);
            return;
        }
        if (timePart == null || (datePart != '' && timePart == '')) {
            setError(wrapper.childNodes[1], label);
            return;
        }
        label.className = 'lb';
    }
};
Famark.setCookie = function (key, value, minutes) {
    value = window.escape(value);
    if (minutes != null) {
        var now = new Date();
        now.setMinutes(now.getMinutes() + minutes);
        value += '; expires=' + now.toUTCString();
    }
    document.cookie = key + '=' + value;
};
Famark.addHandler = function (el, ev, fn) {
    if (el.addEventListener)
        el.addEventListener(ev, fn, false);
    else if (el.attachEvent)
        el.attachEvent('on' + ev, fn);
    else
        el[ev] = fn;
};
Famark.parseJSON = function (data) {
    if (data == null || typeof data !== 'string')
        return null;

    data = (data.trim) ? data.trim() : data.replace(/^\s+|\s+$/g, '');

    if (window.JSON && window.JSON.parse) {
        try {
            return window.JSON.parse(data);
        } catch (e) {
            alert('Invalid JSON: ' + data);
            return null;
        }
    }
    var valData = data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
    valData = valData.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
    valData = valData.replace(/(?:^|:|,)(?:\s*\[)+/g, '');

    var valExp = /^[\],:{}\s]*$/;

    if (valExp.test(valData))
        return (new Function('return ' + data))();

    alert('Invalid JSON: ' + data);
    return null;
};
Famark.toJSON = function (obj) {
    if (obj == null)
        return 'null';

    if (window.JSON && window.JSON.stringify)
        return window.JSON.stringify(obj);

    function quote(string) {
        var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
            meta = {
                '\b': '\\b',
                '\t': '\\t',
                '\n': '\\n',
                '\f': '\\f',
                '\r': '\\r',
                '"': '\\"',
                '\\': '\\\\'
            };

        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string' ? c :
                '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }

    function str(key, holder) {
        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            partial,
            value = holder[key];

        if (value && typeof value === 'object' && typeof value.toJSON === 'function')
            value = value.toJSON(key);

        switch (typeof value) {
            case 'string':
                return quote(value);
            case 'number':
                return isFinite(value) ? String(value) : 'null';
            case 'boolean':
            case 'null':
                return String(value);
            case 'object':
                if (!value)
                    return 'null';

                partial = [];
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    length = value.length;
                    for (i = 0; i < length; i += 1) {
                        partial[i] = str(i, value) || 'null';
                    }

                    v = partial.length === 0 ? '[]' : '[' + partial.join(',') + ']';
                    return v;
                }

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + ':' + v);
                        }
                    }
                }

                v = partial.length === 0 ? '{}' : '{' + partial.join(',') + '}';
                return v;
        }

        return 'null';
    }

    return str('', { '': value });
};

Famark.getElementsByClassName = function (cName, tName, node) {
    var els = [];
    var tmp, i;

    tName = tName || '*';
    node = node || document;

    if (node.getElementsByClassName) {
        tmp = node.getElementsByClassName(cName);
        for (i = 0; i < tmp.length; i++)
            els.push(tmp[i]);
    }
    else {
        var pattern = new RegExp('\\b' + cName + '\\b');
        tmp = node.getElementsByTagName(tName);
        for (i = 0; i < tmp.length; i++) {
            if (pattern.test(tmp[i].className))
                els.push(tmp[i]);
        }
    }

    return els;
};
Famark.onModify = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target != null) {
        var fieldName = target.id.substr(3, target.id.length - 3);
        Famark.setModified(fieldName);
    }
};
Famark.setModified = function (field) {
    var modifiedFields = Famark._divData.getAttribute('data-modified');
    var currentValue = ',' + modifiedFields + ',';
    if (currentValue.indexOf(',' + field + ',') < 0) {
        if (modifiedFields.length > 0)
            modifiedFields += ',';
        modifiedFields += field;
        Famark._divData.setAttribute('data-modified', modifiedFields);
    }
    Famark._isWorking = true;
    Famark._preventUnloadMessage = Famark._changesNotSaved;
};
Famark.setRequired = function (field, val, rule) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    var i;
    var lb = document.getElementById('lb_' + field);
    var disp = (lb != null) ? lb.innerHTML : null;

    if (val == null || val == true) {
        for (i = 0; i < Famark._reqFields.length; i++) {
            if (Famark._reqFields[i] == field) {
                Famark._reqFieldRules[i] = rule;
                return;
            }
        }

        Famark._reqFields.push(field);
        Famark._reqFieldRules.push(rule);

        if (disp != null && lb != null) {
            if (disp[disp.length - 1] == '*' || disp[disp.length - 1] == '`')
                disp = disp.substring(0, disp.length - 1);

            lb.innerHTML = disp + (rule == null ? '*' : '`');
        }
    }
    else {
        for (i = 0; i < Famark._reqFields.length; i++) {
            if (Famark._reqFields[i] == field) {
                Famark._reqFields.splice(i, 1);
                Famark._reqFieldRules.splice(i, 1);

                if (disp != null && lb != null && (disp[disp.length - 1] == '*' || disp[disp.length - 1] == '`'))
                    lb.innerHTML = disp.substring(0, disp.length - 1);
                return;
            }
        }
    }
};
Famark.setPattern = function (field, pattern) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    var i;
    if (pattern == null || pattern == false) {
        el.removeAttribute('pattern');
        for (i = 0; i < Famark._formFields.length; i++) {
            if (Famark._formFields[i] == field) {
                Famark._formFields.splice(i, 1);
            }
        }
    }
    else {
        el.setAttribute('pattern', pattern);
        for (i = 0; i < Famark._formFields.length; i++) {
            if (Famark._formFields[i] == field)
                return;
        }
        Famark._formFields.push(field);
    }
};
Famark.setPlaceHolder = function (field, placeHolder) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    if (placeHolder == null || placeHolder == false)
        el.removeAttribute('placeholder');
    else
        el.setAttribute('placeholder', placeHolder);
    
    var tx = document.getElementById('tx_' + field);
    if (tx != null) {
        if (placeHolder == null || placeHolder == false)
            tx.removeAttribute('placeholder');
        else
            tx.setAttribute('placeholder', placeHolder);
    }

    var lb = document.getElementById('lb_' + field);
    if (lb != null) {
        if (placeHolder == null || placeHolder == false)
            lb.removeAttribute('title');
        else
            lb.setAttribute('title', placeHolder);
    }
};
Famark.setConnection = function (el, conFields) {
    conFields = conFields.split(',');
    var relatedEntity = null;
    for (var j = 0; j < Famark._relatedEntityId.length; j++) {
        if (el.value == Famark._relatedEntityId[j]) {
            relatedEntity = Famark._relatedEntityName[j];
            break;
        }
    }
    if (relatedEntity == null && el.value != '') {
        var url = 'Data.ashx?entity=System_Entity&rid=' + el.value + '&columns=SystemName';
        var http = new XMLHttpRequest();
        http.open("GET", url, false);
        http.send();
        var result = Famark.parseJSON(http.responseText);
        if (result.Output == null || result.Output.Fields == null || result.Output.Fields.length == 0) {
            if (result.ErrorMessage != null && result.ErrorMessage != '')
                alert(result.ErrorMessage);
            else
                alert(Famark._invalidEntityPrefix + el.options[el.selectedIndex].text);
        } else {
            relatedEntity = result.Output.Fields[0].Value;
            if (relatedEntity === '********') {
                alert(Famark._invalidEntityPrefix + relatedEntity);
                relatedEntity = null;
            } else {
                Famark._relatedEntityId.push(el.value);
                Famark._relatedEntityName.push(relatedEntity);
            }
        }
    }
    relatedEntity = relatedEntity || '';
    for (var i = 0; i < conFields.length; i++) {
        var conEl = document.getElementById('el_' + conFields[i]);
        if (conEl != null)
            conEl.setAttribute('data-lookup', relatedEntity);

        var conTx = document.getElementById('tx_' + conFields[i]);
        if (conTx != null) {
            conTx.setAttribute('data-lookup', relatedEntity);
            if (conTx.value != '')
                conTx.className = 'elError';
        }
    }
};
Famark.onLookupKeyDown = function (e) {
    e = e || window.event;
    if (e.keyCode != 9)
        return;
    
    var target = e.target || e.srcElement;
    var highlightClass = 'highlightlookuprow';
    var field = target.id.substring(3);
    var dd = document.getElementById('dd_' + field);
    var el = document.getElementById('el_' + field);
    var rows, i;
    if (dd.style.display == 'none' || dd.firstChild == null)
        return;
    rows = dd.getElementsByTagName('tr');
    for (i = 0; i < rows.length; i++) {
        if (rows[i].className == highlightClass) {
            target.value = rows[i].firstChild.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
            el.value = rows[i].id;
            return;
        }
    }

    el.value = target.value = '';
    return;
};
Famark.onLookupKeyUp = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    var highlightClass = 'highlightlookuprow';
    var field = target.id.substring(3);
    var dd = document.getElementById('dd_' + field);
    var el = document.getElementById('el_' + field);
    var txlu = document.getElementById('txlu_' + field);

    var rows, i;
    if (e.keyCode == 13) {
        if (dd.style.display == 'none' || dd.firstChild == null)
            return;
        rows = dd.getElementsByTagName('tr');
        for (i = 0; i < rows.length; i++) {
            if (rows[i].className == highlightClass) {
                target.value = rows[i].firstChild.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
                el.value = rows[i].id;
                txlu.innerHTML = Famark._lookupEditHTML;
                return;
            }
        }

        el.value = target.value = '';
        txlu.innerHTML = Famark._lookupAddHTML;
        return;
    }

    if (e.keyCode == 40) {
        if (dd.firstChild == null)
            return;
        rows = dd.getElementsByTagName('tr');
        for (i = 0; i < rows.length - 1; i++) {
            if (rows[i].className == highlightClass) {
                rows[i].className = null;
                rows[i + 1].className = highlightClass;
                return;
            }
        }
        return;
    }

    if (e.keyCode == 38) {
        if (dd.firstChild == null)
            return;
        rows = dd.getElementsByTagName('tr');
        for (i = 1; i < rows.length; i++) {
            if (rows[i].className == highlightClass) {
                rows[i].className = null;
                rows[i - 1].className = highlightClass;
                return;
            }
        }
        return;
    }

    if (e.ctrlKey) {
        if (e.keyCode == 222) {
            Famark.openLookupForm(field);
            return;
        }
        if (e.keyCode == 191) {
            Famark.openLookupSelect(field);
            return;
        }
    }

    if (e.keyCode == 9 || e.keyCode == 16 || e.keyCode == 17 || e.keyCode == 91 || ((e.ctrlKey || e.metaKey) && (e.keyCode == 65 || e.keyCode == 67)))
        return;

    el.value = '';
    txlu.innerHTML = Famark._lookupAddHTML;
    window.setTimeout(function () {
        while (dd.childNodes.length > 0)
            dd.removeChild(dd.lastChild);

        var relatedEntity = target.getAttribute('data-lookup');

        if (target.value == '' || relatedEntity == '')
            return;

        var url = 'View.ashx?entity=' + relatedEntity +
                    '&mode=Lookup&root=Table&pageSize=4&pageIndex=0' +
                    '&search=' + window.encodeURIComponent(target.value);
        var filter = el.getAttribute('data-filter');
        if (filter != null && filter != '')
            url += '&filter=' + window.encodeURIComponent(filter);

        var http = new XMLHttpRequest();
        http.open("GET", url, false);
        http.send();
        var data = document.createElement('div');
        data.innerHTML = http.responseText;
        data = data.firstChild;
        dd.appendChild(data);
        dd.style.display = '';
        dd.scrollIntoView(false);
        rows = dd.getElementsByTagName('tr');
        if (rows.length > 0)
            rows[0].className = highlightClass;
    }, 20);
};
Famark.onLookupFocus = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    var field = target.id.substring(3);
    var el = document.getElementById('el_' + field);
    el.oldValue = el.value;
};
Famark.onLookupBlur = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;

    var field = target.id.substring(3);
    var dd = document.getElementById('dd_' + field);
    var el = document.getElementById('el_' + field);
    var txlu = document.getElementById('txlu_' + field);

    window.setTimeout(function () {
        if (target.value == '') {
            el.value = '';
            target.className = 'tx';
            txlu.innerHTML = Famark._lookupAddHTML;
        } else if (el.value == '') {
            target.className = 'elError';
            txlu.innerHTML = Famark._lookupAddHTML;
        } else {
            target.className = 'tx';
            txlu.innerHTML = Famark._lookupEditHTML;
        }
        dd.style.display = 'none';
        if (el.oldValue !== el.value)
            Famark.triggerChange(el);
    }, 500);
};
Famark.onLookupClick = function (e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    while (target.nodeName != 'TR' && target.nodeName != 'DIV')
        target = target.parentNode;
    if (target.nodeName != 'TR')
        return;
    var row = target;
    var dd = target.parentNode;
    while (dd.nodeName != 'DIV')
        dd = dd.parentNode;
    var field = dd.id.substring(3);
    var tx = document.getElementById('tx_' + field);
    var el = document.getElementById('el_' + field);
    var txlu = document.getElementById('txlu_' + field);
    tx.value = row.firstChild.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
    el.value = row.id;
    txlu.innerHTML = Famark._lookupEditHTML;
    window.setTimeout(function () {
        dd.style.display = 'none';
        if (el.oldValue !== el.value)
            Famark.triggerChange(el);
    }, 500);
};
Famark.showRelatedLookup = function (relatedEntity, filterKey, control, callback) {
    var formInfo = Famark.getFormInfo();
    if ((formInfo.recordId == '' || Famark._isWorking)
        && confirm(Famark._saveRecordBeforeUsingLookup) && Famark.saveClicked())
        formInfo = Famark.getFormInfo();

    if (formInfo.recordId != '') {
        var url = 'view.ashx?entity=' + relatedEntity + '&mode=Related&filter=' + window.encodeURIComponent(filterKey + '=' + formInfo.recordId);
        var win = Famark.showLookupWindow(url);
        win.opener = control;
        win.closing = callback;
    }
};
Famark.applyRecordFilter = function (field, recordFilterKey) {
    var formInfo = Famark.getFormInfo();
    if ((formInfo.recordId == '' || Famark._isWorking)
        && confirm(Famark._saveRecordBeforeUsingLookup) && Famark.saveClicked())
        formInfo = Famark.getFormInfo();

    if (formInfo.recordId != '') {
        Famark.setFilter(field, recordFilterKey + "=" + formInfo.recordId);
        return true;
    }
    return false;
};
Famark.openLookupForm = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    var relatedEntity = el.getAttribute('data-lookup');
    if (relatedEntity == null || relatedEntity == '')
        return;

    var tx = document.getElementById('tx_' + field);
    if (tx == null || tx.disabled || tx.readOnly)
        return;

    var recordFilterKey = el.getAttribute('data-record-filter-key');
    if (recordFilterKey != null && recordFilterKey != '' && !Famark.applyRecordFilter(field, recordFilterKey))
        return;

    var txlu = document.getElementById('txlu_' + field);

    var url = 'Form.ashx?entity=' + relatedEntity + '&tools=selector,sclose';
    function onFormSave(entity, rid) {
        if (relatedEntity == entity) {
            el.value = rid;
            txlu.innerHTML = Famark._lookupEditHTML;
            Famark.setLookupText(entity, rid, tx);
            if (el.oldValue !== el.value)
                Famark.triggerChange(el);
            Famark.fadeIn(tx);
        }
    }

    if (el.value == '') {
        var filter = el.getAttribute('data-filter');
        if (filter != null && filter != '')
            url += '&preset=' + window.encodeURIComponent(filter);
        Famark.formRecordCreated = onFormSave;
    } else {
        url += '&rid=' + el.value;
        Famark.formRecordUpdated = onFormSave;
    }

    var win = Famark.showLookupWindow(url);
    win.opener = tx;
    win.closing = function () {
        Famark.formRecordCreated = null;
        Famark.formRecordUpdated = null;
    };
};
Famark.openLookupSelect = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    var relatedEntity = el.getAttribute('data-lookup');
    if (relatedEntity == null || relatedEntity == '')
        return;

    var tx = document.getElementById('tx_' + field);
    if (tx == null || tx.disabled || tx.readOnly)
        return;

    var recordFilterKey = el.getAttribute('data-record-filter-key');
    if (recordFilterKey != null && recordFilterKey != '' && !Famark.applyRecordFilter(field, recordFilterKey))
        return;

    var txlu = document.getElementById('txlu_' + field);

    var url = 'View.ashx?entity=' + relatedEntity + '&mode=Select&tools=add,edit,del,prop,ref,selector,search,count,header,pick';
    var filter = el.getAttribute('data-filter');
    if (filter != null && filter != '')
        url += '&filter=' + window.encodeURIComponent(filter);
    Famark.viewRecordPicked = function (entity, rid) {
        if (relatedEntity == entity) {
            el.value = rid;
            txlu.innerHTML = Famark._lookupEditHTML;
            Famark.setLookupText(entity, rid, tx);
            if (el.oldValue !== el.value)
                Famark.triggerChange(el);
            Famark.fadeIn(tx);
        }
    };
    var win = Famark.showLookupWindow(url);
    win.opener = tx;
    win.closing = function () {
        Famark.viewRecordPicked = null;
    };
};
Famark.showLookupWindow = function (url) {
    var win = window.top.Famark.showWindow(url);
    var control = Famark.getElementsByClassName('btnWinOut', 'div', win);
    if (control.length > 0)
        control[0].style.display = 'none';
    control = Famark.getElementsByClassName('btnWinMin', 'div', win);
    if (control.length > 0)
        control[0].style.display = 'none';
    return win;
};
Famark.focusSave = function () {
    if (Famark._buttons.length > 0)
        Famark._buttons[0].focus();
};
Famark.fadeIn = function (el) {
    var op = 0.1;
    var timer = setInterval(function () {
        if (op >= 1) {
            clearInterval(timer);
        }
        el.style.opacity = op;
        el.style.filter = 'alpha(opacity=' + op * 100 + ")";
        op += op * 0.1;
    }, 20);
};
Famark.setLookupText = function(entity, rid, tx) {
    var url = 'Data.ashx?entity=' + entity + '&rid=' + rid + '&columns=!';
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();
    var result = Famark.parseJSON(http.responseText);
    if (result.Output == null || result.Output.Fields == null || result.Output.Fields.length == 0) {
        if (result.ErrorMessage != null && result.ErrorMessage != '')
            tx.value = result.ErrorMessage;
        else
            tx.value = rid;
        tx.className = 'elError';
    } else {
        tx.value = result.Output.Fields[0].Value;
        if (tx.value === '********')
            tx.style.backgroundColor = '#dddddd';
    }
};
Famark.triggerChange = function (el) {
    var evt;
    if (document.createEvent) {
        // dispatch for firefox + others
        evt = document.createEvent("HTMLEvents");
        evt.initEvent('change', true, true); // event type,bubbling,cancelable
        return el.dispatchEvent(evt);
    }
    else {
        // dispatch for IE
        evt = document.createEventObject();
        return el.fireEvent('onchange', evt);
    }
};
Famark.setLabel = function (field, label) {
    var lb = document.getElementById('lb_' + field);
    if (lb == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    lb.innerHTML = label.replace(/&/g, '&amp;').replace(/\>/g, '&gt;').replace(/\</g, '&lt;');
};
Famark.setValue = function (field, val, setModify) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    val = (val == null) ? '' : val.toString();

    var elType = el.type;

    if (elType == 'checkbox')
        el.checked = (val.toUpperCase() == 'TRUE');
    else if (elType == 'date')
        el.value = val.indexOf('T') < 0 ? val : val.substr(0, val.indexOf('T'));
    else if (elType == 'time')
        el.value = val.substr(val.indexOf('T') + 1, 8);
    else
        el.value = val;

    if (el.getAttribute('data-custom') != null)
        return;

    if (val === '********')
        el.style.backgroundColor = '#dddddd';

    if (setModify === undefined || setModify)
        Famark.setModified(field);

    if (elType != 'text' && elType != 'textarea' && elType != 'select-one')
        return;

    var relatedEntity = el.getAttribute('data-lookup');
    if (relatedEntity != null) {
        var tx = document.getElementById('tx_' + field);
        var txlu = document.getElementById('txlu_' + field);

        if (val == '') {
            tx.value = '';
            txlu.innerHTML = Famark._lookupAddHTML;
            return;
        }

        txlu.innerHTML = Famark._lookupEditHTML;

        if (val === '********') {
            tx.value = '********';
            tx.style.backgroundColor = '#dddddd';
            return;
        }

        Famark.setLookupText(relatedEntity, val, tx);
        return;
    }

    var dtType = el.getAttribute('data-datetime');
    if (dtType != null) {
        Famark.setDateTimeValue(el, dtType);
        return;
    }

    var conFields = el.getAttribute('data-connection');
    if (conFields != null) {
        Famark.setConnection(el, conFields);
        return;
    }

    if (elType != 'textarea')
        return;

    if (el.isPiped !== undefined && el.isPiped != null) {
        el.setPipeList();
        return;
    }

    if (el.isHtmlDisp !== undefined && el.isHtmlDisp != null) {
        el.setHtmlDisplay();
        return;
    }

    if (el.isRichInput !== undefined && el.isRichInput != null)
        el.setRichValue();
};
Famark.setDateTimeValue = function (el, dtType) {
    var val = el.value;
    var tPos = val.indexOf('T');
    var cName;

    if (dtType == 'date') {
        if (val == '') {
            el.value = 'yyyy-mm-dd';
            return;
        }
        if (val === '********')
            return;
        cName = el.className;
        if (tPos > -1)
            el.value = val.substr(0, tPos);
        if (Famark.getDateValue(el) == null)
            el.value = 'yyyy-mm-dd';
        el.className = cName;
        return;
    }
    if (dtType == 'time') {
        if (val == '') {
            el.value = 'hh:mm AM';
            return;
        }
        if (val === '********')
            return;
        cName = el.className;
        if (tPos > -1)
            val = val.substr(tPos + 1, 8);
        var tp = val.split(':');
        el.value = Famark.getDisplayTime(parseInt(tp[0], 10), parseInt(tp[1], 10));
        if (Famark.getTimeValue(el) == null)
            el.value = 'hh:mm AM';
        el.className = cName;
        return;
    }
    if (dtType == 'datetime') {
        var wrapper = document.getElementById('dt_' + el.id.substring(3));
        var dateEl = wrapper.childNodes[0];
        var timeEl = wrapper.childNodes[1];
        var zoneEl = wrapper.childNodes[2];
        if (val == '') {
            dateEl.value = 'yyyy-mm-dd';
            timeEl.value = 'hh:mm AM';
            zoneEl.value = Famark.getTimezone();
            return;
        }
        if (val === '********') {
            dateEl.value = '********';
            dateEl.style.backgroundColor = '#dddddd';
            timeEl.value = '********';
            timeEl.style.backgroundColor = '#dddddd';
            zoneEl.value = Famark.getTimezone();
            return;
        }
        var dt = Famark.getDateFromIso(val);
        if (!isFinite(dt)) {
            dateEl.value = 'yyyy-mm-dd';
            timeEl.value = 'hh:mm AM';
            zoneEl.value = Famark.getTimezone();
            return;
        }

        var year = dt.getFullYear();
        var month = dt.getMonth() + 1;
        var date = dt.getDate();
        dateEl.value = year + '-' + (month < 10 ? '0' : '') + month + '-' + (date < 10 ? '0' : '') + date;
        var hours = dt.getHours();
        var mins = dt.getMinutes();
        if (timeEl.type == 'time')
            timeEl.value = (hours < 10 ? '0' : '') + hours + ':' + (mins < 10 ? '0' : '') + mins + ':00';
        else
            timeEl.value = Famark.getDisplayTime(hours, mins);
        Famark.setTimezone(zoneEl, Famark.getTimezone(dt));
    }
};
Famark.getValue = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return null;
    }

    if (el.type == 'checkbox')
        return el.checked;

    var dtType = el.getAttribute('data-datetime');
    if (dtType != null)
        return Famark.getIsoDateTime(dtType, el);

    if (el.isRichInput !== undefined && el.isRichInput != null)
        return el.getRichValue();
    
    return el.value;
};
Famark.getDateFromIso = function (s) {
    var day = new Date('1980-12-21T15:25:00+05:30');
    if (isFinite(day) && day.getTime() === 346240500000)
        return new Date(s);
    var tz,
        rx = /^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
        p = rx.exec(s) || [];
    if (!p[1])
        return NaN;
    day = p[1].split(/\D/);
    for (var i = 0; i < day.length; i++)
        day[i] = parseInt(day[i], 10) || 0;
    day[1] -= 1;
    day = new Date(Date.UTC.apply(Date, day));
    if (!day.getDate())
        return NaN;
    if (p[5]) {
        tz = (parseInt(p[5], 10) * 60);
        if (p[6]) tz += parseInt(p[6], 10);
        if (p[4] == '+') tz *= -1;
        if (tz) day.setUTCMinutes(day.getUTCMinutes() + tz);
    }
    return day;
};
Famark.getIsoString = function (dt) {
    function pad(num) { return (num < 10) ? '0' + num : num; };
    return dt.getUTCFullYear() + '-' + pad(dt.getUTCMonth() + 1) + '-' + pad(dt.getUTCDate()) +
    'T' + pad(dt.getUTCHours()) + ':' + pad(dt.getUTCMinutes()) + ':' + pad(dt.getUTCSeconds()) + 'Z';
};
Famark.getIsoDateTime = function (dtType, el) {
    if (el.value == '' || dtType == 'datetime')
        return el.value;
    var cName = el.className;
    if (dtType == 'date') {
        var datePart = Famark.getDateValue(el);
        el.className = cName;
        return (datePart == null || datePart == '') ? '' : datePart + 'T00:00:00Z';
    }
    if (dtType == 'time') {
        var timePart = Famark.getTimeValue(el);
        el.className = cName;
        return (timePart == null || timePart == '') ? '' : '1900-01-01T' + timePart + (timePart.length < 6 ? ':00Z' : 'Z');
    }
    return null;
};
Famark.getDisplayTime = function (hh, mm) {
    var tt = hh > 11 ? 'PM' : 'AM';
    hh = ((hh + 11) % 12) + 1;
    return hh + ':' + (mm < 10 ? '0' : '') + mm + ' ' + tt;
};
Famark.getDisplayDateTime = function (dtType, val) {
    if (val === '********')
        return val;
    function f2D(c, x) { return x < 10 ? c + '0' + x : c + x; }
    var dt = Famark.getDateFromIso(val);
    if (dtType == 'date')
        return dt.getFullYear() + f2D('-', dt.getMonth() + 1) + f2D('-', dt.getDate());
    if (dtType == 'time')
        return Famark.getDisplayTime(dt.getHours(), dt.getMinutes());
    return dt.getFullYear() + f2D('-', dt.getMonth() + 1) + f2D('-', dt.getDate()) + ' ' + Famark.getDisplayTime(dt.getHours(), dt.getMinutes());
};
Famark.resetOptions = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.nodeName != 'SELECT') {
        alert(Famark._invalidFieldPrefix + field);
        return null;
    }
    el.options.length = 0;
    el.addOption = function (text, value) {
        var op = document.createElement('option');
        op.innerHTML = text;
        op.value = value;
        el.appendChild(op);
        return op;
    };
    var op1 = el.addOption('', '');
    op1.selected = true;
    return el;
};
Famark.refreshCaptcha = function (tid) {
    var img = document.getElementById(tid);
    if (img == null)
        return;
    var imgSrc = img.src;
    var rPos = imgSrc.indexOf('&r=');
    if (rPos > 0)
        imgSrc = imgSrc.substring(0, rPos);
    img.src = imgSrc + '&r=' + Math.random();
};
Famark.getCurrencyLabel = function () {
    return '(' + Famark._currency + ')';
};
Famark.getFormMode = function () {
    var rid = Famark._divData.getAttribute('data-rid');
    return (rid == null || rid == '') ? 'ADD' : rid.indexOf(',') < 0 ? 'EDIT' : 'BULK-EDIT';
};
Famark.getFormInfo = function () {
    var rid = Famark._divData.getAttribute('data-rid');
    var formInfo = {};
    formInfo.formMode = (rid == null || rid == '') ? 'ADD' : rid.indexOf(',') < 0 ? 'EDIT' : 'BULK-EDIT';
    formInfo.entityName = Famark._divData.getAttribute('data-entity');
    formInfo.formName = Famark._divData.getAttribute('data-form');
    formInfo.recordId = rid;
    formInfo.preset = Famark._divData.getAttribute('data-preset');
    return formInfo;
};
Famark.setDisabled = function (field, isTrue) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    el.disabled = (isTrue === undefined || isTrue);

    var tx = document.getElementById('tx_' + field);
    if (tx != null) {
        tx.disabled = el.disabled;
        return;
    }
    var dt = document.getElementById('dt_' + field);
    if (dt != null) {
        dt.childNodes[0].disabled = el.disabled;
        dt.childNodes[1].disabled = el.disabled;
        dt.childNodes[2].disabled = el.disabled;
        return;
    }
    if (el.isPiped !== undefined && el.isPiped != null) {
        el.disablePipeList(el.disabled);
        return;
    }
    if (el.isHtmlDisp !== undefined && el.isHtmlDisp != null) {
        el.disableHtmlDisplay(el.disabled);
        return;
    }
    if (el.isRichInput !== undefined && el.isRichInput != null)
        el.disableRichInput(el.disabled);
};
Famark.setBackgroundColor = function (field, color) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    
    color = color || '#fff';
    
    el.style.backgroundColor = color;

    var tx = document.getElementById('tx_' + field);
    if (tx != null)
        tx.style.backgroundColor = color;
};
Famark.disableAllFields = function (exceptFields, color) {
    var dataFields = Famark.getDataFields(exceptFields);
    Famark.disableFields(dataFields, color);
};
Famark.enableAllFields = function (exceptFields, color) {
    var dataFields = Famark.getDataFields(exceptFields);
    Famark.enableFields(dataFields, color);
};
Famark.getDataFields = function (exceptFields) {
    var isNotExceptField;
    if (exceptFields != null && exceptFields.length > 0) {
        isNotExceptField = function (f) {
            for (var x = 0; x < exceptFields.length; x++) {
                if (exceptFields[x] == f)
                    return false;
            }
            return true;
        };
    } else {
        isNotExceptField = function (f) { return true; };
    }
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    var dataFields = [];
    for (var i = 0; i < fields.length; i++) {
        var field = fields[i].getAttribute('data-field');
        if (isNotExceptField(field))
            dataFields.push(field);
    }
    return dataFields;
};
Famark.disableFields = function (fieldsArray, color) {
    for (var i = 0; i < fieldsArray.length; i++)
        Famark.setDisabled(fieldsArray[i], true);
    if (color == null)
        return;
    for (i = 0; i < fieldsArray.length; i++)
        Famark.setBackgroundColor(fieldsArray[i], color);
};
Famark.enableFields = function (fieldsArray, color) {
    for (var i = 0; i < fieldsArray.length; i++)
        Famark.setDisabled(fieldsArray[i], false);
    if (color == null)
        return;
    for (i = 0; i < fieldsArray.length; i++)
        Famark.setBackgroundColor(fieldsArray[i], color);
};
Famark.setVisible = function (field, isTrue) {

    var lr = document.getElementById('lr_' + field);
    var er = document.getElementById('er_' + field);

    if (lr == null || er == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    er.style.display = lr.style.display = (isTrue === undefined || isTrue) ? '' : 'none';
};
Famark.showFields = function (fieldsArray) {
    for (var i = 0; i < fieldsArray.length; i++)
        Famark.setVisible(fieldsArray[i], true);
};
Famark.hideFields = function (fieldsArray) {
    for (var i = 0; i < fieldsArray.length; i++)
        Famark.setVisible(fieldsArray[i], false);
};
Famark.requireFields = function (fieldsArray) {
    for (var i = 0; i < fieldsArray.length; i++) {
        Famark.setVisible(fieldsArray[i], true);
        Famark.setRequired(fieldsArray[i], true);
    }
};
Famark.ignoreFields = function (fieldsArray) {
    for (var i = 0; i < fieldsArray.length; i++) {
        Famark.setVisible(fieldsArray[i], false);
        Famark.setRequired(fieldsArray[i], false);
    }
};
Famark.setFilter = function (field, filter) {

    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    var eqPos = filter.indexOf('=');
    if (eqPos < 1) {
        alert(Famark._invalidFilterPrefix + filter);
        return;
    }

    var filterKey = filter.substr(0, eqPos).replace(/^\s+|\s+$/g, '');
    var filterVal = filter.substr(eqPos + 1).replace(/^\s+|\s+$/g, '');
    
    var exFilter = el.getAttribute('data-filter');
    if (exFilter == null || exFilter == '') {
        el.setAttribute('data-filter', filterKey + '=' + filterVal.replace(/&/g, '&&'));
        return;
    }

    var checkFilterKey = filterKey.toUpperCase();
    var exFilterPairs = Famark.getKeyValuePairs(exFilter);

    var exFilterString = '';
    for (var i = 0; i < exFilterPairs.length; i++) {
        if (checkFilterKey != exFilterPairs[i].Key.toUpperCase())
            exFilterString += exFilterPairs[i].Key + '=' + exFilterPairs[i].Value.replace(/&/g, '&&') + '&';
    }

    el.setAttribute('data-filter', exFilterString + filterKey + '=' + filterVal.replace(/&/g, '&&'));
};
Famark.getKeyValuePairs = function (dataString) {
    var dataParts = dataString.split('&');
    var processedParts = [];

    for (var i = 0; i < dataParts.length; i++) {
        var valPart = dataParts[i];
        while (i < dataParts.length - 1 && dataParts[i + 1] == '') {
            if (i < dataParts.length - 2)
                valPart += '&' + dataParts[i + 2];
            i = i + 2;
        }

        processedParts.push(valPart);
    }

    var pairs = [];

    for (var j = 0; j < processedParts.length; j++) {
        var processedPart = processedParts[j];
        var indexOfEqual = processedPart.indexOf('=');
        if (indexOfEqual < 1)
            continue;
        var key = processedPart.substr(0, indexOfEqual).replace(/^\s+|\s+$/g, '');
        var value = processedPart.substr(indexOfEqual + 1).replace(/^\s+|\s+$/g, '');
        pairs.push({ 'Key': key, 'Value': value });
    }

    return pairs;
};
Famark.setParentChildFilter = function (parentField, childField, filterKey) {
    var parentValue = Famark.getValue(parentField);
    if (parentValue != null && parentValue != '') {
        Famark.setFilter(childField, filterKey + '=' + parentValue);
    }
    else {
        Famark.setFilter(childField, filterKey + '=NULL');
    }
};
Famark.setRecordFilter = function (field, recordFilterKey) {
    var el = document.getElementById('el_' + field);
    if (el == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    var formInfo = Famark.getFormInfo();
    if (formInfo.recordId != '') {
        Famark.setFilter(field, recordFilterKey + '=' + formInfo.recordId);
    } else {
        Famark.setFilter(field, recordFilterKey + '=NA');
        el.setAttribute('data-record-filter-key', recordFilterKey);
    }
};
Famark.getColumnValues = function (entity, columns, filter) {
    if (!entity || !columns || !filter) {
        alert(Famark._requiredFieldPrefix + 'entity, columns, filter');
        return null;
    }
    var url = 'Data.ashx?entity=' + entity + '&columns=' + columns + '&filter=' + window.encodeURIComponent(filter);
    var output = Famark.getDataOutput(url, 1);
    if (!output)
        return null;
    var record = output[0];
    var values = [];
    for (var i = 0; i < record.Fields.length; i++)
        values.push(record.Fields[i].Value);
    return values;
};
Famark.getGroupColumnValues = function (entity, columns, groupBy, filter) {
    if (!entity || !columns || !groupBy) {
        alert(Famark._requiredFieldPrefix + 'entity, columns, groupBy');
        return null;
    }
    var url = 'Data.ashx?entity=' + entity + '&columns=' + columns + '&groupBy=' + groupBy;
    if (filter != null && filter != '')
        url += '&filter=' + window.encodeURIComponent(filter);
    var output = Famark.getDataOutput(url, 2);
    if (!output)
        return null;
    var row = output[1].value[0];
    var values = [];
    for (var i = 1; i < row.length; i++)
        values.push(row[i]);
    return values;
};
Famark.getDataOutput = function (url, len) {
    var http = new XMLHttpRequest();
    var result;
    try {
        http.open("GET", url, false);
        http.send();
        result = Famark.parseJSON(http.responseText);
    } catch (e) {
        alert(e.message);
        return null;
    }
    if (result.ErrorMessage != null && result.ErrorMessage != '') {
        alert(result.ErrorMessage);
        return null;
    }
    if (result.Output == null || (len && result.Output.length < len)) {
        alert('null or empty output!');
        return null;
    }
    return result.Output;
};
Famark.moveField = function (field, index) {
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    var mField = null;
    for (var i = 0; i < fields.length; i++) {
        var iField = fields[i].getAttribute('data-field');
        if (iField == field) {
            mField = iField;
            break;
        }
    }
    if (mField == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    
    mField.parentNode.removeChild(mField);

    if (isNaN(index) || index > Famark._divData.children.length) {
        Famark._divData.appendChild(mField);
        return;
    }

    var posTr = Famark._divData.children[index < 0 ? 0 : index];
    Famark._divData.insertBefore(mField, posTr);
};
Famark.getFieldIndex = function (field) {
    var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
    for (var i = 0; i < fields.length; i++) {
        var iField = fields[i].getAttribute('data-field');
        if (iField == field)
            return i;
    }
    return -1;
};
Famark.insertSection = function (key, label, fromField, toField, expanded) {
    var index = Famark.getFieldIndex(fromField);
    if (index < 0)
        index = null;
    var sec = Famark.insertField(key, label, toField, 'section', index);
    if (!expanded)
        sec.collapse();
    return sec;
};
Famark.insertField = function (key, label, value, type, pos) {
    
    if (Famark.getFieldIndex(key) > -1)
        return document.getElementById('el_' + key);
    
    var fDiv = document.createElement('div');
    fDiv.setAttribute('data-field', key);
    fDiv.className = 'field';
    var lr = document.createElement('div');
    lr.id = 'lr_' + key;
    var lb = document.createElement('span');
    lb.id = 'lb_' + key;
    lb.className = 'lb';
    lb.innerHTML = label.replace(/&/g, '&amp;').replace(/\>/g, '&gt;').replace(/\</g, '&lt;');
    lr.appendChild(lb);
    fDiv.appendChild(lr);

    var er = document.createElement('div');
    er.id = 'er_' + key;
    var el, isCollapsible = false;
    if (type == 'select') {
        el = document.createElement('select');
        if (value != null) {
            var op = document.createElement('option');
            op.text = value;
            op.value = value;
            el.appendChild(op);
            op.selected = true;
        }
        el.className = 'el';
    } else if (type == 'section') {
        el = document.createElement('input');
        el.type = 'text';
        el.className = 'el section-line';
        el.disabled = true;
        lb.className += ' section-label';
        isCollapsible = (value != null && value != '');
    } else if (type == 'textarea') {
        el = document.createElement('textarea');
        el.rows = '3';
        el.value = value;
        el.className = 'el';
    } else {
        el = document.createElement('input');
        el.type = type || 'text';
        el.value = value;
        el.className = 'el';
    }

    el.id = 'el_' + key;
    el.setAttribute('data-custom', 'true');
    er.appendChild(el);
    fDiv.appendChild(er);

    if (pos == null) {
        Famark._divData.appendChild(fDiv);
    }
    else {
        var posTr = Famark._divData.children[pos];
        Famark._divData.insertBefore(fDiv, posTr);
    }

    if (isCollapsible) {
        Famark.initCollapse(key, value);
        el.collapse = function () {
            if (!lb.isCollapsed) 
                lb.toggle();
        };
        el.expand = function () {
            if (lb.isCollapsed) 
                lb.toggle();
        };
    }

    return el;
};
Famark.removeField = function (field) {
    var lr = document.getElementById('lr_' + field);
    if (lr == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    Famark._divData.removeChild(lr.parentNode);
};
Famark.initCollapse = function (field, lastField) {
    var lb = document.getElementById('lb_' + field);

    if (lb == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    lb.style.fontWeight = 'bold';
    lb.style.cursor = 'pointer';
    lb.style.display = 'inline-block';
    lb.style.paddingTop = '10px';
    lb.innerHTML = '&#x25BA;&nbsp;' + lb.innerHTML;
    lb.isCollapsed = false;
    lb.tabIndex = 0;
    lb.toggle = function () {
        var fields = Famark.getElementsByClassName('field', 'div', Famark._divData);
        var disp;
        if (!lb.isCollapsed) {
            lb.innerHTML = '&#x229E;' + lb.innerHTML.substring(1);
            disp = 'none';
        } else {
            lb.innerHTML = '&#x25BC;' + lb.innerHTML.substring(1);
            disp = 'block';
        }

        lb.isCollapsed = !lb.isCollapsed;

        var skip;
        for (skip = 0; skip < fields.length; skip++) {
            var skField = fields[skip].getAttribute('data-field');
            if (skField == field)
                break;
        }
        skip++;
        for (var i = skip; i < fields.length; i++) {
            fields[i].style.display = disp;
            var lField = fields[i].getAttribute('data-field');
            if (lField == lastField)
                break;
        }
    };
    lb.onclick = lb.toggle;
    lb.onkeyup = function (e) {
        e = e || window.event;
        if (e.keyCode == 13 || e.keyCode == 32)
            lb.toggle();
    };
};
Famark.makeHtmlDisplay = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.nodeName != 'TEXTAREA') {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    if (el.isHtmlDisp !== undefined && el.isHtmlDisp != null)
        return;
    
    function writeContent() {
        var hd = new Caja.HtmlDisplay('if_' + field);
        el.setHtmlDisplay = function () {
            hd.html = el.value;
            hd.drawIn('er_' + field);
            if (el.value === '********') {
                var fm = document.getElementById('if_' + field);
                fm.style.backgroundColor = '#dddddd';
            }
        };
        el.disableHtmlDisplay = function (isTrue) {
            var fm = document.getElementById('if_' + field);
            fm.className = isTrue ? 'htmlFrameDisabled' : 'htmlFrame';
        };
        el.setHtmlDisplay();
        el.style.display = 'none';
        el.isHtmlDisp = 'true';
        el.isRichInput = null;
    };

    if (window.Caja !== undefined) {
        writeContent();
        return;
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'Attachment/Caja.js';

    Famark.addHandler(script, 'load', function () { writeContent(); });

    document.getElementsByTagName('head')[0].appendChild(script);
};
Famark.makePipeInput = function (field, entity, dispAttr, sysAttr, filter) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.nodeName != 'TEXTAREA') {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    if (filter != null) {
        filter = filter.replace(/\s*=\s*/, '=').replace(/&/g, '&&');

        var eqPos = filter.indexOf('=');
        if (eqPos < 1) {
            alert(Famark._invalidFilterPrefix + filter);
            return;
        }
    }

    if (window.Pipe !== undefined) {
        Pipe.createList(field, entity, dispAttr, sysAttr, filter);
        return;
    }

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = 'Attachment/Pipe.js';

    Famark.addHandler(script, 'load', function () { Pipe.createList(field, entity, dispAttr, sysAttr, filter); });

    document.getElementsByTagName('head')[0].appendChild(script);
};
Famark.changePipeFilter = function (field, filter) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.isPiped === undefined || el.isPiped == null) {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }
    el.changePipeFilter(filter);
};
Famark.makeRichInput = function (field) {
    var el = document.getElementById('el_' + field);
    if (el == null || el.nodeName != 'TEXTAREA') {
        alert(Famark._invalidFieldPrefix + field);
        return;
    }

    if (el.isRichInput !== undefined && el.isRichInput != null)
        return;

    function writeContent() {
        Rich.initialize();
        var rt = new Rich.TextEditor('rt_' + field);
        rt.html = Caja.getSafeHtml(el.value);
        var container = document.createElement('div');
        document.getElementById('er_' + field).appendChild(container);
        rt.changeListener = function () { Famark.triggerChange(el); };
        rt.drawIn(container);
        el.setRichValue = function () {
            rt.setValue(Caja.getSafeHtml(el.value));
        };
        el.getRichValue = function () {
            return Caja.getSafeHtml(rt.getValue());
        };
        el.disableRichInput = function (isTrue) {
            rt.setDisabled(isTrue);
        };

        el.style.display = 'none';
        el.isRichInput = 'true';
        el.isHtmlDisp = null;
    };

    if (window.Rich !== undefined && window.Caja !== undefined) {
        writeContent();
        return;
    }

    var hasWritten = false;

    function loadRichCaja() {
        if (!hasWritten && window.Rich !== undefined && window.Caja !== undefined) {
            writeContent();
            hasWritten = true;
        }
    }

    if (window.Rich === undefined) {
        var script1 = document.createElement('script');
        script1.type = 'text/javascript';
        script1.src = 'Attachment/Rich.js';
        Famark.addHandler(script1, 'load', function () { loadRichCaja(); });
        document.getElementsByTagName('head')[0].appendChild(script1);
    }

    if (window.Caja === undefined) {
        var script2 = document.createElement('script');
        script2.type = 'text/javascript';
        script2.src = 'Attachment/Caja.js';
        Famark.addHandler(script2, 'load', function () { loadRichCaja(); });
        document.getElementsByTagName('head')[0].appendChild(script2);
    }
};
Famark.setTimezone = function (tz, tzVal) {
    tz.value = tzVal;
    if (tz.value === tzVal)
        return;
    var op = document.createElement('option');
    op.innerHTML = tzVal;
    op.value = tzVal;
    tz.appendChild(op);
    tz.value = tzVal;
};
Famark.getTimezone = function (dt) {
    dt = dt || new Date();
    var tzOffset = dt.getTimezoneOffset();
    var sign = tzOffset > 0 ? '-' : '+';
    var zh = Math.floor(Math.abs(tzOffset / 60));
    var zm = Math.floor(Math.abs(tzOffset % 60));
    return sign + (zh < 10 ? '0' : '') + zh + ':' + (zm < 10 ? '0' : '') + zm;
};