/*	ViewXP JavaScript Stuff
 *
 *
 /*--------------------------------------------------*/

var ViewXP = {
    Version: '0.0.1'
}

var browserName = navigator.appName;

/* Filter function */
Array.prototype.filter = function(fn, thisObj) {
    var scope = thisObj || window;
    var a = [];
    for (var i = 0, j = this.length; i < j; ++i) {
        if (!fn.call(scope, this[i], i, this)) {
            continue;
        }
        a.push(this[i]);
    }
    return a;
};

/*
 Script loader ensuring that a js file is only loaded once pr. request
 Usage: JSScriptLoader.load(url);
 */
var JSScriptLoader = {
    uris : new Array(),
    load: function(src) {
        if (typeof this.uris[src] == 'undefined') {
            this.uris[src] = true;
            document.write('<script type="text\/javascript" src="' + src + '"><\/script>');
        }
    }
}

var NavTree = Class.create();

/**
 *
 *   Usage:  new Tree(elementName, baseUrl, treeParam, selectParam)
 *   elementName is either a element or the id of an element to add click handling to.
 *   when clicking an element in the tree, the Window location is changed according to the following rules
 *    1 ) if the element or it's parents has class "selectableItem" then window location is changed to baseUrl + "&" + selectParam+<selectable.id>
 *    2 ) if the element or on can be found the nearest parent that has class "nodeGrip" tried found and the baseUrl + "&" + nodeParam+<treeNode.id>
 */
NavTree.prototype = {
    initialize: function(navItemElem, baseUrl, nodeParam, selectParam) {
        this.itemElem = $(navItemElem);
        this.baseUrl = baseUrl;
        this.nodeParam = nodeParam;
        this.selectParam = selectParam;
        this.itemElem.onclick = this.clickHandler.bindAsEventListener(this);
        Event.observe(window, 'load', this.locateElement.bindAsEventListener(this));
    },

    clickHandler: function(event) {
        var element = Event.element(event);
        var param = null;
        while (element != null && element != this.itemElem) {
            if (Element.hasClassName(element, "selectableItem")) {
                param = this.selectParam + element.id;
                break;
            }
            if (Element.hasClassName(element, "nodeGrip")) {
                param = this.nodeParam + element.id;
                break;
            }
            element = element.parentNode;
        }
        if (param != null) {
            window.location = this.baseUrl + "&" + param;
        }
    },
    locateElement: function() {
        var findSelectedElem = $$(".selected_navTreeNode");
        if (findSelectedElem.length == 1) {
            findSelectedElem.each(function(elem) {
                elem.parentNode.parentNode.scrollIntoView(true);
            });
        }
    }
};


var Utility = Class.create();

Utility.prototype = {

    initialize: function() {

    },
    getActionField : function(formElem) {
        var actionElem = Form.getInputs(formElem, "hidden").find(function(e) {
            return e.hasClassName("btnaction");
        });
        if (!actionElem) {
            actionElem = $(document.createElement("input"));
            actionElem.type = "hidden";
            actionElem.addClassName("btnaction");
            formElem.appendChild(actionElem);
        }
        return actionElem;
    },
    submitAction: function(form, actionName, actionValue, hiddenField) {
        var formElem = $(form);
        var actionElem = this.getActionField(formElem);
        actionElem.name = actionName;
        actionElem.value = actionValue || 'click';
        formElem.submit();
    },
    submitActionWtihValidate: function(form, actionName, actionValue, hiddenField) {
        var formElem = $(form);
        var actionElem = this.getActionField(formElem);
        actionElem.name = actionName;
        actionElem.value = actionValue || 'click';
        if (formElem.validators) {
            if (!formElem.validators.validate()) {
                return false;
            }
        }
        formElem.submit();
    },
    validateForm: function(form, actionName, actionValue, hiddenField) {
        var formElem = $(form);
        var actionElem = this.getActionField(formElem);
        actionElem.name = actionName;
        actionElem.value = actionValue || 'click';
        if (formElem.validators) {
            if (!formElem.validators.validate()) {
                return false;
            }
        }
        return true;
    },
    enclosingTag: function(e, elementName) {
        var element = $(e);
        while (element) {
            if (element.tagName)
                if (element.tagName.toUpperCase() == elementName.toUpperCase()) {
                    return element;
                }
            element = element.parentNode;
        }
        return false;
    },
    getForm: function(e) {
        return this.enclosingTag(e, "form");
    },
    doActionSubmit: function(elem, actionName, actionValue, validate) {
        try {
            var form = this.enclosingTag($(elem), "FORM");
            if (!form) {
                form = document.forms[0];
            }
            if (validate) {
                this.submitActionWtihValidate(form, actionName, actionValue);
            } else {
                this.submitAction(form, actionName, actionValue);
            }
        } catch (e) {
        }
        return false;
    }
}

var FormUtil = new Utility();

var Spinner = Class.create();

Spinner.prototype = {

    initialize: function(initValue, inputElementId, minValue, maxValue) {
        this.lastValue = 0;
        this.minValue = minValue;
        this.maxValue = maxValue;
        this.inputElement = $(this.inputElementId);
        ;
        this.inputElementId = inputElementId;
        if (!isNaN(initValue)) {
            this.lastValue = initValue;
        }
    },

    upClick: function() {
        this.setElement();
        if (this.isElementExist()) {

            var newValue = this.lastValue;
            if (this.isElementHasNumValue()) {
                newValue = this.inputElement.value;
            }
            newValue = parseInt(newValue) + 1;
            if (newValue <= this.maxValue) {
                this.lastValue = newValue;
                this.inputElement.value = this.lastValue;
            }
        }
    },

    downClick: function() {
        this.setElement();
        if (this.isElementExist()) {
            var newValue = this.lastValue;
            if (this.isElementHasNumValue()) {
                newValue = this.inputElement.value;
            }
            newValue -= 1;
            if (newValue >= this.minValue) {
                this.lastValue = newValue;
                this.inputElement.value = this.lastValue;
            }
        }
    },

    onChange: function() {
        this.setElement();
        if (this.isElementExist()) {
            var newValue = this.lastValue;
            if (this.isElementHasNumValue()) {
                newValue = parseInt(this.inputElement.value);
                this.lastValue = newValue;
                if (newValue > this.maxValue) {
                    this.lastValue = this.maxValue;
                    this.inputElement.value = this.lastValue;
                } else if (newValue < this.minValue) {
                    this.lastValue = this.minValue;
                    this.inputElement.value = this.lastValue;
                }
            } else {
                this.inputElement.value = this.lastValue;
            }
        }
        if (!this.isElementHasNumValue()) {
            this.inputElement.value = this.minValue;
        }
    },

    // private methods
    setElement: function() {
        if (this.inputElement == null) {
            this.inputElement = $(this.inputElementId);
        }
    },

    isElementExist: function() {
        return this.inputElement != null;
    },

    isElementHasNumValue: function() {
        if (this.isElementExist()) {
            return !isNaN(this.inputElement.value);
        }
        return false;
    }
}


var TabPanel = Class.create();

TabPanel.prototype = {

    initialize: function(id) {
        this.id = id;
        this.tabs = $A([]);
    },

    selectTab: function(selectedId) {
        var hiddenId = this.id + '_hidden';
        this.tabs.each(function(val) {
            $(val + '_tabPanel').className = 'hideMe';
            if (val == selectedId) {
                $(val + '_tabPanel').className = 'showMe';
                var hiddenElem = null;
                hiddenElem = $(hiddenId);
                hiddenElem.value = selectedId;
            }
        })
    },

    addTab: function(tabId) {
        this.tabs.push(tabId);
    },

    removeTab: function(tabId) {
        var index = this.tabs.indexOf(tabId);
        this.tabs[index] = null;
        this.tabs.compact();
    }
}


var WindowResizeHandler = Class.create();

WindowResizeHandler.prototype = {
    initialize: function() {
        this.listeners = [];
        Event.observe(window, 'resize', this.doResize.bindAsEventListener(this));
        this.lastDims = this.getViewportSize();
    },
    getViewportSize: function() {
        var x, y;
        if (self.innerHeight) {
            x = self.innerWidth;
            y = self.innerHeight;
        } else if (document.documentElement && document.documentElement.clientHeight) {
            x = document.documentElement.clientWidth;
            y = document.documentElement.clientHeight;
        } else if (document.body) {
            x = document.body.clientWidth;
            y = document.body.clientHeight;
        }
        return {width: x, height: y};
    },
    addListener:function(listener) {
        this.listeners.push(listener);
    },
    doResize:function() {
        var dims = this.getViewportSize();
        var resized = dims.width != this.lastDims.width || dims.height != this.lastDims.height;
        if (resized) {
            this.listeners.each(function(listener) {
                listener(dims);
            }
                    );
            this.lastDims = dims;
        }

    }
}
var resizeEventHandler = new WindowResizeHandler();

var OnLoadHandler = Class.create();

OnLoadHandler.prototype = {
    initialize: function() {
        this.listeners = $A([]);
        Event.observe(window, 'load', this.doOnLoad.bindAsEventListener(this));
    },
    addListener:function(listener) {
        this.listeners.push(listener);
    },
    doOnLoad:function() {
        this.listeners.each(function(listener) {
            listener();
        });
    }
}
var loadEventHandler = new OnLoadHandler();

var navPane = Class.create();

navPane.prototype = {
    initialize: function(left, treeContainer) {
        this.selectedTreeContainer = $(treeContainer);
        this.leftNavigation = $(left);
        loadEventHandler.addListener(this.navPaneHandler.bind(this));
        resizeEventHandler.addListener(this.navPaneHandler.bindAsEventListener(this));
        Event.observe(window, 'load', this.addOverLay.bindAsEventListener(this));
    },
    navPaneHandler: function() {
        // Checking if the navPaneTreeContainer is pressent
        if (this.selectedTreeContainer == null) {
            return
        }
        var navPaneMenuItems = this.leftNavigation.getElementsBySelector(".navPaneMenuItem");
        // Getting the height of all buttons
        var menuItems = 0;
        navPaneMenuItems.each(function(elem) {
            menuItems += elem.getHeight();
        });
        // Checking if the navPaneSubMenu is pressent, and getting the height
        var navPaneSubMenuHeight;
        if ($("navPaneSubMenu") != null) {
            navPaneSubMenuHeight = $("navPaneSubMenu").getHeight();
        } else {
            navPaneSubMenuHeight = 0;
        }
        // Dooing the calculation, and setting the height of the navPaneTreeContainer
        var calculation = heightResult - menuItems - navPaneSubMenuHeight;
        this.selectedTreeContainer.style.height = Math.abs(calculation) + 'px';
    },
    addOverLay: function() {
        this.leftNavigation.getElementsBySelector("li.modified").each(function(elem) {
            elem.immediateDescendants().filter(function(imc) {
                return imc.tagName.toLowerCase() == "span"
            }).each(function(childElem) {
                $(childElem).getElementsBySelector(".nodeIcon").each(function(iconElem) {
                    new Insertion.After(iconElem, '<img class="overLay" src="/agillicadmin/forward/workbenchglobal/defaultkit/images/overLay.gif" alt="">');
                });
            });
        });
    }
}

var Tab = Class.create();
//var resultElements;
//var resultData;

Tab.prototype = {
    initialize: function(navigationItemElement, hiddenFieldId, contentContainerId) {
        this.itemElem = $(navigationItemElement);
        this.hiddenField = $(hiddenFieldId);
        this.contentContainer = $(contentContainerId);
        Element.cleanWhitespace(this.itemElem);
        var curSelected = document.getElementsByClassName("selectedTab", this.itemElem);
        if (curSelected.length == 0) {
            //if none of the tabs have a "selectedTab" class, then set the first tab to selectedTab
            var tempTest = this.itemElem.childNodes[0].id;
            $(tempTest).addClassName("selectedTab");
            this.getElementForTab(this.itemElem.childNodes[0]).show();
            this.hiddenField.value = this.itemElem.childNodes[0].id;
        } else {
            this.getElementForTab(curSelected[0]).show();
            this.hiddenField.value = curSelected[0].id;
        }
        this.itemElem.onclick = this.onTabHandler.bindAsEventListener(this);
        //Event.observe(window, 'load', this.tabContentHandler.bindAsEventListener(this));

        loadEventHandler.addListener(this.tabContentHandler.bind(this));
        resizeEventHandler.addListener(this.tabContentHandler.bindAsEventListener(this));
    },
    onTabHandler: function(event) {
        if (this.itemElem == Event.element(event)) {
            // if clicks are on the UL itself
            return;
        }
        var li = Event.findElement(event, "li");
        if (!Element.hasClassName(li, "selectedTab")) {
            var selfReference = this;
            var mySelecedTabList = $(li.parentNode).getElementsBySelector(".selectedTab");
            mySelecedTabList.each(function(elem) {
                Element.removeClassName(elem, "selectedTab");
                selfReference.getElementForTab(elem).hide();
            });
            Element.addClassName(li, "selectedTab");
            var panelElem = this.getElementForTab(li);
            panelElem.show();
            this.hiddenField.value = panelElem.id;

        }
    },
    getElementForTab: function(liElement) {
        return $(liElement.id.replace(/^tab_/, ""));
    },
    tabContentHandler: function() {
        // set the content area height
        var rightContentArea = Element.getHeight("rightContentArea");
        var headingArea = 0;
        if ($("headingArea") != null) {
            headingArea = Element.getHeight("headingArea") + 20;
        }
        var bottomButtonsArea = 0;
        if ($("bottomButtonsArea") != null) {
            bottomButtonsArea = Element.getHeight("bottomButtonsArea") + 10;
        }
        var theTabTopBar = Element.getHeight(this.itemElem) + 22;
        this.contentContainer.style.height = heightResult - headingArea - bottomButtonsArea - theTabTopBar + 45 + 'px';
    }


}

var Layout = Class.create();
var heightResult;

Layout.prototype = {
    initialize: function() {
        //Event.observe(window, 'load', this.onloadHandler.bindAsEventListener(this));
        loadEventHandler.addListener(this.onloadHandler.bind(this));
        resizeEventHandler.addListener(this.layoutHandler.bindAsEventListener(this));
    },
    onloadHandler: function() {
        this.layoutHandler(resizeEventHandler.getViewportSize());
    },
    layoutHandler: function(dimensions) {
        var documentHeight = dimensions.height;
        var documentWidth = dimensions.width;

        var topNavigationHeight = $('topNavigation').getHeight();
        var footerHeight = Math.min(50, $('footer').getHeight());
        var leftNavigationDimensionsWidth = $('leftNavigation').getDimensions().width;

        heightResult = documentHeight - topNavigationHeight - footerHeight;
        var widthResult = documentWidth - leftNavigationDimensionsWidth;
        var followElem = null;
        var followWins = document.getElementsByClassName("followWindow");
        if (followWins.length == 1) {
            followElem = followWins[0];
            followElem.style.height = heightResult + 'px';
        }
        $("rightContentArea").setStyle( { width:widthResult - 25 + 'px'});
        $("rightContentArea").show();

    }
}

var ImageResizer = Class.create();

ImageResizer.prototype = {
    initialize: function(maxImageWidth, maxImageHeight) {
        this.maxImageWidth = maxImageWidth;
        this.maxImageHeight = maxImageHeight;
        //Event.observe(window,'load',this.resizeImages.bindAsEventListener(this));
        loadEventHandler.addListener(this.resizeImages.bind(this));
    },
    resizeImages: function() {
        var pageImages = $$(".resizeImage");
        var maxWidth = this.maxImageWidth;
        var maxHeight = this.maxImageHeight;
        var chgWidth;
        var chgHeight;

        pageImages.each(function(tempElement) {
            if (tempElement.hasClassName("resizer")) {
                return;
            }
            tempElement.addClassName("resizer");
            tempElement.hide();
            var tempImageSize = Element.getDimensions(tempElement);
            chgWidth = tempImageSize.width;
            chgHeight = tempImageSize.height;
            var tempObj = $(tempElement);
            var changed = false;

            if (chgWidth > maxWidth) {
                chgHeight = parseInt(maxWidth / chgWidth * chgHeight);
                chgWidth = maxWidth;
                changed = true;
            }

            if (chgHeight > maxHeight) {
                chgWidth = parseInt(maxHeight / chgHeight * chgWidth);
                chgHeight = maxHeight;
                changed = true;
            }
            tempObj.style.width = chgWidth + "px";
            tempObj.style.height = chgHeight + "px";

            if (!changed) {
                tempObj.style.width = tempImageSize.width - 10 + "px";
                //  2 * 5 padding (left and right) = 10
                tempObj.style.height = tempImageSize.height - 10 + "px";
            }
            Element.show(tempElement);
            new Insertion.After(tempElement.parentNode, "<br/>Width: " + (tempImageSize.width - 10) + " pixels, Height: " + (tempImageSize.height - 10) + " pixels.");
        });
    }
}

var CSSHelper = {
    toggleClass:function(elem, class1, class2, use1IfNone) {
        var e = $(elem);
        if (!e) return;
        if (e.hasClassName(class1)) {
            e.removeClassName(class1);
            e.addClassName(class2);
        } else if (e.hasClassName(class2)) {
            e.removeClassName(class2);
            e.addClassName(class1);
        } else if (use1IfNone) {
            e.addClassName(class1);
        }
    }
};

var ExplorerTree = Class.create();
ExplorerTree.prototype = {
    initialize:function(rootUL) {
        this.root = $(rootUL);
        Event.observe(this.root, "click", this.handleTree.bindAsEventListener(this));
        var selectedElemes = this.root.getElementsByClassName("selected");
        if (selectedElemes.length > 0) {
            this.expandToElement(selectedElemes[0]);
        }
    },
    handleTree:function(event) {
        var node = $(Event.findElement(event, "li"));
        if (!node.hasClassName("leaf")) {
            CSSHelper.toggleClass(node, "expanded", "collapsed", true);
        }
    },
    expandToElement:function(elem) {
        var ancestors = $(elem).ancestors();
        ancestors.each(function(ancestor) {
            if (ancestor == this.root) {
                throw $break;
            }
            if (ancestor.tagName.toLowerCase() == "li" && !ancestor.hasClassName("expanded")) {
                CSSHelper.toggleClass(ancestor, "expanded", "collapsed", true);
            }
        });
    }
}

var iFrameLoader = Class.create();
iFrameLoader.prototype = {
    initialize: function(contentDiv, iFrame, cssArray, pagesClass, pageClass, pagerHeader) {
        this.contentArea = $(contentDiv);
        this.previewArea = $(iFrame);
        this.cssFiles = $A(cssArray);
        this.pagesClass = pagesClass;
        this.pageClass = pageClass;
        this.pagerHeader = pagerHeader;
        // Hiding the preview content/markup
        this.contentArea.hide();
        // Getting the preview content/markup from the DIV
        this.previewContent = this.contentArea.innerHTML;
        this.contentArea.innerHTML = "The content is now loaded into the preview iFrame...";
        // Calling the "loadContent" function on load
        Event.observe(window, 'load', this.loadContent.bindAsEventListener(this));
    },
    loadContent: function() {
        if (this.previewArea.hasClassName("iframeLoader")) {
            return;
        }
        this.previewArea.addClassName("iframeLoader");
        // Adding each CSS file, from the array, as a LINK element, to the HEAD of the iFrame
        var selfRef = this;
        this.cssFiles.each(function(cssFile) {
            selfRef.addCssFile(cssFile);
        });
        // Adding all the preview content/markup to the BODY of the iFrame
        this.previewArea.contentWindow.document.getElementById("agillicIFrameInnerContainer").innerHTML = this.previewContent;
        // Calling the setPreviewHeiht function, with a delay to make sure the CSS files are loaded and aplied to the content/markup inside the iFrame
        setTimeout(this.initContent.bind(this), 100);
    },
    initContent: function() {
        this.previewArea.contentWindow.ClientSidePager.createPagers(this.pagesClass, this.pageClass, this.pagerHeader);
        this.setPreviewHeight();
    },
    addCssFile: function(cssFile) {
        var iFrameDoc = this.previewArea.contentWindow.document;
        // Making the LINK element
        var linkElem = iFrameDoc.createElement("LINK");
        linkElem.href = cssFile;
        linkElem.type = "text/css";
        linkElem.rel = "stylesheet";
        var headElem = iFrameDoc.getElementsByTagName("HEAD")[0];
        // Adding the LINK element to the HEAD
        headElem.appendChild(linkElem);
    },
    setPreviewHeight: function() {
        // Setting the height of the iFrame to mach the content/markup inside
        this.previewArea.setAttribute("height", this.previewArea.contentWindow.document.body.clientHeight);
    },
    setPreviewDimensions : function(width, height) {
        this.previewArea.setAttribute("height", height);
        this.previewArea.setAttribute("width", width);
    },
    getContentElement:function() {
        var f = this.previewArea;
        return f.contentWindow ? f.contentWindow.document : f.contentDocument;
    }

}

var FormChecker = Class.create();
FormChecker.prototype = {
    initialize: function(formId, messageAreaId, status, styleClassOfElmToDisplayMessage) {
        this.formToCheck = $(formId);
        if (this.formToCheck.hasClassName("formchecker")) {
            return;
        }
        this.formToCheck.addClassName("formchecker")
        this.backendStatus = Boolean(status);
        this.styleClassOfElmToDisplayMessage = styleClassOfElmToDisplayMessage;
        this.originalFormValue = this.stripHiddenFields(this.formToCheck);
        var displayArea = $$("." + this.styleClassOfElmToDisplayMessage);
        if (displayArea.length == 1) {
            displayArea.each(function(elem) {
                new Insertion.Before(elem, "<span id='" + messageAreaId + "' class='isDirtyMessage'>You have unsaved changes!</span>")
            });
        }
        this.messageDisplay = $(messageAreaId);
        Element.hide(this.messageDisplay);
        Event.observe(window, 'load', this.compareFormValues.bindAsEventListener(this));
        Event.observe(this.formToCheck, 'click', this.compareFormValues.bindAsEventListener(this));
        Event.observe(this.formToCheck, 'change', this.compareFormValues.bindAsEventListener(this));

    },
    compareFormValues: function() {
        var tempFormValue = "";
        tempFormValue = this.stripHiddenFields(this.formToCheck);
        if (!this.backendStatus) {
            if (this.originalFormValue != tempFormValue) {

                Element.show(this.messageDisplay);
            } else {
                Element.hide(this.messageDisplay);
            }
        } else {
            Element.show(this.messageDisplay);
        }
    },
    stripHiddenFields: function(formId) {
        var tempString = Form.serialize(formId)
        var hiddenNames = formId.getElementsBySelector('INPUT[type="hidden"]').inject([], function(array, hiddenElem) {
            array.push("(" + hiddenElem.name + "=[^&]*&?)");
            return array;
        });
        var replacer = new RegExp(hiddenNames.join("|") + "", "g");
        return tempString.replace(replacer, "")

    }
}

var FormValidator = Class.create();
FormValidator.prototype = {
    initialize: function(validatorCollection, formId, errorTemplate) {
        this.formToValidate = $(formId);
        this.validators = validatorCollection;
        var templateString = errorTemplate ? errorTemplate : '<img class="errorIcon" src="/agillicadmin/forward/workbenchglobal/defaultkit/images/error.gif" alt=""><br />#{message}'
        this.errorTemplate = new Template(templateString);
        Event.observe(window, 'load', this.injectErrFields.bindAsEventListener(this), false);
    },
    injectErrFields:function() {
        var selfRef = this;
        Form.getElements(this.formToValidate).each(function(elem) {
            if (elem.next() && elem.next().hasClassName("validationErrorStyle")) {
                return;
            }
            new Insertion.After(elem, "<span class=\"validationErrorStyle\"></span>");
            if (selfRef.serverErrors && selfRef.serverErrors[elem.name]) {
                selfRef.setError(elem, selfRef.serverErrors[elem.name].errorMessage);
            }
        });
    },
    add: function(fieldName, validatorContent) {
        this.validators[fieldName] = validatorContent;
    },
    validate: function() {
        this.clearAllErrors();
        var selfRef = this;
        var formElems = Form.getElements(this.formToValidate);
        var validated = true;
        $A(formElems).each(function(elem) {
            var validator = selfRef.validators[elem.name];
            if (validator) {
                selfRef.clearError(elem);
                var isOk = false;
                if (selfRef.isVisible(elem)) {
                    switch (typeof validator.validationRule) {
                        case "function" : isOk = validator.validationRule(elem.value); break;
                        case "string" :   isOk = new RegExp(validator.validationRule).test(elem.value);break;
                    }
                    if (!isOk) {
                        selfRef.setError(elem, validator.errorMessage);
                        validated = false;
                    }
                }
            }
        });
        if (this.crossValidators) {
            $A(this.crossValidators).each(function(cValidator) {
                validated = cValidator.validate(selfRef.formToValidate, selfRef) && validated;
            });
        }
        if (!validated && this.onErrors != null) {
            this.onErrors();
        }
        return validated;
    },
    setError : function(elem, msg) {
        var message = this.errorTemplate.evaluate({message:msg});
        try {
            this.getErrorElem(elem).innerHTML = '' + message;
        } catch (e) {
            alert(message);
        }
    },
    clearError : function(elem) {
        try {
            this.getErrorElem(elem).innerHTML = "";
        } catch(e) {

        }
    },
    getErrorElem:function(elem) {
        if (Element.hasClassName(elem.nextSibling, "validationErrorStyle")) {
            return elem.nextSibling;
        }
        return null;
    },

    clearAllErrors:function() {
        $A(this.formToValidate.elements).each(this.clearError.bind(this));
    },
    isVisible: function(elem) {
        var current = elem;
        while (current != this.formToValidate) {
            if (!Element.visible(current)) {
                return false;
            }
            current = current.parentNode;
        }
        return true;
    },
    serverError: function(errorCollection) {
        if (this.serverErrors) {
            Object.extend(errorCollection, this.serverErrors);
        } else {
            this.serverErrors = errorCollection;
        }
    },
    addServerError: function(fieldName, errorContent) {
        if (!this.serverErrors) {
            this.serverErrors = {};
        }
        this.serverErrors[fieldName] = errorContent;
    },
    clearServerErrors : function() {
        if ($("generalServerError")) {
            $("generalServerError").parentNode.removeChild($("generalServerError"));
        }
    },
    createServerErrorDiv:function() {
        if (!$("generalServerError")) {
            new Insertion.Top(this.formToValidate, "<div id=\"generalServerError\" class=\"validationErrorStyle\"><ul></ul></span>");
        }
    },
    generalServerError: function(errorCollection) {
        this.createServerErrorDiv();
        this.addGeneralServerError(errorCollection);
    },

    addGeneralServerError: function(errorCollection) {
        $H(errorCollection).each(function(item) {
            new Insertion.Bottom($("generalServerError").childNodes[0], "<li>" + item.value + "</li>")
        });
    },

    addCrossValidator:function(validator) {
        if (!this.crossValidators) {
            this.crossValidators = [];
        }
        this.crossValidators.push(validator);
    }
}
var BaseValidator = function(validationRule, errorMessage) {
    this.validationRule = validationRule;
    this.errorMessage = errorMessage;
}

var NotBlankValidator = function(errorMessage) {
    this.validationRule = "^\\S+$";
    this.errorMessage = errorMessage;
}

var EmailValidator = function(errorMessage) {
    this.validationRule = "^\\w[^ <>%&=@]*@\\w[^ <>%&=@]*\\.\\w[^ <>%&=@]*$";
    this.errorMessage = errorMessage;
}

var IdenticalValuesValidator = Class.create();
IdenticalValuesValidator.prototype = {
    initialize:function(field1, field2, message) {
        this.field1 = field1;
        this.field2 = field2;
        this.message = message;
    },
    validate:function(form, formValidator) {
        if (form.elements[this.field1].value != form.elements[this.field2].value) {
            formValidator.setError(form[this.field2], this.message);
            return false;
        }
        return true;
    }
}

/*
 Usage: add onclick="HelpDisplay.displayToggler(this, event, [an unique ID to assign - to the HelpDisplay], [id of the hidden DIV - containing the content, that should be displayed inside the HelpDisplay], [width as a number], [height as a number]);" to a IMG- or A-tag.
 */
var HelpDisplay = {
    zIndex: 0,
    displayToggler: function(elem, evt, helperDiv, helpContentContainer, helpWidth, helpHeight) {
        if ($(helperDiv) == null) {
            var helpContent = $(helpContentContainer).innerHTML;
            var width, height;
            if (helpWidth == null) {
                width = 220 + "px";
            } else {
                width = helpWidth + "px";
            }
            if (helpWidth == null) {
                height = 200 + "px";
            } else {
                height = helpHeight + "px";
            }
            var helpTemplate = new Template('<div class=\"helpDisplayContainer\" style=\"width: #{width};\" id=\"#{id}\"><div class=\"helpDisplayFrame\" onclick=\"HelpDisplay.displayToggler(this, event, \'#{id}\');\"><div class=\"helpDisplayInnerFrame\" style=\"height: #{height};\">#{content}<\/div><\/div><\/div>');
            var helpProperties = {id: helperDiv, content: helpContent, width: width, height: height};
            new Insertion.After($(elem), helpTemplate.evaluate(helpProperties));
            $(helperDiv).hide();
        }
        var xPos = Event.pointerX(evt);
        var yPos = Event.pointerY(evt);
        $(helperDiv).style.left = (xPos + 10) + "px";
        $(helperDiv).style.top = (yPos - 50) + "px";
        $(helperDiv).style.zIndex = this.zIndex;
        $(helperDiv).toggle();
        this.zIndex++;
    }
};
/*
 Toggle next/prev.
 */
var ClientSideToggler = {
    portletsClassName: "clmPortlets",
    portletClassName: "clmPortlet",
    createButtons: function(pageContainer) {
        var self = this;
        if (!pageContainer) {
            $$("." + this.portletsClassName).each(function(e) {
                //self.createButtonBar(e);
                pageContainer = e;
            });
        }
        self.createButtonBar(pageContainer);
    },
    createButtonBar: function(pageContainer) {
        var childElems = document.getElementsByClassName(this.portletClassName, pageContainer);
        for (var i = 0; i < childElems.length; i++) {
            if (i == 0) {
                childElems[i].show();
            } else {
                childElems[i].hide();
            }
        }
        var buttonBar = "<div id=\"" + pageContainer.id + "_buttons\" class=\"clmButtonBar\"></div>";
        new Insertion.After(pageContainer, buttonBar);
        var prevButton, nextButton;
        for (var i = 0; i < Math.min(2, childElems.length); i++) {
            if (i == 0) {
                prevButton = "<a href=\"javascript:void(0);\" class=\"disabledButton\">Prev.</a>";
            } else if (i == 1) {
                nextButton = "<a href=\"javascript:ClientSideToggler.toggle('" + pageContainer.id + "', '" + childElems[i].id + "')\">Next</a>";
            }
        }
        if (prevButton != null && nextButton != null) {
            $(pageContainer.id + "_buttons").innerHTML = prevButton + " - " + nextButton;
        }
    },
    toggle: function(pageContainer, elem) {
        var childElems = document.getElementsByClassName(this.portletClassName, pageContainer);
        var prevButton, nextButton;
        for (var i = 0; i < childElems.length; i++) {
            if (childElems[i].id == elem) {
                childElems[i].show();
                if (i == 0) {
                    prevButton = "<a href=\"javascript:void(0);\" class=\"disabledButton\">Prev.</a>";
                } else {
                    prevButton = "<a href=\"javascript:ClientSideToggler.toggle('" + pageContainer + "', '" + childElems[i - 1].id + "')\">Prev.</a>";
                }
                if (i == childElems.length - 1) {
                    nextButton = "<a href=\"javascript:void(0);\" class=\"disabledButton\">Next</a>";
                } else {
                    nextButton = "<a href=\"javascript:ClientSideToggler.toggle('" + pageContainer + "', '" + childElems[i + 1].id + "')\">Next</a>";
                }
            } else {
                childElems[i].hide();
            }
        }
        $(pageContainer + "_buttons").innerHTML = prevButton + " - " + nextButton;
    }
}

/*
 Table pager, pages on TBODY tag groupings
 */
var tablePager = Class.create();

tablePager.prototype = {
    initialize: function(tableId, tableContainerId) {
        this.tableToPage = $(tableId);
        this.tableContainer = $(tableContainerId);
        Event.observe(window, 'load', this.createPager.bindAsEventListener(this));
    },
    createPager: function() {
        var divElem = document.createElement("DIV");
        divElem.id = "tablePagerContainer";
        divElem.appendChild(document.createTextNode("Pages: "));
        var i = 0;
        var self = this;
        $A(this.tableToPage.getElementsByTagName("tbody")).each(function(tbody) {
            var aLink = document.createElement("A");
            divElem.appendChild(aLink);
            aLink.href = "javascript:void(0);";
            aLink.onclick = self.switchPage.bind(self, tbody);
            aLink.innerHTML = i + 1;
            divElem.appendChild(document.createTextNode(" "));
            if (i == 0) {
                Element.show(tbody);
                aLink.className = "selectedTablePagerPage";
            } else {
                Element.hide(tbody);
            }
            i++;
        });
        this.tableContainer.insertBefore(divElem, this.tableToPage);
    },
    switchPage: function(selectedPage) {
        var selectedPageIndex = "";
        var i = 0;
        $A(this.tableToPage.getElementsByTagName("tbody")).each(function(tbody2) {
            tbody2.hide();
            if (tbody2 == selectedPage) {
                selectedPageIndex = i;
            }
            i++;
        });
        selectedPage.show();
        var j = 0;
        $A($("tablePagerContainer").getElementsByTagName("a")).each(function(linkElem) {
            if (selectedPageIndex == j) {
                Element.addClassName(linkElem, "selectedTablePagerPage")
            } else {
                Element.removeClassName(linkElem, "selectedTablePagerPage")
            }
            j++;
        });
    }
}
var showTableDetails = function(clickedElem, showArea) {
    var displayDiv = clickedElem.nextSibling;
    var show = $(showArea);
    show.innerHTML = displayDiv.innerHTML;
}

function cancelEvent(evt) {
    return false;
}

var Dialog = {
    handle: function(result) {
        Dialog.modalController.curOpen.last.callback(result);
    }

};
Dialog.modalController = {
    isIe6 : (Prototype.Browser.IE && !(document.documentElement && typeof document.documentElement.style.maxHeight != "undefined")),
    curOpen:$A([]),
    initialZIndex: 5000,

    open : function(dialog) {
        if (!this.overlay) {
            this.overlay = $(this.createOverlay());
        }
        this.curOpen.push(dialog);
        var overlayZindex = this.initialZIndex + 2 * this.curOpen.length;
        this.overlay.style.zIndex = overlayZindex;
        this.overlay.show();
        dialog.contentElement.style.zIndex = overlayZindex + 1;
        dialog.contentElement.show();
    },
    close:function(dialog) {
        if (this.curOpen.length > 0 && this.curOpen.last() == dialog) {
            dialog.contentElement.hide();
            dialog.contentElement.zIndex = 0;
            this.overlay.style.zIndex = parseInt(this.overlay.style.zIndex) - 2;
            this.curOpen.pop();
            if (this.curOpen.length == 0) {
                this.overlay.hide();
            }
        } else {
            throw new Error("Cannot close modal dialog, which is not the current top");
        }
    },
    createOverlay : function() {
        var overlay = document.createElement(Dialog.modalController.isIe6 ? 'iframe' : 'div');

        Object.extend(overlay, {
            frameBorder:"0",
            src:"about:blank",
            scrolling:"no",
            marginWidth:"0",
            marginHeight:"0"});

        Object.extend(overlay.style, {
            position: 'absolute',
            top: 0,
            left: 0,
            backgroundColor: '#FFFFFF',
            zIndex:this.initialZIndex,
            filter: "alpha(opacity=70)",
            width:"100%",
            height:"100%",
            opacity:0.7,
            display:"none"
        });
        document.body.insertBefore(overlay, document.body.childNodes[0]);
        if (Dialog.modalController.isIe6) {
            overlay.style.setExpression("width", "document.documentElement.clientWidth");
            overlay.style.setExpression("height", "document.documentElement.clientHeight");
        }
        return overlay;
    }
}

Dialog.Box = Class.create();
Object.extend(Dialog.Box.prototype, {
    initialize: function(options) {
        //this.contentElement = $(id);
        this.contentElement = this.createDialogSkeleton(options);
        document.body.insertBefore(this.contentElement, document.body.childNodes[0]);
        this.initializeDialog(options);

        this.addButtons(options);
        //this.initializeDialog(options);
    },
    getViewportDims:function() {
        var res = null;
        if (self.innerHeight) { // all except Explorer
            res = { width:self.innerWidth, height:self.innerHeight};
        } else if (document.documentElement && document.documentElement.clientHeight) { // IE6 Strict Mode
            res = {width:document.documentElement.clientWidth,height:document.documentElement.clientHeight};
        } else  if (document.body) { // other Explorers
            res = {width:document.body.clientWidth,height:document.body.clientHeight}
        }
        return res;
    },
    initializeDialog:function(options) {
        var dialogDims = Element.getDimensions(this.contentElement);
        var winDims = this.getViewportDims();
        this.options = Object.extend({
            modal:true,
            initialLocationAdjust:20,
            resetLocation:true,
            left: Math.max(10, (winDims.width / 2) - (dialogDims.width / 2)) + "px",
            top: Math.max(10, (winDims.height / 2) - (dialogDims.height / 2)) + "px",
            dragHandleClassName:"dialogDragHandle",
            width: "600px"
        }, options);
        var drgHandles = $(this.contentElement).getElementsByClassName(this.options.dragHandleClassName);
        if (drgHandles.length > 0) {
            this.dragHandle = drgHandles[0];
        }
        this.contentElement.style.position = "absolute";
        this.contentElement.style.left = this.options.left
        this.contentElement.style.top = this.options.top;
    },
    createDialogSkeleton : function(options) {
        var content = "";
        var targetDoc = document;
        if (options.content) {
            if (typeof(options.content) == "string") {
                content = new Element("p").update(options.content);
            } else {
                content = options.content;
                targetDoc=$(content).ownerDocument;
            }
        }
        var templateText = '<div class="dialogHeader dialogDragHandle">#{title}</div><div class="dialogContent"></div><div class="dialogButtons"></div>'
        var evalTemplate = new Template(templateText).evaluate(options);
        var outerDiv = agWidgets.elementFactory(targetDoc,"div", {className:"simpleDialogBox",display:"none"});
        if (options.width) {
            outerDiv.setStyle({width:options.width});
        }
        targetDoc.body.insertBefore(outerDiv, targetDoc.body.childNodes[0]);
        outerDiv.innerHTML = evalTemplate;
        var contentDiv = outerDiv.getElementsBySelector(".dialogContent")[0];
        contentDiv.appendChild(content);
        return outerDiv;
    }
    ,
    openInIframe: function(callbackHandler) {
        this.callback = callbackHandler;
        this.open();
    },
    open: function() {
        if (this.options.modal) {
            window.top.Dialog.modalController.open(this);
        } else {
            this.contentElement.show();
        }
        if (this.dragHandle) {
            this.draggable = new Draggable(this.contentElement, {
                onStart:function() {
                    if (Prototype.Browser.IE) {
                        Event.observe(document.body, "drag", cancelEvent, false);
                        Event.observe(document.body, "selectstart", cancelEvent, false);
                    }
                },
                onEnd:function() {
                    if (Prototype.Browser.IE) {
                        Event.stopObserving(document.body, "drag", cancelEvent, false);
                        Event.stopObserving(document.body, "selectstart", cancelEvent, false);
                    }
                },
                starteffect : false, endeffect : false,
                handle:this.dragHandle,
                zindex:this.contentElement.style.zIndex
            });
        }
    }
    ,
    close: function() {
        if (this.options.resetLocation) {
            this.contentElement.style.left = this.options.left
            this.contentElement.style.top = this.options.top;
        }
        if (this.options.modal) {
            window.top.Dialog.modalController.close(this);
        } else {
            this.contentElement.hide();
        }
        if (this.draggable) {
            this.draggable.destroy();
        }
    },
    addButtons: function(options) {
        if (!options.onOk) {
            options.onOk = this.close;
        }
        if (!options.onCancel) {
            options.onCancel = this.close;
        }

        var buttons = this.contentElement.getElementsBySelector(".dialogButtons")[0];
        var targetDoc =  this.contentElement.ownerDocument;
        var cancel = agWidgets.elementFactory(targetDoc, "a", {href:"javascript:void(0)",className:"button darkGreyBg"}).update("Cancel");
        var ok = agWidgets.elementFactory(targetDoc, "a", {href:"javascript:void(0)",className:"button darkGreyBg"}).update("OK");
        Event.observe(ok, "click", options.onOk.bind(this));
        Event.observe(cancel, "click", options.onCancel.bind(this));
        buttons.appendChild(ok);
        buttons.appendChild(cancel);
    }


});
Dialog.messageBox = Class.create();
Object.extend(Dialog.messageBox.prototype, Dialog.Box.prototype);
Object.extend(Dialog.messageBox.prototype, {
    initialize:function(options) {
        this.contentElement = this.createDialogSkeleton(options);
        document.body.insertBefore(this.contentElement, document.body.childNodes[0]);
        this.initializeDialog();

        var buttons = this.contentElement.getElementsBySelector(".dialogButtons")[0];
        var close = new Element("a", {href:"javascript:void(0)"}).update("ok");
        Event.observe(close, "click", this.close.bind(this));
        buttons.appendChild(close);
    }
});

var IFrameDialog = Class.create();
Object.extend(IFrameDialog.prototype, Dialog.Box.prototype);
Object.extend(IFrameDialog.prototype, {
    initialize:function(options) {
        // cannot use prototype new Element, since IE won't allow inserting elements from other frame
        this.iframe = agWidgets.elementFactory(window.top.document,"iframe", {
            frameBorder:0,
            width:"100%",
            marginHeight:0,
            marginWidth:0,
            scrolling:"mp",
            className:"agDialogFrame",
            src:"about:blank"}
       );

        options.content = this.iframe;
        this.contentElement = this.createDialogSkeleton(options);
        var doc = window.top.document;
        $(doc.body).insert({top:this.contentElement});
        this.initializeDialog(options);
        var self = this;
        Event.observe(this.iframe, "load", function() {
            self.resizeToInner()
            if (options.onLoad) {
                options.onLoad(self);
            }
        });

        this.iframe.src = options.src;

        this.addButtons(options);
    },
    resizeToInner:function() {
        var fDoc = this.getFrameDocument();
        this.iframe.height = (Element.getHeight(fDoc.body) + 5) + "px";
    },
    getFrameDocument: function() {
        var f = this.iframe;
        return f.contentWindow ? f.contentWindow.document : f.contentDocument;

    }
});

var ComboBox = Class.create({
    initialize: function(select, errorMessage) {
        this.select = $(select);
        this.errorMessage = errorMessage;
        var combo = new Element("span", {className:"combobox"});
        this.comboElem = combo;
        combo.update("<input type='text'>");
        this.inputElem = combo.down(0);
        combo.setStyle({
            width:select.getWidth() - 21 + "px",
            height:select.style.height
        });
        this.inputElem.style.width = this.select.getWidth() - 21 + "px";
        this.select.insert({ after:combo });

        var validationError = new Element("span", {className:"validationErrorStyle", style:"display:block"});
        this.validationError = validationError;
        combo.insert({ after:validationError });
        this.select.hide();

        var dropdown = new Element("div", {className:"comboDropdown"})
        this.dropDown = dropdown;
        dropdown.clonePosition(combo, {setHeight:false});
        dropdown.hide();

        // collect in string and update using innerHTML which is faster than DOM insert
        this.cloneSelectOptions();
        combo.insert({after: dropdown});

        if (Prototype.Browser.IE) {
            this.iframe = new Element("iframe", {
                className:"comboDropdown",
                frameborder:"0",
                src:"javascript:false",
                scrolling:"no",
                style:"display:none;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);"
            });
            this.dropDown.insert({before:this.iframe});
        }
        Event.observe(this.comboElem, "click", this.toggleDropdown.bindAsEventListener(this));
        Event.observe(this.inputElem, "keydown", this.keyboardInput.bindAsEventListener(this));
        Event.observe(this.inputElem, "blur", this.specialBlur.bindAsEventListener(this));
        Event.observe(this.dropDown, "click", this.doSelect.bindAsEventListener(this));
        Event.observe(this.dropDown, "keydown", this.keyboardInput.bindAsEventListener(this));
    },
    cloneSelectOptions:function() {
        //reinitializes all dropdown elements
        var content = [];
        $A(this.select.options).each(function(elem) {
            content.push("<div value='" + elem.value + "'>" + elem.innerHTML + "</div>");
        });

        this.dropDown.update(content.join(""));
    },
    reinit:function() {
        //Updates the dropDown to preselect the value of the select if it has one.
        this.validationError.hide();
        var initialSelected = this.dropDown.getElementsBySelector('[value="' + this.select.value + '"]');
        if (initialSelected.length > 0) {
            //there should just be one element with this value
            var selectedElement = initialSelected[0];
            this.setSelected(selectedElement);
            this.inputElem.value = selectedElement.innerHTML;
        }
    },
    doUpdate:function(elem) {
        //Adds an element to the dropDown and updates the original select. Any validation error will be hidden.
        this.dropDown.insert({bottom:"<div value='" + elem.value + "'>" + elem.innerHTML + "</div>"})
        this.inputElem.value = elem.innerHTML;
        this.setSelectValueUsingIndex(elem.value);
        this.validationError.hide();
    },
    setSelectValueUsingIndex:function(value) {
        //in IE6 select.value = ... doesnt work so we need to cycle through the select and set the index right
        var i = 0;
        var j = 0;
        $A(this.select.options).each(function(option) {
            if (option.value == value) {
                j = i;
            }
            i++;
        });
        this.select.selectedIndex = j;
    },
    setSelected:function(elem) {
        if (this.curSelected) {
            this.curSelected.removeClassName("selected");
        }
        if (elem) {
            elem.addClassName("selected");
            this.curSelected = elem;
        }
    },
    doSelect:function(evt) {
        if (!evt.keyCode) {
            var clicked = evt.findElement("div");
            if (this.dropDown == clicked) {
                return;
            }
            this.setSelected(clicked);
        }
        this.inputElem.value = this.curSelected.innerHTML;
        this.updateHideAndValidateSelection();
    },
    updateHideAndValidateSelection:function() {
        if (this.hideAndValidateSelection()) {
            var selectedValue = this.curSelected.getAttribute("value");
            this.setSelectValueUsingIndex(selectedValue);
        }
    },
    specialBlur:function() {
        setTimeout(this.updateHideAndValidateSelection.bind(this), 300);
    },
    hideAndValidateSelection:function() {
        this.hideDropDown();
        var currentText = this.inputElem.value;
        var found = $A(this.select.options).find(function(item) {
            return item.value == currentText;
        })
        if (!found) {
            this.validationError.innerHTML = this.errorMessage;
            this.select.value = null;
            this.validationError.show();
        } else {
            this.validationError.hide();
        }
        return found;
    },
    toggleDropdown:function() {
        if (this.dropDown.visible()) {
            this.hideDropDown();
        } else {
            this.inputElem.focus();
            this.showDropDown();
        }
    },
    hideDropDown:function() {
        if (this.iframe) {
            this.iframe.hide();
        }
        this.dropDown.hide();
    },
    showDropDown:function() {
        this.dropDown.hide();
        if (this.iframe) {
            this.iframe.hide();
        }
        this.filterList();
        var comboPos = this.comboElem.positionedOffset();
        this.dropDown.style.top = comboPos.top + 18 + "px";
        this.dropDown.style.left = comboPos.left + "px";
        this.dropDown.show();
        if (this.iframe) {
            this.iframe.clonePosition(this.dropDown);
            this.iframe.show();
        }
        this.setSelected();
        try {
            var firstVisible = this.finder(this.dropDown.down(0), 'nextSibling', Element.visible, true);
            firstVisible.scrollIntoView(true);
            this.setSelected(firstVisible);
        } catch(ex) {
            // ignore...
        }
    },
    keyboardInput:function(evt) {
        switch (evt.keyCode) {
            case    Event.KEY_TAB: return; // handled blur handler
            case    Event.KEY_RETURN:  Event.stop(evt); this.doSelect(evt);break;
            case    Event.KEY_HOME:
            case    Event.KEY_END:
            case    Event.KEY_UP:
            case    Event.KEY_DOWN:
            case    Event.KEY_PAGEUP:
            case    Event.KEY_PAGEDOWN: {
                if (!this.dropDown.visible()) {
                    this.showDropDown();
                }
                this.moveSelection(evt.keyCode);
                // stop the event to avoid scrolling body....
                Event.stop(evt);
                break;
            }
            default: {
                var self = this;
                window.setTimeout(function() {
                    self.showDropDown()
                }, 1);
            }
        }
    },
    finder:function(element, property, finder, checkFirst) {
        element = $(element);
        if (checkFirst) {
            while (element && !finder(element)) {
                element = $(element[property]);
            }
        } else {
            do {
                element = $(element[property]);
            } while (element && !finder(element));
        }
        return element;
    },
    moveSelection:function(keyCode) {
        var find = this.finder;
        var toBeSelected;
        if (!this.curSelected || !this.curSelected.visible()) {
            this.setSelected(null);
            toBeSelected = find(this.dropDown.firstChild, 'nextSibling', Element.visible, true);
            this.curSelected = toBeSelected;
        } else {
            switch (keyCode) {
                case Event.KEY_UP: toBeSelected = find(this.curSelected, 'previousSibling', Element.visible);break;
                case Event.KEY_DOWN: toBeSelected = find(this.curSelected, 'nextSibling', Element.visible);break;
                case Event.KEY_HOME: toBeSelected = find(this.dropDown.firstChild, 'nextSibling', Element.visible, true);break;
                case Event.KEY_END: toBeSelected = find(this.dropDown.lastChild, 'previousSibling', Element.visible, true);break;
            }
        }
        if (toBeSelected) {
            this.setSelected(toBeSelected);
            this.curSelected.scrollIntoView(true);
        }
    },
    filterList:function() {
        var pattern ;
        try {
            pattern = new RegExp($F(this.inputElem), "i");
        } catch(e) {
            // make sure nothing is matched....
            pattern = /^$/
        }
        this.dropDown.descendants().each(function(elem) {
            if (elem.innerHTML.match(pattern)) {
                elem.show();
            } else {
                elem.hide();
            }
        })
    },
    selectFromDropDown:function(elem) {
    }

});

var CreateComboBoxDialog = Class.create({
    dialogstuff:
            "<div id='#{prefix}error' style=\"color: red; display:none;\"></div>\n" +
            "<table class=\"form\" border=\"0\">\n" +
            "    <tr style=\"border:0\">\n" +
            "        <td style=\"width:50px; border:0\"><label for='#{prefix}name'>#{namelabel}</label></td>\n" +
            "        <td style=\"width:250px; border:0\"><input id='#{prefix}name' type=\"text\" style=\"width:98%\"></td>\n" +
            "    </tr>\n" +
            "    <tr style=\"border:0\">\n" +
            "        <td style=\"border:0\"><label for='#{prefix}description'>#{descriptionlabel}</label></td>\n" +
            "        <td style=\"border:0\"><textarea id='#{prefix}description' cols=\"40\" rows=\"6\" style=\"width:98%\"></textarea></td>\n" +
            "    </tr>\n" +
            "    <tr style=\"border:0\">\n" +
            "        <td style=\"border:0\"><label for='#{prefix}number'>#{numberlabel}</label></td>\n" +
            "        <td style=\"border:0\"><input id='#{prefix}number' type=\"text\"></td>\n" +
            "    </tr>\n" +
            "</table>\n" +
            "<td><input id='#{prefix}timer' type=\"checkbox\" style=\"vertical-align: middle;\"><label for='#{prefix}timer'>#{timerlabel}</label></td>\n",
    initialize: function(select, message, button, dialogOptions, bcname) {
        this.select = select;
        this.idPrefix = select.id;
        this.combobox = new ComboBox(select, message);
        this.dialogOptions = dialogOptions;
        // specify jsContext:parent in dialogOptions if component is inside iframe and you wish the dialog to appear in the parent. Requires that DefaultKit.js / DefaultKit.css is already loaded in parentframe
        this.jsContext = dialogOptions.jsContext ? dialogOptions.jsContext : window;
        this.bcname = bcname;
        Event.observe(button, "click", this.openCreateDialog.bind(this));
        this.combobox.reinit();
    },
    openCreateDialog:function() {
        if (!this.createDialog) {

            var dialogTemplate = new Template(this.dialogstuff);
            this.dialogOptions.content = new this.jsContext.Element("div", {style:'display:none;'});

            this.dialogOptions.content.update(dialogTemplate.evaluate({
                prefix:this.idPrefix,
                namelabel:this.dialogOptions.namelabel,
                descriptionlabel:this.dialogOptions.descriptionlabel,
                numberlabel:this.dialogOptions.numberlabel,
                timerlabel:this.dialogOptions.timerlabel
            }));
            this.dialogOptions.onOk = this.onOk.bind(this);
            this.dialogOptions.onCancel = this.onCancel.bind(this);
            this.createDialog = new this.jsContext.Dialog.Box(this.dialogOptions);
        }
        this.createDialog.open();
        this.dialogOptions.content.show();
    },
    onOk:function() {
        var targetUrl = this.dialogOptions.targetUrl;
        var queryParam = {
            'name': this.jsContext.$F(this.idPrefix + 'name'),
            'description': this.jsContext.$F(this.idPrefix + 'description'),

            'setTimer': this.jsContext.$F(this.idPrefix + 'timer') == 'on'};
        if (this.bcname) {
            queryParam.contentReference = this.bcname;
            queryParam.targetClicks = this.jsContext.$F(this.idPrefix + 'number');
        } else {
            queryParam.resetInDays = this.jsContext.$F(this.idPrefix + 'number');
        }
        var qs = $H(queryParam).toQueryString();

        new Ajax.Request(targetUrl + qs, {
            onSuccess: this.onSuccess.bind(this),
            onFailure: this.onFailure.bind(this)
        });
    },
    onCancel:function() {
        this.jsContext.$(this.idPrefix + 'name').value = "";
        this.jsContext.$(this.idPrefix + 'description').value = "";
        this.jsContext.$(this.idPrefix + 'number').value = "";
        this.jsContext.$(this.idPrefix + 'timer').checked = false;
        this.jsContext.$(this.idPrefix + 'error').innerHTML = "";
        this.jsContext.$(this.idPrefix + 'error').hide();
        this.createDialog.close();
    },
    onSuccess:function(transport) {
        var newName = this.jsContext.$(this.idPrefix + 'name').value;
        var select = this.jsContext.$(this.select);
        var selectedOption = new Option(newName, newName, false, false);
        select.options[this.select.length] = selectedOption
        this.combobox.doUpdate(selectedOption);
        this.jsContext.$(this.idPrefix + 'name').value = "";
        this.jsContext.$(this.idPrefix + 'description').value = "";
        this.jsContext.$(this.idPrefix + 'number').value = "";
        this.jsContext.$(this.idPrefix + 'timer').checked = false;
        this.jsContext.$(this.idPrefix + 'error').innerHTML = "";
        this.jsContext.$(this.idPrefix + 'error').hide();
        this.createDialog.close();
    },
    onFailure:function(transport) {
        var theDiv = this.jsContext.$(this.idPrefix + 'error');
        theDiv.show();
        theDiv.innerHTML = transport.statusText;
    }
});

var agWidgets = {};

agWidgets.MultiRowTable = Class.create({
    initialize: function(tableId, maskId) {
        this._initialize(tableId,maskId);
    },
    _initialize: function(tableId, maskId) {
        this.table = $(tableId);
        this.tableId = tableId;
        this.mask = $(maskId);
        if (this.mask) {
            //console.log("Binding keyup evtlistener");
            this.mask.observe("keyup", this.hideItems.bind(this));
        }
        var self = this;
        $$("a[rel='" + tableId + "']").each(function(elem) {
            var func = elem.href.split("#")[1] ;
            elem.observe("click", function(evt) {
                self[func]();
                evt.stop();

            });

        });


    },
    clicked: function(evt) {

        var row = Event.findElement(evt, "div");
        row.toggleClassName('selected');
    },
    getIdList: function() {
        var val = '';
        $$('#' + this.tableId + ' > div').each(function(row) {
            if (val != '') {
                val = val + ";";
            }
            var realId = row.id.sub('.*_l2l_', '', 1);
            val = val + realId;
        });
        return val;
    },
    deleteSelected: function() {
        $$('#' + this.tableId + ' > div.selected').each(function(row) {
            row.remove();
        });
    },
    appendRow: function(text, id, toLeft, list2list) {
        var rw = document.createElement('div');
        rw.className = 'selectablerow';
        rw.id = id;
        rw.innerHTML = text;
        Event.observe(rw, 'click', this.clicked.bind(this));
        if (toLeft) {
            Event.observe(rw, 'dblclick', list2list.moveSingleRight.bind(list2list));
        } else {
            Event.observe(rw, 'dblclick', list2list.moveSingleLeft.bind(list2list));
        }
        var list = $$('#' + this.tableId + ' > div');
        if (list == null || list.length == 0) {
            $(this.tableId).appendChild(rw);
        } else {
            var elmAfter = this.findElementAfter(text);
            if (elmAfter) {
                elmAfter.insert({before:rw});
            } else {
                var last = list[list.length - 1];
                last.insert({after:rw});
            }

            this.hideItems();

        }
    },
    getSelectedItems: function() {
        var result = [];
        $$('#' + this.tableId + ' > div.selected').each(function(row) {
            result.push(row);
        });
        return result;
    },
    hideItems: function() {
       // console.log("Hiding itemt");
        if (!this.mask) {
            return;
        }
        var maskValue = this.mask.value;
        var pattern ;
        try {
            pattern = new RegExp(maskValue, "i");
        } catch(e) {
            // make sure nothing is matched....
            pattern = /^$/
        }
        $$('#' + this.tableId + ' > div').each(function(row) {
            var s = row.innerHTML.strip();
            if (!s.match(pattern)) {
                row.style.display = 'none';
                row.removeClassName('selected')
                row.removeClassName('exactMatch');
            } else {
                if (s==maskValue) {
                    row.addClassName('exactMatch');
                } else {
                    row.removeClassName('exactMatch');
                }
                row.style.display = '';
            }
        });
    },
    findElementAfter: function(text) {
        var result = null;
        var first = true;
        $$('#' + this.tableId + ' > div').each(function(row) {
            var rowText = row.innerHTML;
            if (text.toUpperCase() < rowText.toUpperCase()) {
                result = row;
                throw $break;
            } else {
                first = false;
            }
        });
        return result;
    },
    selectAll: function() {
        $$('#' + this.tableId + ' > div').each(function(row) {
            if (row.style.display != 'none' && !row.hasClassName('selected')) {
                row.addClassName('selected');
            }
        });
    },
    unselectAll: function() {
        $$('#' + this.tableId + ' > div').each(function(row) {
            if (row.style.display != 'none' && row.hasClassName('selected')) {
                row.removeClassName('selected');
            }
        });
    }
});

agWidgets.ListBoxToListBox = Class.create({
    initialize: function(table, maskId, hiddenFieldId) {

        this.table = $(table);
        this.maskField = $(maskId);

        var left = this.table.select(".leftContainer:first-child")[0];

        this.leftTable = this.createListBox(left.id,maskId);

        var right = this.table.select(".rightContainer:first-child")[0];

        this.rightTable = this.createListBox(right.id);
        this.hiddenField = $(hiddenFieldId);
        if (!this.hiddenField) {
            this.hiddenField = new Element("input", {type:"hidden",disabled:true});
            this.table.appendChild(this.hiddenField);
        }
        var self = this;
        $(left).select("div.selectablerow").each(function(row) {
            Event.observe(row, 'dblclick', self.moveSingleRight.bind(self));
            Event.observe(row, 'click', self.leftTable.clicked.bind(self.leftTable));
        });
        $(right).select("div.selectablerow").each(function(row) {
            Event.observe(row, 'dblclick', self.moveSingleLeft.bind(self));
            Event.observe(row, 'click', self.rightTable.clicked.bind(self.rightTable));
        });
        $(this.table).select("a[rel='listBoxToListBox']").each(function(elem) {

            var func = elem.href.split("#")[1];
            Event.observe(elem, 'click', function(evt) {
                self[func]();
                evt.stop();
            });
        });
        this.updateHidden();
    },
    createListBox:function(id,maskId) {
        return new agWidgets.MultiRowTable(id, maskId);
    },
    moveLeft: function() {
        var self = this;
        var elms = this.rightTable.getSelectedItems();
        this.rightTable.deleteSelected();
        elms.each(function(rw) {
            self.leftTable.appendRow(rw.innerHTML, rw.id, true, self);
        });
        this.updateHidden();
    },
    moveRight: function() {
        var self = this;
        var elms = this.leftTable.getSelectedItems();
        this.leftTable.deleteSelected();
        elms.each(function(rw) {
            self.rightTable.appendRow(rw.innerHTML, rw.id, false, self);
        });
        this.updateHidden();
    },
    moveSingleRight: function(evt) {
        var target = Event.findElement(evt, "div");
        target.remove();
        this.rightTable.appendRow(target.innerHTML, target.id, false, this);
        this.updateHidden();
    },
    moveSingleLeft: function(evt) {
        var target = Event.findElement(evt, "div");
        target.remove();
        this.leftTable.appendRow(target.innerHTML, target.id, true, this);
        this.updateHidden();
    },
    updateHidden: function() {
        this.hiddenField.value = this.leftTable.getIdList() + '|' + this.rightTable.getIdList();
    }
});

agWidgets.elementFactory=function(doc, tagName, attributes ) {
    var elem = $(doc.createElement(tagName));
    elem.writeAttribute(attributes);
    return elem;
};
