if (typeof PeopleInsite === 'undefined') {
    var PeopleInsite = {};
}

PeopleInsite.string = {};

PeopleInsite.GLOBALS = {};

/**
* Returns the substring of string after the last occurrence of pattern
*
* @param string
* @param pattern
* @return the substring, or string if no match
*/
PeopleInsite.string.substringAfterLast = function(string, pattern) {
    var part = string;
    var index;
    while (index = part.indexOf(pattern) >= 0) {
        part = part.substring(index, part.length);
    }
    return part;
};

PeopleInsite.net = function() {

    var Dom = YAHOO.util.Dom;

    /**
     *
     * @scope object with target propert
     */
    var defaultCallback = {
        success: function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, o.responseText, true);
                if (Dom.getStyle(this.target, "display") === "none") {
                    showById(this.target, "block");
                }
            }
        },
        failure: function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, PeopleInsite.net.errorMessage(o), true);
                if (Dom.getStyle(this.target, "display") === "none") {
                    showById(this.target, "block");
                }
            } else {
                PeopleInsite.tools.showErrorDialog(PeopleInsite.net.errorMessage(o));
            }
        },
        cache: false
    };

    /**
     *
     * @scope if scope in includes a target htmlElement, the response will be inserted as the body of that
     * element, without escaping it.  If target is not visible
     */
    var defaultMultipartCallback = {
        upload:function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, o.responseText, true);
                if (Dom.getStyle(this.target, "display") === "none") {
                    showById(this.target, "block");
                }
            }
        },
        failure:function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, PeopleInsite.net.errorMessage(o), true);
                if (Dom.getStyle(this.target, "display") === "none") {
                    showById(this.target, "block");
                }
            } else {
                PeopleInsite.tools.showErrorDialog(PeopleInsite.net.errorMessage(o));
            }
        }
    };

    return {
        /**
         * very simple JSON result detection.  The YUI method is unreliable for html responses.
         * This method assumes the JSON starts with an opening brace
         * @param body
         */
        isJSON : function(body) {
            var index = YAHOO.lang.trim(body).indexOf("{");
            return ((index >= 0) && (index <= 5));
        },
        /**
         * Safe eval of the JSON response into an Object
         * @param response { String }
         */
        deserializeJSON : function(response) {
            var obj = null;

            try {
                obj = YAHOO.lang.JSON.parse(response);
            } catch (e) {
                // ingore invalid json
            }

            return obj;
        },
        errorMessage: function(o) {
            switch (o.status) {
                case 0 :
                    return "Error communicating with the remote server (communications network error)";
                case -1:
                    return "";  // request interrupted
                default:
                    var statusText = YAHOO.lang.trim(o.getResponseHeader['XStatusText']);
                    if (!statusText) {
                        statusText = o.statusText;
                    }
                    return "The server reported an error: " + statusText;
            }
        },
        /**
         * make an asynchronous request and insert the result into the target div
         * If the callback is specified it will be used instead of the default
         * @param target { HTMLElement } optional to insert the HTML result, passed as target property in scope to callback
         * @param callback { Object } optional callback
         * @param cache { Boolean } optional, if set to true will allow browser to cache. Defualt is false
         * */

        asyncGet: function(href, target, callback, cache) {
            if (href) {
                YAHOO.util.Connect.resetFormState();
                if (!callback) {
                    callback = defaultCallback;
                }

                var scope = { target : target };
                
                YAHOO.util.Connect.asyncRequest('GET', href, {
                    success : callback.success,
                    failure: callback.failure,
                    scope: scope,
                    cache: (cache || false)
                 });

            }
        },
         /**
          * make an asynchronous post.
         * If the altCallback is specified it will be used instead of doing nothing */
        asyncPost: function(href, callback, scope) {
            if (href) {
                YAHOO.util.Connect.resetFormState();
                if (!callback) {
                    callback = defaultCallback;
                }
                YAHOO.util.Connect.asyncRequest('POST', href, {
                    success : callback.success,
                    failure: callback.failure,
                    scope: scope
                });
            }
        },
         /**
          * make an asynchronous submission of a form using the action and method of the form element.
          * If the altCallback is specified it will be used instead of doing nothing.
          *
          * @param elOrId { HTMLElement | String } the Form or child of the form
          * @param callback { Object } optional callback to invoke. If not specified uses a default callback.
          *  Implementation depends on whether submit is multipart or not.
          * @param scope { Object } optional object to use as scope for the callback
          * @param multipart { Boolean } optional flag, if true use a multipart encoding
          **/
        asyncSubmit: function(elOrId, callback, scope, multipart) {
            YAHOO.util.Connect.resetFormState();
            var formEl = PeopleInsite.dom.getAncestorForm(elOrId);

            if (formEl) {
                var href = formEl.action;
                var method = formEl.method || "POST";

                if (multipart) {
                    if (YAHOO.env.ua.ie) {
                        YAHOO.util.Connect.setForm(formEl, true, true); // multi-part, IE SSL
                    } else {
                        YAHOO.util.Connect.setForm(formEl, true); // multi-part
                    }
                    if (!callback) {
                        callback = defaultMultipartCallback;
                    }

                    YAHOO.util.Connect.asyncRequest(method, href, {
                        upload: callback.upload,
                        failure: (callback.failure ? callback.failure : defaultMultipartCallback.failure),
                        scope: scope,
                        cache: false
                    });
                } else {
                    YAHOO.util.Connect.setForm(formEl);
                    if (!callback) {
                        callback = defaultCallback;
                    }

                    YAHOO.util.Connect.asyncRequest(method, href, {
                        success : callback.success,
                        failure: (callback.failure ? callback.failure : defaultCallback.failure),
                        scope: scope,
                        cache: false
                    });
                }

            }
        },
        escape : encodeURIComponent,
        /**
             *  Derived from YUI 3 accepted change:
             *     http://github.com/isaacs/yui3/blob/master/src/querystring/js/querystring-stringify-simple.js
             *      accessed 5 July 2010
             *
                * <p>Converts a simple object to a Query String representation.</p>
                * <p>Nested objects, Arrays, and so on, are not supported.</p>
                *
                * @method stringify
                * @param obj {Variant} any arbitrary value to convert to query string
                * @param prefix {String} optional string to prefix each property name
                * @static
                */
        stringify : function (obj, prefix) {
            var sep = "&";
            var eq = "=";
            prefix = prefix || "";
            var qs = [], key, escape = PeopleInsite.net.escape;
            for (key in obj) if (obj.hasOwnProperty(key)) {

                if ((typeof obj[key] !== 'object') && (typeof obj[key] !== 'function')) {
                    qs.push(prefix+escape(key) + eq + escape(String(obj[key])));
                }
            }
            return qs.join(sep);
        }
    };
}();

PeopleInsite.dom = function() {
    return {
        select : function () {
            return {
                // replace the options for a select identified by id
                setOptions : function(idOrEl, optionEls) {
                    var selectEl;
                    if (typeof idOrEl === "object") {
                        selectEl = idOrEl;
                    } else {
                        selectEl = document.getElementById(idOrEl);
                    }
                    if (selectEl) {
                        selectEl.options.length = 0;   // clear existing options
                        for (var i = 0; i < optionEls.length; i++) {
                            //selectEl.options[selectEl.options.length] = options[i];
                            if (YAHOO.env.ua.ie) {
                                selectEl.add(optionEls[i]);
                            } else {
                                selectEl.add(optionEls[i], selectEl.options[i]);
                            }
                        }
                    }
                },
                setSelectedIndex : function(idOrEl, index) {
                    var selectEl;
                    if (typeof idOrEl === "object") {
                        selectEl = idOrEl;
                    } else {
                        selectEl = document.getElementById(idOrEl);
                    }

                    if (selectEl) {
                        selectEl.selectedIndex = index;
                    }
                },
                getSelectedIndex : function(idOrEl, defaultIndex) {
                    var selectEl;
                    if (typeof idOrEl === "object") {
                        selectEl = idOrEl;
                    } else {
                        selectEl = document.getElementById(idOrEl);
                    }

                    if (selectEl) {
                        return selectEl.selectedIndex;
                    } else {
                        return defaultIndex;
                    }
                },
                setSelectedValue : function(idOrEl, value) {
                    var selectEl;
                    if (YAHOO.lang.isString(idOrEl)) {
                        selectEl = YAHOO.util.Dom.get(idOrEl);
                    } else {
                        selectEl = idOrEl;
                    }

                    if (selectEl) {
                        for (var i = 0; i < selectEl.options.length; i++) {
                            if (selectEl.options[i].value == value) {
                                selectEl.selectedIndex = i;
                                break;
                            }
                        }
                    }
                },
                /**
                 * Get the selected value for the selected option, or the default value if not set
                 *
                 * @param idOrEl
                 * @param defaultValue
                 */
                getSelectedValue : function(idOrEl, defaultValue) {
                    var selectEl;
                    if (YAHOO.lang.isString(idOrEl)) {
                        selectEl = YAHOO.util.Dom.get(idOrEl);
                    } else {
                        selectEl = idOrEl;
                    }
                    if (selectEl) {
                        return selectEl.value;
                    } else {
                        return defaultValue;
                    }
                },
                /**
                 * Get the text (rather than the value) for the selected option
                 * @param id
                 * @param defaultValue
                 */
                getSelectedText: function(idOrEl, defaultValue) {
                    var selectEl;
                    var index = PeopleInsite.dom.select.getSelectedIndex(idOrEl, -1);
                    if (index >= 0) {
                        if (YAHOO.lang.isString(idOrEl)) {
                            selectEl = YAHOO.util.Dom.get(idOrEl);
                        } else {
                            selectEl = idOrEl;
                        }
                        return selectEl.options[index].text;
                    } else {
                        return defaultValue;
                    }
                },
                selectAllItemsInOption : function(optionEl) {
                    for (var j = 0; j < optionEl.options.length; j++) {
                        if (optionEl.options[j].value) {
                            optionEl.options[j].selected = true;
                        }
                    }
                },
                /** Update theOptionTransferSelect so the items are selected. Necessary before submitting a form */
                refreshOptionTransferSelects : function(containerElOrId) {
                    var containerEl = YAHOO.util.Dom.get(containerElOrId);

                    var optionTransferSelects = YAHOO.util.Dom.getElementsByClassName("optionTransferSelect", "div", containerEl);
                    if (optionTransferSelects) {
                        for (var i = 0; i < optionTransferSelects.length; i++) {
                            // select items in the left select
                            var leftSelectEl = PeopleInsite.dom.getFirstElement(optionTransferSelects[i], "select");
                            if (leftSelectEl) {
                                PeopleInsite.dom.select.selectAllItemsInOption(leftSelectEl);
                            }

                            var rightSelectEl = PeopleInsite.dom.getNthElement(optionTransferSelects[i], "select", 2);
                            if (rightSelectEl) {
                                PeopleInsite.dom.select.selectAllItemsInOption(rightSelectEl);
                            }
                        }
                    }
                }                
            };
        }(),
        escapeHTML : function(text, preserveBreaks) {
            if (text) {
                var result = text.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
                if (preserveBreaks) {
                    result = result.replace(/\n/g, "<br/>");
                }
                return result;
            } else {
                return text;
            }
        },
        /**
         *
         * @param id   { String | HTMLElement }
         * @param text
         * @param dontEscape
         */
        insertHTML : function (id /*or element*/, text, dontEscape) {
            var el;
            if (YAHOO.lang.isObject(id)) {
                el = id;
            } else {
                el = document.getElementById(id);
            }
            if (el) {
                var escaped = (dontEscape ? text : PeopleInsite.dom.escapeHTML(text));
                if (escaped) {
                    el.innerHTML = escaped;
                } else {
                    PeopleInsite.dom.clearHTML(el);
                }
            }
        },
        clearHTML : function(idOrEl) {
            var el;
            if (YAHOO.lang.isObject(idOrEl)) {
                el = idOrEl;
            } else {
                el = YAHOO.util.Dom.get(idOrEl);
            }
            if (el) {
                var Event = YAHOO.util.Event;
                while (el.firstChild) {
                    Event.purgeElement(el.firstChild, true); // recursively remove listeners
                    el.removeChild(el.firstChild);
                }
            }
        },
        /**
         * Clear the content of the specified element and replace it with the next content
         * @param id
         * @param text
         * @param dontEscape
         */
        replaceHTML : function(id /*or element*/, text, dontEscape) {
            var el;
            if (YAHOO.lang.isObject(id)) {
                el = id;
            } else {
                el = YAHOO.util.Dom.get(id);
            }
            if (el) {
                PeopleInsite.dom.clearHTML(el);
                PeopleInsite.dom.insertHTML(el, text, dontEscape);
            }
        },
        /**
         * Extract the innerHTML of the element with tag specified by name (that's a descendant of the htmlElement).
         * The first matching tag is used.
         * @param htmlElement { HTMLElement }
         * @param tagName { String } optional tag name to match
         */
        extractHTML : function(htmlElement, tagName) {
            if (tagName) {
                var elements = htmlElement.getElementsByTagName(tagName);
                if (elements && elements.length > 0) {
                    return elements[0].innerHTML;
                } else {
                    return null;
                }
            } else {
                return htmlElement.innerHTML;
            }
        },
        /**
         * @param {HTMLElement}   containerEl
         * @param {String} tag    type of tag
         */
        getFirstElement : function(containerEl, tag) {
            var elements = YAHOO.util.Dom.getElementsBy(function() {
                return true;
            }, tag, containerEl);
            if ((YAHOO.lang.isArray(elements)) && (elements.length > 0)) {
                return elements[0];
            } else {
                return null;
            }
        },
        /**
         * @param {HTMLElement}   containerEl
         * @param {String} tag    type of tag
         * @param {String} occurrence number starting at 1
         */
        getNthElement : function(containerEl, tag, occurrence) {
            var elements = YAHOO.util.Dom.getElementsBy(function() {
                return true;
            }, tag, containerEl);
            if ((YAHOO.lang.isArray(elements)) && (elements.length >= occurrence)) {
                return elements[occurrence-1];
            } else {
                return null;
            }
        },
        /**
         * @param {HTMLElement | String}   containerEl
         * @param {String} tag    type of tag
         * @param {String} className
         */
        getFirstElementByClass : function(containerEl, tag, className) {
            var elements = YAHOO.util.Dom.getElementsByClassName(className, tag, containerEl);
            if ((YAHOO.lang.isArray(elements)) && (elements.length > 0)) {
                return elements[0];
            } else {
                return null;
            }
        },
        /**
         * Determine if the element is a FORM
         *
         * @param elOrId { HTMLElement | String }
         * @return HTMLElement if the element is a Form, otherwise null;
         */
        isForm : function(elOrId) {
            var el;

            if (typeof elOrId === 'string') { // id
                el = document.getElementById(elOrId);
            } else {
                el = elOrId;
            }

            if (el) {
                if (el.tagName === "FORM") {
                    return el;
                }
            }
            return null;
        },
        /**
         * Get a form from the DOM by its id.  Ensures there's no conflict with elements named
         * id in the form (which was a bug in YUI's equivalent getElementById method)
         * @param el
         */
        getFormById : function(el) {
            var id, nodes, c, i, len;

            if (el) {
                if (typeof el === 'string') { // id
                    id = el;
                    el = document.getElementById(el);
                }

                return el; // some other object, just pass it back
            }

            return null;
        },
        /**
         * Get the HTMLElement that is a FORM and ancestor of the argument
         * @param elOrId { HTMLElement | String } descendant of the form
         */
        getAncestorForm : function(elOrId) {
            var formEl = PeopleInsite.dom.isForm(elOrId);
            if (formEl) {
                // the argument is the form
                return formEl;
            } else {
                return YAHOO.util.Dom.getAncestorByTagName(elOrId, 'FORM');
            }
        },
        /**
         * When the specified select element has the target Value, show the target element, otherwise hide it
         * @param selectEl
         * @param targetValue
         * @param targetId
         */
        showBySelect: function(selectEl, targetValue, targetId) {
            var actualValue = PeopleInsite.dom.select.getSelectedValue(selectEl);
            if (actualValue === targetValue) {
                showById(targetId);
            } else {
                hideById(targetId);
            }
        },
        /**
         * Toggle visibility of elements in the specified container.  The elements need to carry the
         * toggle-visibility class and a data attribute specified the value to match
         *
         * The data-match attribute may contain comma-separated values for OR
         *
         * @param selectEl  { HTMLElement }
         * @param containerEl {HTMLElement | String } container element or its ID
         * @param disable { boolean } if true, hidden inputs are disabled
         */
        toggleVisibility: function(selectEl, containerEl, disable) {
            var actualValue = PeopleInsite.dom.select.getSelectedValue(selectEl);

            var els = YAHOO.util.Dom.getElementsByClassName("toggle-visibility", "div", containerEl);
            for (var i = 0; i < els.length; i++) {
                var val = YAHOO.util.Dom.getAttribute(els[i], "data-match");
                if (val) {
                    var parts = val.split(",");
                    var matched = false;
                    for (var j = 0; j < parts.length; j++) {
                        if (parts[j] === actualValue) {
                            YAHOO.util.Dom.setStyle(els[i], "display", "block");
                            matched = true;
                            if (disable) {
                                // enable input elements
                                YAHOO.util.Dom.getElementsBy(function(el) {
                                    return PeopleInsite.dom.isFormInput(el);
                                }, null, els[i],
                                   function (el) {
                                    el.removeAttribute("disabled");
                                    //YAHOO.util.Dom.setAttribute(el, "disabled", "false");
                                });
                            }
                        }
                    }
                    if (!matched) {
                        YAHOO.util.Dom.setStyle(els[i], "display", "none");
                        if (disable) {
                            // disable input elements
                            YAHOO.util.Dom.getElementsBy(function(el) {
                                return PeopleInsite.dom.isFormInput(el);
                            }, null, els[i],
                               function (el) {
                                YAHOO.util.Dom.setAttribute(el, "disabled", "disabled");
                            });
                        }
                    }
                }
            }
            return true;
        },
        /**
         * Toggle visibility of elements in the specified container.  The elements need to carry the
         * toggle-visibility class and an id specified the value to match
         * @param {HTMLElement | String }  containerEl
         * @param { String } matchIdOrClass       The id or class of the element(s) to show. ID takes precedence.
         */
        toggleVisibilityMatching: function(containerEl, matchIdOrClass) {
            var els = YAHOO.util.Dom.getElementsByClassName("toggle-visibility", "div", containerEl);
            for (var i = 0; i < els.length; i++) {
                var val = YAHOO.util.Dom.getAttribute(els[i], "id");
                var classMatched  = YAHOO.util.Dom.hasClass(els[i], matchIdOrClass);
                if ((val && val === matchIdOrClass) || classMatched) {
                    YAHOO.util.Dom.setStyle(els[i], "display", "block");
                } else {
                    YAHOO.util.Dom.setStyle(els[i], "display", "none");
                }
            }
            return true;
        },
        /**
         * Toggle the classname of elements in the container. El will have the class set, the others
         * will have the class removed.  Elements need to carry the toggle-class class
         * @param el { HTMLElement }  el element to enable the class on
         * @param containerEl { HTMLElement | String }  
         * @param className { String }  The className to add/remove

         */
        toggleClasses: function(el, containerEl, tagName, className) {
            var els = YAHOO.util.Dom.getElementsByClassName("toggle-class", tagName, containerEl);
            for (var i = 0; i < els.length; i++) {
                if (els[i] === el) {
                    YAHOO.util.Dom.addClass(els[i], className);
                } else {
                    YAHOO.util.Dom.removeClass(els[i], className);
                }
            }
            return true;
        },
        /** Get the target element for an event, searching ancestors matching by class name if necessary
         * @param className
         **/
        getTargetByClassName: function(event, className) {
            var el = YAHOO.util.Event.getTarget(event);
            var found = false;
            if (el) {
                if (YAHOO.util.Dom.hasClass(el, className)) {
                    found = true;
                } else {
                    el = YAHOO.util.Dom.getAncestorByClassName(el, className);
                }
            }
            return el;
        },
        /** Creates HTML elements in the body that contain a modal dialog
         * Check whether is exists already and reuses the emptied container if appropriate
         *
         * creates :
         * body
         *  div id=gen0 class=className
         *     div id=gen1
         *     /div
         *  /div
         *
         * @param  className { String } optional class name to assign to the container                 *
         * @return {HTMLElement} container element
         * */
        prepareDialogContainer : function(className) {

           // create a container at the top of the body
           var outerId = YAHOO.util.Dom.generateId();
           var innerId = YAHOO.util.Dom.generateId();

           var containerEl;
           if (className) {
              containerEl = YAHOO.util.Dom.create('div', { id : outerId, 'className' : className }, [
                 YAHOO.util.Dom.create('div', {id : innerId })] );
           } else {
              containerEl = YAHOO.util.Dom.create('div', { id : outerId }, [
                 YAHOO.util.Dom.create('div', {id : innerId })] );
           }

           YAHOO.util.Dom.insertBefore(containerEl, YAHOO.util.Dom.getFirstChild(document.body));

            return containerEl;
        },
        /**
         *
         *
         * @param el  { HTMLElement }
         * @return true if the element is an HTML Form input (input, select, textarea)
         */
        isFormInput : function(el) {
            if (el) {
                return ((el.nodeName === "INPUT") || (el.nodeName === "SELECT") || (el.nodeName === "TEXTAREA"));
            } else {
                return false;
            }
        },
        /** Move the specified element to the new parent in the dom */
        moveTo : function(sourceEl, newParentEl) {
            if (newParentEl) {
                newParentEl.appendChild(sourceEl);
            }
        },
        /**
             * Read the content of the metadata attribute with the specified name. If multiple attributes have the same name the
             * results is a comma separated string
             * @param name { String}
             * @returns { String }  or null if not found
             */
        readMetaAttribute : function(name) {
           var Dom = YAHOO.util.Dom;
           try {
               var headEl = Dom.getElementBy(function() { return true; }, "head");
               if (headEl) {
                   var meta = YAHOO.util.Dom.getElementsBy(function(el) {
                        return (YAHOO.util.Dom.getAttribute(el, "name") === name);
                    }, "meta", headEl);
                    if (meta && meta.length > 0) {

                        var value = "";
                        var first = true;
                        for (var i = 0; i < meta.length; i++) {
                            var thisValue = YAHOO.util.Dom.getAttribute(meta[i], "content");

                            if (thisValue && thisValue.length > 0) {
                                if (!first) {
                                    value += ",";
                                } else {
                                    first = false;
                                }

                                value += thisValue;
                            }
                        }
                        return value; 
                    }
               }
           } catch (e) {

           }
           return null;
        },
        /**
              * Refresh the value of the target based on the value of the source
              * @param sourceEl
             * @param targetElOrId
             */
        refreshValue : function(sourceEl, targetElOrId) {
            var targetEl = YAHOO.util.Dom.get(targetElOrId);
            var value = sourceEl.value;
            if (targetEl) {
                targetEl.value = value;
            }
        },
        /**
         * Invoke a function specified by a string name in any namespace
         *
         * @param functionName { String } name of the method including namespace
         * @param scope { Object }
         * @return the result of invoking the function.  If the function is not valid an exception may be thrown
         */
        invoke : function(functionName, scope /*, args */) {
            var args = Array.prototype.slice.call(arguments, 2);
            var namespaces = functionName.split(".");
            var func = namespaces.pop();
            var context = window;
            for (var i = 0; i < namespaces.length; i++) {
                context = context[namespaces[i]];
            }

            return context[func].apply(scope, args);
        },
        /**
         * Set the style property of all matching elements in the containerEl
         *
         * @param containerEl
         * @param tag
         * @param className
         * @param styleProperty
         * @param styleValue
         */
        setStyleByClass : function(containerEl, tag, className, styleProperty, styleValue) {
            YAHOO.util.Dom.getElementsByClassName(className, tag, containerEl, function(el) {
                YAHOO.util.Dom.setStyle(el, styleProperty, styleValue);
            })
        }
    };
}();

PeopleInsite.dom.checkbox = {
    isCheckbox : function(idOrEl) {
        var el;
        if (YAHOO.lang.isString(idOrEl)) {
            el = Dom.get(idOrEl);
        } else {
            el = idOrEl;
        }
        if (el) {
            if (el.tagName === 'INPUT') {
                if (el.type) {
                    if (el.type.toUpperCase() === 'CHECKBOX') {
                        return true;
                    }
                }
            }
        }
        return false;
    },
    /** Update the status of all the checkboxes within the container
       * @param checked { boolean | HTMLElement }  if boolean, true to set, false to clear. If HTML element, sets the checked status to the same as the element*/
    checkAll : function(containerId, checked) {
        var checkboxes = YAHOO.util.Dom.getElementsBy(PeopleInsite.dom.checkbox.isCheckbox, "input", containerId);
        if (YAHOO.lang.isObject(checked)) {
            checked = checked.checked; // read the status
        }
        for (var i = 0; i < checkboxes.length; i++) {
            setCheckedValue(checkboxes[i], checked);
        }
    }
};

PeopleInsite.calendar = function () {

    var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    
    function pad(value) {
        if (YAHOO.lang.isNumber(value)) {
            if (value < 10) {
                return "0" + value;
            } else {
                return value;
            }
        } else {
           if (value && value.length === 1) {
               return "0" + value;
            } else {
                return value;
            }
        }
    }

    function lookupDateRadio(id) {
        var radioId = id + "Specified";
        var radioEl = YAHOO.util.Dom.get(radioId);
        if (radioEl) {
            var radioName = radioEl.name;
            var parentForm = YAHOO.util.Dom.getAncestorByTagName(id, 'FORM');
            var radio = parentForm[radioName];
            return radio;
        }
    }

    function setDateSpecified(id, specified) {
        setCheckedValue(lookupDateRadio(id), specified);
    }

    /** if there's a radio button to enable the date, check its state, otherwise the presence of the
     *  selects is sufficient
     * @param id
     */
    function isDateSpecified(id) {
        var radio = lookupDateRadio(id);
        if (radio) {
            return getCheckedValue(radio) == "true";
        } else {
            return true;
        }
    }

    function setDateSelection(id, day, month, year) {
        PeopleInsite.dom.select.setSelectedValue(id + 'Day', pad(day));
        PeopleInsite.dom.select.setSelectedValue(id + 'Month', pad(month));
        PeopleInsite.dom.select.setSelectedValue(id + 'Year', year);
    }

    function syncDateFromInput(id) {
        var el = document.getElementById(id);
        if (el) {
            var date = parseDate(el.value);
            if (date) {
                setDateSelection(id, date.day, date.month, date.year);
                setDateSpecified(id, true);
            } else {
                var today = PeopleInsite.calendar.today();
                setDateSelection(id, today.day, today.month, today.year);
                // initialise the input with value, but track that it hasn't been set
                el.value = formatSystemDate(today.day, today.month, today.year);
                setDateSpecified(id, false);
            }
        }
    }

    function syncDateFromSelect(id) {
        var today = PeopleInsite.calendar.today();
        var dateElement;
        if (isDateSpecified(id)) {
            var day = PeopleInsite.dom.select.getSelectedValue(id + 'Day', today.day);
            var month = PeopleInsite.dom.select.getSelectedValue(id + 'Month', today.month);
            var year = PeopleInsite.dom.select.getSelectedValue(id + 'Year', today.year);

            dateElement = document.getElementById(id);
            if (dateElement) {
                dateElement.value = formatSystemDate(day, month, year);
            }
        } else {
            dateElement = document.getElementById(id);
            if (dateElement) {
                dateElement.value = "";
            }
        }
    }

    function selectFocusCallback(e, id) {
        setDateSpecified(id, true);
    }

    function selectChangeCallback(e, id) {
        syncDateFromSelect(id);
    }

    //            function radioChangeCallback(e) {
    //                setExpiryDateSpecified(getElementById("expiryDateNotSpecified").checked);
    //            }

    function setupListeners(id) {
        YAHOO.util.Event.addListener([id + 'Day', id + 'Month', id + 'Year'], 'focus', selectFocusCallback, id, false);
        // update the hidden value when a select changes
        YAHOO.util.Event.addListener([id + 'Day', id + 'Month', id + 'Year'], 'change', selectChangeCallback, id, false);
    }

    function formatDate(day, month, year) {
        return day + " " + PeopleInsite.calendar.monthName(month) + " " + year;
    }

    function formatSystemDate(day, month, year) {
        return day + "/" + month + "/" + year;
    }

    /**
     * Parse a date in the format dd/MM/yy, dd/MM/yyyy or dd/MM/nn where [ 100 <=. nn < 1000 ] eg. 102
     * If there is whitespace text after the year it will be truncated (eg. if it includes the time)
     *
     * @param dateString
     */
    function parseDate(dateString) {
        if (dateString !== null) {
            var components = dateString.split("/");
            if ((components) && (components.length == 3)) {

                if (components[2].indexOf(" ") >= 0) {
                    // truncate text after whitespace
                    components[2] = components[2].substring(0, components[2].indexOf(" "));
                }

                var yearValue = Number(components[2]);  // typecast for addition

                var calculatedYear;
                if (yearValue < 20) {   // todo: these offsets need to roll (or force format of date params)
                    // eg "11"
                    calculatedYear = yearValue + 2000;
                } else {
                    if (yearValue < 1000) {
                        // eg. 50
                        calculatedYear = yearValue + 1900;
                    } else {
                        calculatedYear = yearValue;
                    }
                }

                return {
                    day : components[0],
                    month: components[1],
                    year: calculatedYear
                };
            }
        }
        return null;
    }

    /**
     * @description parse a date in JSON format into a independent date map
     * @param dateString
     * @return map of date attributes
     */
    function parseJSONDate(dateString) {
        if (dateString !== null) {
            var index = dateString.indexOf('T');
            var endMark = dateString.indexOf("+");
            if (endMark < 0) {
                endMark = dateString.indexOf("Z");
            }
            if (endMark < 0) {
                endMark = dateString.length;
            }

            var datePart = dateString.substring(0, index);
            var timePart = dateString.substring(index + 1, endMark);

            var dateComponents = datePart.split("-");
            var timeComponents = timePart.split(":");

            if ((dateComponents) && (dateComponents.length == 3)) {
                return {
                    day : dateComponents[2],
                    month: dateComponents[1],
                    year: dateComponents[0],
                    hour: timeComponents[0],
                    min: timeComponents[1],
                    sec: timeComponents[2]
                };
            }
        }
        return null;
    }

    /**
     * Parse time string in the format hh:mm:ss or hh:mm
     * @param timeString
     */
    function parseTime(timeString) {
        var timeComponents = timeString.split(":");
        if (timeComponents.length == 3) {
            return {
                hour: timeComponents[0],
                min: timeComponents[1],
                sec: timeComponents[2]
            };
        } else {
            if (timeComponents.length == 2) {
                return {
                    hour: timeComponents[0],
                    min: timeComponents[1],
                    sec: 0
                };

            }
        }
        return null;
    }

    /**
     * @description parse a time string into a JS Date object
     * @param timeString
     * @param baseDate  the base date to use (it will be updated_
     * @return updated Date object or null if invalid
     */
    function parseTimeAsJSDate(timeString, baseDate) {
        var timeObj = parseTime(timeString);
        if (timeObj) {
            baseDate.setHours(timeObj.hour);
            baseDate.setMinutes(timeObj.min);
            baseDate.setSeconds(timeObj.sec);
            baseDate.setMilliseconds(0);
            return baseDate;
        } else {
            return null;
        }
    }

    /* Convert jsDate or JSON date to a simple browser-independent object */
    function convertDate(jsDate) {
        if (typeof jsDate == 'object') {
            var year = jsDate.getYear();
            if (year < 1000) {
                year += 1900;
            }
            return {
                day : jsDate.getDate(),
                month: jsDate.getMonth() + 1,
                year: year,
                hour: jsDate.getHours(),
                min: jsDate.getMinutes(),
                sec: jsDate.getSeconds()
            };
        } else {
            if ((typeof jsDate == 'string') && (jsDate.indexOf('T') > -1)) {
                return parseJSONDate(jsDate);
            } else {
                return null;
            }
        }
    }

    return {
        // array of Option's
        daysOfWeek : function() {
            var dayOptions = [];
            for (var i = 0; i < 31; i++) {
                dayOptions[i] = new Option(i + 1, pad(i + 1), false, false);
            }
            return dayOptions;
        },
        monthsOfYear : function() {
            var monthOptions = [];
            for (var i = 0; i < months.length; i++) {
                monthOptions[i] = new Option(months[i], pad(i + 1), false, false);
            }
            return monthOptions;
        },
        monthName : function(month) {     // 1-12
            if ((month >= 1) && (month <= months.length)) {
                return months[month - 1];
            } else {
                return null;
            }
        },
        years : function(from, to, desc) {
            var yearOptions = new Array();
            var i;
            if (desc) {
                for (i = 0; i <= (to - from); i++) {
                    yearOptions[i] = new Option(to - i, to - i, false, false);
                }
            } else {
                for (i = 0; i <= (to - from); i++) {
                    yearOptions[i] = new Option(from + i, from + i, false, false);
                }
            }
            return yearOptions;
        },
        /**
         * @return today as a Date map
         */
        today: function() {
            return convertDate(new Date());
        },
        /**
         * @param  minutes { int } optional number of minutes to add to now
         * @return today { jsDate} as a Date map
         */
        now: function(minutes, seconds) {
            var now = new Date();
            if (minutes || seconds) {
                var offsetSecs = ((minutes || 0) * 60) + (seconds || 0);
                now.setTime(now.getTime() + (offsetSecs * 1000));
            }
            return now;
        },
        /**
         * @return tomorrow as a Date map
         */
        tomorrow: function() {
            var tomorrow = new Date();
            tomorrow.setDate(tomorrow.getDate() + 1);
            return convertDate(tomorrow);
        },
        initDatePicker: function(id, minYear, maxYear, desc) {
            var el = YAHOO.util.Dom.get(id);
            // the data-initialised attribute is a flag so the same datepicker element doesn't get initialised twice
            if (el && !YAHOO.util.Dom.getAttribute(el, "data-initialised")) {
                YAHOO.util.Dom.get(id).setAttribute("data-initialised", "true");
                PeopleInsite.dom.select.setOptions(id + 'Day', PeopleInsite.calendar.daysOfWeek());
                PeopleInsite.dom.select.setOptions(id + 'Month', PeopleInsite.calendar.monthsOfYear());
                PeopleInsite.dom.select.setOptions(id + 'Year', PeopleInsite.calendar.years(minYear, maxYear, desc));
                syncDateFromInput(id);
                setupListeners(id);
            }
        },
        /** @description initialise the datepickers within the specified container
         *
         * @param minYear    { int } default minimum year (if not specified by an attribute)
         * @param maxYear    { int } default maximum year (if not specified by an attribute)
         * @param desc       { boolean } true if high to low
         * */
        initDatePickers: function(idOrEl, minYear, maxYear, desc) {
            var container;
            if (YAHOO.lang.isObject(idOrEl)) {
                container = idOrEl;
            } else {
                container = YAHOO.util.Dom.get(idOrEl);
            }
            if (container) {
                var datepickers = YAHOO.util.Dom.getElementsByClassName("datepicker", "input", container);
                for (var i = 0; i < datepickers.length; i++) {
                    var id = datepickers[i].id;

                    var actualMinYear = YAHOO.util.Dom.getAttribute(datepickers[i], "data-minyear") || minYear;
                    var actualMaxYear = YAHOO.util.Dom.getAttribute(datepickers[i], "data-maxyear") || maxYear;
                    var actualDesc = YAHOO.util.Dom.getAttribute(datepickers[i], "data-desc") || desc;

                    PeopleInsite.calendar.initDatePicker(id, actualMinYear, actualMaxYear, actualDesc);
                }
            }
        },
        /** @param id of the hidden datepicker element */
        refreshDatePicker: function(id) {
            if (YAHOO.util.Dom.get(id)) {
                syncDateFromSelect(id);
            }
        },
        refreshDatePickers: function(containerEl) {
            var datePickers = YAHOO.util.Dom.getElementsByClassName("datepicker", "input", containerEl);
            for (var i = 0; i < datePickers.length; i++) {
                PeopleInsite.calendar.refreshDatePicker(datePickers[i].id);
            }
        },
        formatSystemDateTime : function(day, month, year, hour, min, sec) {
            return formatSystemDate(day, month, year) + " " + hour + ":" + min + ":" + sec;
        },
        formatSystemDateTimeObject : function(oDateTime) {
            return formatSystemDate(oDateTime.day, oDateTime.month, oDateTime.year) + " " + oDateTime.hour + ":" + oDateTime.min + ":" + oDateTime.sec;
        },
        formatSystemJSDateTime: function(jsDate) {
            var date = convertDate(jsDate);
            return PeopleInsite.calendar.formatSystemDateTime(date.day, date.month, date.year, date.hour, date.min, date.sec);
        },

        formatSystemJSDate: function(jsDate) {
            var date = convertDate(jsDate);
            return formatSystemDate(date.day, date.month, date.year);
        },
        formatSystemDate: function(day, month, year) {
            return day + "/" + month + "/" + year;
        },
        /** Convert jsDate or dateString to simple date map  */
        convertDate: function(date) {
            return convertDate(date);
        },
        formatJSDisplayTime : function(jsDate) {
            var time = convertDate(jsDate);
            return pad(time.hour) + ":" + pad(time.min) + ":" + pad(time.sec);
        },
        /**
         * 10:00 am Monday 24 January 2009
         * @param jsDate
         */
        formatJSDisplayDayDate : function(jsDate) {
            var day = days[jsDate.getDay()];
            var time = convertDate(jsDate);
            return day+" "+time.day+" "+months[time.month-1]+" "+time.year;
        },
        /**
         * @description long millseconds to display format [hours:]mins:secs
         * @param intervalMS  internal in MS
         *
         */
        formatMSDisplayTime : function(intervalMS) {
            var hours = 0;
            var remainder;
            if (intervalMS > 3600000) {
                hours = Math.floor(intervalMS / 3600000);
                remainder = intervalMS - (hours * 3600000);
            } else {
                remainder = intervalMS;
            }
            var mins = Math.floor(remainder / 60000);
            remainder = remainder - (mins * 60000);

            var secs = Math.floor(remainder / 1000);
            var result;
            if (hours > 0) {
                result = hours + ":" + pad(mins) + ":" + pad(secs);
            } else {
                if (mins > 0) {
                    result = mins + ":" + pad(secs);
                } else {
                    result = secs + "s";
                }
            }

            return result;
        },
        /**
         * @description parse a time string in the hh:mm:ss or hh:mm format into a JS Date object
         * @param timeString
         * @param jsBaseDate  the base date to use (it will be updated_
         * @return updated jsBaseDate or null if invalid
         **/
        parseTimeAsJSDate : function(timeString, jsBaseDate) {
            return parseTimeAsJSDate(timeString, jsBaseDate);
        },
        /**
         * @description parse a date in JSON format into a independent date map
         * @param jsonDateString
         * @return map of date attributes
         */
        parseJSONDate : function(jsonDateString) {
            return parseJSONDate(jsonDateString);
        },
        convertJSONDateToJSDate : function(jsonDateString) {
            var dateMap = parseJSONDate(jsonDateString);
            if (dateMap) {
                var jsDate = new Date();
                jsDate.setFullYear(dateMap.year, (dateMap.month - 1) % 12, dateMap.day);
                jsDate.setHours(dateMap.hour);
                jsDate.setMinutes(dateMap.min);
                jsDate.setSeconds(dateMap.sec);
                jsDate.setMilliseconds(0);
                return jsDate;
            }
            return null;
        }
    };
}();

PeopleInsite.validation = function() {
    // get the current value of the specified field
    function currentValue(field) {
        if (field.tagName === 'INPUT') {
            return field.value;
        } else {
            if (field.tagName === 'SELECT') {
                return field.options[field.selectedIndex].value;
            }
        }
        return null;
    }

    function insertFieldError(containerId, message) {
        PeopleInsite.dom.insertHTML(containerId,
                "<span class='errormessage'>" + message + "</span>", true);
        showById(containerId, "block");
    }

    function reportFieldError(validatorSpec, defaultMessage) {
        var message = (validatorSpec.message ? validatorSpec.message : defaultMessage);
        if (validatorSpec.containerId) {
            insertFieldError(validatorSpec.containerId, message);
        }
    }

    function clearFieldError(validatorSpec) {
        if (validatorSpec.containerId) {
            PeopleInsite.dom.clearHTML(validatorSpec.containerId);
        }
    }

    return {
        requiredString: function(field) {
            var value = currentValue(field);
            return PeopleInsite.validation.isNonBlank(value);
        },
        requiredEmail : function(field) {
            var value = currentValue(field);
            return PeopleInsite.validation.isValidEmail(value);
        },
        requiresEmailOrBlank : function(field) {
            var value = currentValue(field);
            if (PeopleInsite.validation.isNonBlank(value)) {
                return PeopleInsite.validation.isValidEmail(value);
            } else {
                return true;
            }
        },
        optionalABN: function(field) {
            var value = currentValue(field);
            if (PeopleInsite.validation.isNonBlank(value)) {
                var regExp = /^[0-9]{11}$/;
                return value.match(regExp) !== null;
            } else {
                return true;
            }
        },
        isNonBlank: function(value) {
            var trimmed = YAHOO.lang.trim(value);
            return (trimmed && trimmed.length > 0);
        },
        /* executes all the validators defined in the settings
        *
        * @param settings  { Object }
        * @param formEl    { HTMLElement} optional form to use, overriding the settings */
        validate: function(settings, formEl) {
            var okay = true;
            var form = formEl;
            if (settings && settings.validators) {
                if (!form) {
                    if (settings.formName) {
                        form = document[settings.formName];
                    }
                }
                if (!form) {
                    form = document.getElementById(settings.formName);
                }
                for (var i = 0; i < settings.validators.length; i++) {
                    var element;
                    var name = settings.validators[i].name;
                    var validators = settings.validators[i].validators;

                    if (name && form) {
                        element = form[name];
                    } else {
                        element = document.getElementById(settings.validators[i].id);
                    }

                    if (element && validators) {
                        for (var j = 0; j < validators.length; j++) {
                            var validator = validators[j].validator;
                            if (validator) {
                                try {
                                    var fieldOkay = validator(element);
                                    if (!fieldOkay) {
                                        reportFieldError(validators[j], "This field is incomplete or invalid");

                                        okay = false;
                                    } else {
                                        clearFieldError(validators[j]);
                                    }
                                } catch (e) {
                                    if (validators[j].containerId) {
                                        reportFieldError(validators[j], "A validation error occurred while processing this field");
                                    }
                                    okay = false;
                                }
                            } else {
                                if (validators[j].containerId) {
                                    reportFieldError(validators[j], "The validator for this field is undefined");
                                }
                                okay = false;
                            }
                        }
                    }
                }
            } else {
                okay = false;
            }
            return okay;
        },
        filterNumericKeypress : function(e) {
            var keyChar;
            var numeric = /\d/;
            if (YAHOO.env.ua.ie) {
                keyChar = String.fromCharCode(e.keyCode);
            } else {
                keyChar = String.fromCharCode(e.which);
            }

            if (!numeric.test(keyChar)) {
                YAHOO.util.Event.preventDefault(e);
            }
        },
        acceptNumericOnly : function(el) {
            YAHOO.util.Event.addListener(el, 'keypress', PeopleInsite.validation.filterNumericKeypress);
        },
        /** A basic implementation of an email validator */
        isValidEmail : function(str) {
            if (str && str.length > 0) {
                return str.indexOf("@") > 0;
            } else {
                return false;
            }
        }
    };
}();

PeopleInsite.dataTable = function() {

    function formatDateTime(elCell, oRecord, oColumn, date) {
        if (date) {
            elCell.innerHTML = PeopleInsite.calendar.formatSystemJSDateTime(date);
        } else {
            PeopleInsite.dom.clearHTML(elCell);
        }
    }

    function formatDate(elCell, oRecord, oColumn, date) {
        if (date) {
            elCell.innerHTML = PeopleInsite.calendar.formatSystemJSDate(date);
        } else {
            PeopleInsite.dom.clearHTML(elCell);
        }
    }

    return {
        /* Render a YUI datatable from a JSON com.peopleinsite.data.TableModel */
        render: function(container, tableModel, formatters, emptyMsg, tableProperties) {

            var showTable = true;

            if (emptyMsg) {
                if (tableModel.rows.length === 0) {
                    PeopleInsite.dom.insertHTML(container, emptyMsg, true);
                    showTable = false;
                }
            }

            if (showTable) {
                var columnDefs = [];
                var columns = 0;
                var fields = 0;
                // mapping from ColumnType to a YUI parser (ensures correct sorting)
                var parserMap = {
                    "String" : YAHOO.util.DataSource.parseString,
                    "Number" : YAHOO.util.DataSource.parseString,
                    "Date"   : YAHOO.util.DataSource.parseDate
                };

                // mapping from ColumnFormat to a YUI formatter
                var formatterMap = {
                    "Number" : "number",
                    "Date"   : formatDate,
                    "DateTime" : formatDateTime
                };
                if (formatters) {
                    // include custom formatters
                    for (var key in formatters) {
                        formatterMap[key] = formatters[key];
                    }
                }

                var dataSource = new YAHOO.util.DataSource(tableModel.rows);
                dataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
                dataSource.responseSchema = {
                    fields: []
                };

                // setup the column definitions
                for (var columnNo = 0; columnNo < tableModel.columns.length; columnNo++) {
                    var columnModel = tableModel.columns[columnNo];

                    if (!columnModel.hidden) {
                        var columnDef = {
                            key: columnModel.name,

                            //                        key: "c"+columnNo,
                            label: columnModel.heading,
                            abbr: columnModel.abbr
                        };
                        if (columnModel.sortable) {
                            columnDef['sortable'] = columnModel.sortable;

                            if (columnModel.sortFunction) {
                                columnDef['sortable'] = columnModel.sortable;
                                columnDef['sortOptions'] = {
                                    sortFunction : function() {
                                        // sortFunction decorator that keeps a reference to the column key
                                        var sortFunction = columnModel.sortFunction;
                                        var key = columnDef.key;
                                        return function(a, b, desc) {
                                            return sortFunction(key, a, b, desc);
                                        };
                                    }() // note execution returns the decorated function
                                };
                            }
                        }
                        // assign a parser if defined and known
                        if (parserMap[columnModel.type]) {
                            columnDef.parser = parserMap[columnModel.type];
                        }
                        // assign a formatter if defined and known
                        if (formatterMap[columnModel.format]) {
                            columnDef.formatter = formatterMap[columnModel.format];
                        }

                        if (columnModel.width) {
                            columnDef.width = columnModel.width;
                        }

                        dataSource.responseSchema.fields[fields++] = columnDef.key;

                        columnDefs[columns++] = columnDef;
                    }
                }

                if (!tableProperties) {
                    tableProperties = {};
                }

                if (!tableProperties['scrollable']) {
                    // caption is not permitted for scrollable in the beta datatable
                    tableProperties['caption'] = tableModel.caption;
                }
                // disable caption in IE6 - does not work when table is inside an overlay
                if (YAHOO.env.ua.ie <= 6) {
                    tableProperties['caption'] = null;
                }
                tableProperties['summary'] = tableModel.summary;

                if (tableModel.rows.length <= 10) {
                    // disable pagination if insufficient rows to justify it
                    tableProperties.paginated = false;
                }

                PeopleInsite.dom.clearHTML(container);

                var containerEl;
                if (YAHOO.lang.isObject(container)) {
                    containerEl = container;
                } else {
                    containerEl = YAHOO.util.Dom.get(container);
                }

                if (tableModel.summary) {
                    var summaryEl = YAHOO.util.Dom.create("div", {
                        className : "summary"
                    }, tableModel.summary);
                    containerEl.appendChild(summaryEl);
                }
                var wrapperEl = YAHOO.util.Dom.create("div");
                containerEl.appendChild(wrapperEl);

                return new YAHOO.widget.DataTable(wrapperEl, columnDefs, dataSource, tableProperties);
            } else {
                return null;
            }
        },
        /**
         *
         * Generates a COlumn in a TableModel that contains checkboxes.  The column is inserted on the left
         * @param name
         * @param tableModel
         */
        insertCheckboxColumn : function(name, tableModel) {
            // insert a column for the checkbox into a table model
            for (var i = tableModel.columns.length; i > 0; i--) {
                tableModel.columns[i] = tableModel.columns[i - 1];
                tableModel.columns[i]['index'] = i;
            }
            tableModel.columns[0] = {
                "index" : 0,
                "heading" : "Select",
                "name" : name,
                "abbr": "Select",
                "type": "Checkbox",
                "format": "Checkbox",
                "hidden": false,
                "sortable": false,
                "width": "3em"
            };
        },
        insertButtonColumn : function(name, tableModel) {

            // append a column for the button into a table model
            var index = tableModel.columns.length;
            tableModel.columns[index] = {
                "index" : index,
                "heading" : "Ok",
                "name" : name,
                "abbr": "Ok",
                "type": "Button",
                "format": "Button",
                "hidden": false,
                "sortable": false,
                "width": "3em"
            };
        },
        /** @description choose sensible properties for pagination - scales the rows per page based on'
         * the number of records (eg. if there's > 1000 records, show 250 per page instead of 10 per page)
         * @param totalRows { Integer } the total number of rows to be rendered
         * @param maxRowsPerPage { Integer} optional maximum limit on the number of rows per page (eg. if
         *  vertically constrained).
         */
        defaultProperties : function(totalRows, maxRowsPerPage) {
            maxRowsPerPage = maxRowsPerPage || 250;
            var rowsToUse = Math.min(10, maxRowsPerPage);
            if (totalRows > 999) {
                rowsToUse = Math.min(250, maxRowsPerPage);
            } else {
                if (totalRows > 499) {
                    rowsToUse = Math.min(100, maxRowsPerPage);
                } else {
                    if (totalRows > 149) {
                        rowsToUse = Math.min(50, maxRowsPerPage);
                    } else {
                        if (totalRows > 79) {
                            rowsToUse = Math.min(20, maxRowsPerPage);
                        }
                    }
                }
            }

            var tableProperties;
            if (totalRows > Math.min(79, maxRowsPerPage)) {
                tableProperties = {
                    paginated:true,
                    paginator: new YAHOO.widget.Paginator({
                        rowsPerPage: rowsToUse,
                        totalRecords: totalRows,
                        rowsPerPageOptions: [10,20,50,100,250],
                        alwaysVisible: false,
                        pageLinks: 20,
                        template: "<div class='pageLinks'>{PreviousPageLink} {PageLinks} {NextPageLink}</div><div class='rpp'>Rows per page: {RowsPerPageDropdown}</div>"
                    })
                };
            } else {
                tableProperties = {};
            }

            if (totalRows > 100) {
                // enable a render loop to draw the first page(s) faster
                tableProperties.renderLoopSize = 100;
            }

            return tableProperties;
        }
    };
}();

PeopleInsite.tools = function() {

    var handleClose = function() {
        this.hide();
    };

    return {
        clearError : function (id) {
            PeopleInsite.tools.reportError(id, "");
            if (YAHOO.env.ua.ie) {
                YAHOO.util.Dom.setStyle(id, "display", "none");  //
//                YAHOO.util.Dom.setStyle(id, "zoom", 0);  //
//                YAHOO.util.Dom.setStyle(id, "font-size", 0);  //                  
            }
            YAHOO.util.Dom.setStyle(id, "line-height", 0);
        },

        reportError : function(id, message) {
            PeopleInsite.dom.insertHTML(id, message);
            if (message && message.length > 0) {
                if (YAHOO.env.ua.ie) {
    //                YAHOO.util.Dom.setStyle(id, "zoom", 1);  //
    //                YAHOO.util.Dom.setStyle(id, "font-size", "1em");  //
                }
                YAHOO.util.Dom.setStyle(id, "line-height", "1");
                showById(id, "block");
            }
        },

        showErrorDialog : function(message) {
            var containerEl = PeopleInsite.dom.prepareDialogContainer();

            var dialog = new YAHOO.widget.SimpleDialog(YAHOO.util.Dom.getFirstChild(containerEl), {
                width: "300px",
                fixedcenter: "contained",
                visible: false,
                draggable: true,
                text: message,
                close: true,
                modal: true,
                constraintoviewport: true
            });

            var buttons = [ {
                    text: "Close",
                    handler:handleClose,
                    isDefault: true
                }
            ];

            dialog.cfg.queueProperty("buttons", buttons);

            dialog.render();
            dialog.show();
        },
        /**
         * @param body { HTMLElement | String }  Body content, either as html or an element containing the html
         */
        showDialog : function(title, body) {
            var message;
            if (YAHOO.lang.isObject(body)) {
                message = body.innerHTML;
            } else {
                message = body;
            }

            var containerEl = PeopleInsite.dom.prepareDialogContainer();

            var dialog = new YAHOO.widget.SimpleDialog(YAHOO.util.Dom.getFirstChild(containerEl), {
                width: "700px",
                fixedcenter: "contained",
                visible: false,
                draggable: true,
                text: message,
                close: true,
                modal: true
            });

            dialog.setHeader(title);

            var buttons = [ {
                    text: "Close",
                    handler:handleClose,
                    isDefault: true
                }
            ];

            dialog.cfg.queueProperty("buttons", buttons);

            dialog.render();
            dialog.show();
        }
    };
}();

PeopleInsite.tabView = function() {

    return {
        /**
         * Lookup the Tab instance for the specified contentId
         *
         * @param tabId <String>
         * @return YAHOO.widget.Tab
         */
        getTabByContentId : function(tabView, tabContentId) {
            var tabs = tabView.get('tabs');
            if (tabs) {
                for (var i = 0; i < tabs.length; i++) {
                    if (tabContentId === tabs[i].get('contentEl').id) {
                        return tabs[i];
                    }
                }
            }
            return null;
        },

        /**
         * Lookup the Tab index for the specified contentId
         *
         * @param tabId <String>
         * @return YAHOO.widget.Tab
         */
        getTabIndexByContentId : function(tabView, tabContentId) {
            var tabs = tabView.get('tabs');
            for (var i = 0; i < tabs.length; i++) {
                if (tabContentId === tabs[i].get('contentEl').id) {
                    return i;
                }
            }
            return null;
        }
    };

}();

/**
 * @description general record access
 **/
PeopleInsite.records = function() {

    var DEFAULT_LIST_URL = "/secure/records/list.json";
    var DEFAULT_SEARCH_URL = "/secure/records/search.json";

    var EMPTY_MSG = "<div class='pad'><p>No records to display.</p>";

    var ID_COLUMN = "c0";



    /* DataTable custom formatter for a reference to a general record */
    function formatRecordName(elCell, oRecord, oColumn, recordName) {
        if (PeopleInsite.validation.isNonBlank(recordName)) {
            elCell.innerHTML = "<a href='/secure/records/show?id=" + oRecord.getData(ID_COLUMN) + "'>" + PeopleInsite.dom.escapeHTML(recordName) + "</a>";
        }
    }

    /* DataTable custom formatter for a reference to a branch by ID */
    function formatBranch(elCell, oRecord, oColumn, branchId) {
        var branchName;
        if (PeopleInsite.GLOBALS.branches) {
            branchName = PeopleInsite.GLOBALS.branches[branchId] || "Other";
        } else {
            branchName = "Other";
        }
        elCell.innerHTML = "<a href='/secure/switch?id="+branchId+"'>"+PeopleInsite.dom.escapeHTML(branchName)+"</a>";
    }

    /**
     * If a response is received, renders information about an empty records table in place of the
     * table.
     *
     * Note that the callback requires a target HTMLElement in the scope (this)
     *
     * @scope object specifying targetEl
     **/
    var renderEmptyListMessageCallback = {
        success: function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, o.responseText, true);
            }
        },
        failure: function(o) {
            // do nothing
        }
    };

    var listRecordsCallback = {
        success: function(o) {
            var containerId = this.containerId; // from the scope param
            var emptyMsg = this.emptyMsg;

            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                var customFormatters = {
                    "Record"    : PeopleInsite.records.formatRecordReference,
                    "BranchId"  : formatBranch
                };

                if (responseObject.records) {
                    var tableModel = responseObject.records;

                    var tableProperties = PeopleInsite.dataTable.defaultProperties(tableModel.rows.length);


                    // setup the custom sorting for the record references
                    for (var columnIndex = 0; columnIndex < tableModel.columns.length; columnIndex++) {
                        if (tableModel.columns[columnIndex]["format"] === "Record") {
                            tableModel.columns[columnIndex]['sortFunction'] = PeopleInsite.records.sortRecordFunction;
                        }
                    }

                    PeopleInsite.dataTable.render(containerId, tableModel, customFormatters, emptyMsg, tableProperties);

                    if (tableModel.rows.length === 0) {
                        // if the table is empty table information if it exists
                        if (responseObject.recordTypeId) {
                            var targetEl = YAHOO.util.Dom.get(containerId);
                            PeopleInsite.net.asyncGet("/secure/records/list-empty-info.xhtml?recordTypeId="+responseObject.recordTypeId, targetEl, renderEmptyListMessageCallback);
                        }
                    }
                } else {
                    PeopleInsite.tools.reportError(containerId + "Error", "Invalid/incomplete response received from the server (no record data)");
                }
            } else {
                PeopleInsite.tools.reportError(containerId + "Error", "Unexpected response received from the server");
            }
        },
        failure: function(o) {
            var containerId = this.containerId; // from the scope param

            PeopleInsite.tools.reportError(containerId + "Error", PeopleInsite.net.errorMessage(o));
            PeopleInsite.dom.clearHTML(containerId);
        },
        cache: false
    };

    return {
        /** @description Performs an async request and renders a table of records in the specified container */
        list : function(formId, containerId) {
            PeopleInsite.tools.clearError(containerId + 'Error');
            YAHOO.util.Connect.resetFormState();
            var formEl = YAHOO.util.Dom.get(formId);
            if (formEl) {
                YAHOO.util.Connect.setForm(formId);
                var searchName;
                if (formEl.searchName) {
                    searchName = formEl.searchName.value;
                }
                if (PeopleInsite.validation.isNonBlank(searchName)) {
                    YAHOO.util.Connect.asyncRequest('GET', DEFAULT_SEARCH_URL, {
                        success: listRecordsCallback.success,
                        failure: listRecordsCallback.failure,
                        scope: { containerId: containerId,
                            emptyMsg: EMPTY_MSG },
                        cache: false
                    });
                } else {
                    YAHOO.util.Connect.asyncRequest('GET', DEFAULT_LIST_URL, {
                        success: listRecordsCallback.success,
                        failure: listRecordsCallback.failure,
                        scope: { containerId: containerId,
                            emptyMsg: EMPTY_MSG },
                        cache: false
                    });
                }
            }
        },
        /**
               * @description  Performs an async request. Returns a TableModel of results
               * @param requestParams { Array } optional name=value pairs
               * @return TableModel
               *
                * */
        lookup : function(callback, recordTypeId, branchId, requestParams) {
            YAHOO.util.Connect.resetFormState();
            if (requestParams && requestParams.length > 0) {
                var params = "";
                var first = true;
                for (var i = 0; i < requestParams.length; i++) {
                    if (!first) {
                        params += "&";
                    } else {
                        first = false;
                    }
                    params += requestParams[i];
                }
                YAHOO.util.Connect.asyncRequest('GET', DEFAULT_LIST_URL + "?recordTypeId=" + recordTypeId + "&branchId=" + branchId + "&branchOnly=true&currentOnly=true&"+params, callback);
            } else {
                YAHOO.util.Connect.asyncRequest('GET', DEFAULT_LIST_URL + "?recordTypeId=" + recordTypeId + "&branchId=" + branchId + "&branchOnly=true&currentOnly=true", callback);
            }
        },
        /**
               * Performs an async request and invokes the specified callback
              *
              *  @param url  { String } the base URL to use for the request (prior to the first ?)
               * @param requestParams { Array } optional name=value pairs to include in the request
               * @return void
               *
                * */
        loadTableModel : function(url, callback, recordTypeId, branchId, requestParams) {
            YAHOO.util.Connect.resetFormState();
            if (requestParams && requestParams.length > 0) {
                var params = "";
                var first = true;
                for (var i = 0; i < requestParams.length; i++) {
                    if (!first) {
                        params += "&";
                    } else {
                        first = false;
                    }
                    params += requestParams[i];
                }
                YAHOO.util.Connect.asyncRequest('GET', url + "?recordTypeId=" + recordTypeId + "&branchId=" + branchId + "&branchOnly=true&currentOnly=true&"+params, callback);
            } else {
                YAHOO.util.Connect.asyncRequest('GET', url + "?recordTypeId=" + recordTypeId + "&branchId=" + branchId + "&branchOnly=true&currentOnly=true", callback);
            }
        },
        /**
         * Function for sorting records in a DataTable
         *
         * @param columnKey
         * @param a
         * @param b
         * @param desc
         */
        sortRecordFunction : function(columnKey, a, b, desc) {
            // Deal with empty values
            if (!YAHOO.lang.isValue(a)) {
                return (!YAHOO.lang.isValue(b)) ? 0 : 1;
            }
            else if (!YAHOO.lang.isValue(b)) {
                return -1;
            }

            // compare by name
            var comp = YAHOO.util.Sort.compare;
            var empA = a.getData(columnKey);
            var empB = b.getData(columnKey);
            var compState = comp(empA.name, empB.name, desc);

            return compState;
        },
        /**
        * DataTable custom formatter to render a a reference to a Record within a cell.
        *
        * If the oRecordRef is a reference to a record only, this function will render a link to the page to show the record.
        * If the oRecordRef is a reference to a record's checklist, the link will be to the page to show the checklist
        *
        * The oRecordRef is created by a ReferenceBeanFactory on the server-side.
        *
        * */
        formatRecordReference : function(elCell, oRecord, oColumn, oRecordRef) {
            if (oRecordRef) {
                if (PeopleInsite.validation.isNonBlank(oRecordRef.checkListId)) {
                    if (PeopleInsite.validation.isNonBlank(oRecordRef.name)) {
                        elCell.innerHTML = "<a href='/secure/records/checklists/show-page?id=" + oRecordRef.id + "&checkListId="+oRecordRef.checkListId+"'>" + PeopleInsite.dom.escapeHTML(oRecordRef.name) + "</a>";
                    } else {
                        elCell.innerHTML = "<a href='/secure/records/checklists/show-page?id=" + oRecordRef.id + "&checkListId="+oRecordRef.checkListId+"'>-</a>";
                    }
                } else {
                    if (PeopleInsite.validation.isNonBlank(oRecordRef.name)) {
                        elCell.innerHTML = "<a href='/secure/records/show?id=" + oRecordRef.id + "'>" + PeopleInsite.dom.escapeHTML(oRecordRef.name) + "</a>";
                    } else {
                        elCell.innerHTML = "<a href='/secure/records/show?id=" + oRecordRef.id + "'>-</a>";
                    }
                }
            }
        }
    };

}();

PeopleInsite.documents = { };

PeopleInsite.documents.list = function() {

    var STATUS_COLUMN = "c3";
    
    var EMPTY_MSG = "<div class='pad'><p>No documents to display.</p>";

    /* DataTable custom formatter */
    function formatDocument(elCell, oRecord, oColumn, document) {
        elCell.innerHTML = "<a href='/secure/documents/view?documentId=" + document.uuid + "'>" + PeopleInsite.dom.escapeHTML(document.title) + "</a>";
    }
     /* DataTable custom formatter  - link directly to download a document*/
    function formatDocumentLink(elCell, oRecord, oColumn, document) {
        if (document) {
            elCell.innerHTML = "<a href='/secure/documents/download?documentId=" + document.uuid + "'>"+ PeopleInsite.dom.escapeHTML(document.title)+"</a>";
        } else {
            PeopleInsite.dom.clearHTML(elCell);
        }
    }

    function sortDocument(columnKey, a, b, desc) {
        // Deal with empty values
        if (!YAHOO.lang.isValue(a)) {
            return (!YAHOO.lang.isValue(b)) ? 0 : 1;
        }
        else if (!YAHOO.lang.isValue(b)) {
            return -1;
        }

        // first compare by name, then by id
        var comp = YAHOO.util.Sort.compare;
        var docA = a.getData(columnKey);
        var docB = b.getData(columnKey);

        var compState = comp(docA.name, docB.name, desc);
        if (compState === 0) {
            // equal names, compare by title
            compState = comp(docA.updated, docB.updated, desc);
        }

        return compState;
    }

     /**
     * If a response is received, renders information about an empty document table in place of the
     * table.
     *
     * Note that the callback requires a target HTMLElement in the scope (this)
     *
     * @scope object specifying targetEl
     **/
    var renderEmptyListMessageCallback = {
        success: function(o) {
            if (this.target) {
                PeopleInsite.dom.insertHTML(this.target, o.responseText, true);
            }
        },
        failure: function(o) {
            // do nothing
        }
    };

    var listDocumentsCallback = {
        success: function(o) {
            var containerId = this.containerId;  // from scope param
            var emptyMsg = this.emptyMsg;

            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                var customFormatters = {
                    "Document" : formatDocument,
                    "DocumentLink" : formatDocumentLink,
                    "View" : PeopleInsite.documents.list.formatViewLink
                };

                if (responseObject.documents) {

                    var tableModel = responseObject.documents;
                    var tableProperties = PeopleInsite.dataTable.defaultProperties(tableModel.rows.length);

                    if (responseObject.useLongForm) {
                        tableModel.columns[0]['width'] = "3em";  // type
                        tableModel.columns[1]['sortFunction'] = sortDocument;
                        tableModel.columns[2]['width'] = "65px";  // updated
                        tableModel.columns[3]['width'] = "70px";  // status
                        tableModel.columns[4]['width'] = "65px";  // expiry
                        tableModel.columns[5]['width'] = "5em";  // author
                        tableModel.columns[6]['width'] = "3em";  // download
                    } else {
                        tableModel.columns[0]['sortFunction'] = sortDocument;
                        tableModel.columns[1]['width'] = "65px";  // updated
                    }
                    PeopleInsite.dataTable.render(containerId, tableModel, customFormatters, EMPTY_MSG, tableProperties);

                    if (tableModel.rows.length === 0) {
                        // if the table is empty we can display "list-empty" information if it exists
                        if (responseObject.folderId) {
                            var targetEl = YAHOO.util.Dom.get(containerId);
                            PeopleInsite.net.asyncGet("/secure/documents/list-empty-info.xhtml?folderId="+responseObject.folderId, targetEl, renderEmptyListMessageCallback);
                        }
                    }

                } else {
                    PeopleInsite.tools.reportError(containerId + "Error", "Invalid or incomplete response received from the server");
                }
            } else {
                //                PeopleInsite.tools.reportError(containerId+"Error", "Unexpected response received from the server");
                PeopleInsite.tools.reportError(containerId + "Error", "Sorry, this document list is currently unavailable");
            }
        },
        failure: function(o) {
            var containerId = this.containerId;  // from scope param

            PeopleInsite.tools.reportError(containerId + "Error", PeopleInsite.net.errorMessage(o));
        }
    };

    function documentAsyncRequest(formId, url, containerId) {
        PeopleInsite.tools.clearError(containerId + 'Error');
        YAHOO.util.Connect.resetFormState();
        YAHOO.util.Connect.setForm(formId);
        YAHOO.util.Connect.asyncRequest('GET', url, {
            success: listDocumentsCallback.success,
            failure: listDocumentsCallback.failure,
            scope: { containerId: containerId },
            cache: false
        });
    }

    /** Listener for search button */
    var defaultOnSearchListener = function() {
        // search function
//        createCookie(SELECTED_TAB_COOKIE, "document_" + folderId, 60);
        PeopleInsite.dom.replaceHTML("documents_" + folderId + '_Container', LOADING_TEXT, true);
        PeopleInsite.documents.list.listFolderDocs("documents_" + folderId + 'Search', "documents_" + folderId + '_Container');
    };

    var defaultOnResetListener = function() {
         // reset function
        form.searchName.value = "";
    };

    var onClear = function() {
         PeopleInsite.dom.clearHTML("documents_" + folderId + '_Container');
    };

    return {
        listRecentDocs : function(formId, containerId) {
            documentAsyncRequest(formId, "/secure/documents/recent/list.json", containerId);
        },
        listCommonDocs : function(formId, containerId) {
            documentAsyncRequest(formId, "/secure/documents/common/list.json", containerId);
        },
        listPropertyDocs : function(formId, containerId) {
            documentAsyncRequest(formId, "/secure/documents/property/list.json", containerId);
        },
        listFolderDocs : function(formId, containerId) {
            documentAsyncRequest(formId, "/secure/documents/folder/list.json", containerId);
        },
        /* DataTable custom formatter - no file name, link to view a file (or edit if it's draft, update if it's Pending Amendment) */
        formatViewLink : function(elCell, oRecord, oColumn, documentId) {
            var status = oRecord.getData(STATUS_COLUMN);
            var document = oRecord.getData("c1");
            if (!documentId) {
                if ("Draft" === status) {
                    if (document) {
                        elCell.innerHTML = "<a href='/secure/documents/creation/edit?id="+document.uuid+"'>Edit</a>";
                    } else {
                        PeopleInsite.dom.clearHTML(elCell);
                    }
                } else {
                    PeopleInsite.dom.clearHTML(elCell);
                }
            } else {
                if ("Pending Amendment" === status) {
                    if (document) {
                        elCell.innerHTML = "<a href='/secure/documents/view?documentId="+document.uuid+"'>Update</a>";
                    } else {
                        PeopleInsite.dom.clearHTML(elCell);
                    }
                } else {
                    elCell.innerHTML = "<a href='/secure/documents/download?documentId=" + documentId + "'>View</a>";
                }
            }
        }
    };
}();

PeopleInsite.documents.upload = function() {

    var uploadValidationSettings = {
        formName : "uploadForm",
        validators : [
            {
                name : "title",
                validators: [
                    {
                        validator : PeopleInsite.validation.requiredString,
                        containerId: "document_titleErrorContainer",
                        message: "Please provide a title for the document"
                    }
                ]
            },
            {
                name : "upload",
                validators: [
                    {
                        validator : PeopleInsite.validation.requiredString,
                        containerId: "uploadForm_uploadErrorContainer",
                        message: "Please select a file to upload"
                    }
                ]
            }
        ]
    };

    /**
     * The default callback expects a serialized documentRef as the response. If one is received, the
     * document information page of the referenced document is opened
     */
    var defaultUploadCallback = {
        // Define this event handler for file upload transactions *only*.
        // This handler will not be used for any other transaction cases.
        upload:function(o) {
            var documentRef = PeopleInsite.net.deserializeJSON(o.responseText);
            if (documentRef) {
                PeopleInsite.documents.upload.globalDocumentUploadedEvent.fire(documentRef);
                if (documentRef.id) {
                    window.location = "/secure/documents/view?documentId=" + documentRef.id+"&uploadAnother=true";
                } else {
                    if (documentRef.errorMessage) {
                        PeopleInsite.tools.reportError("uploadErrorContainer", "Error: " + documentRef.errorMessage);
                    } else {
                        PeopleInsite.tools.reportError("uploadErrorContainer", "Error: The document could not be created");
                    }
                }
            }
        }
    };


    return {
        /**
         * Use this event to listen when a document is uploaded.
         * The argument will be an oDocReference, scope will be window
         */
        globalDocumentUploadedEvent : new YAHOO.util.CustomEvent("documentUploaded"),    
        showEmployees : function() {
            YAHOO.util.Dom.setStyle("collectiveViewForm", "display", "none");
            YAHOO.util.Dom.setStyle("collectiveEditForm", "display", "block");
            Documents.collective.edit();
        },
        /**
         * @description perform an asynchronous file upload using the specified form
         * @param uploadFormEl { HTMLElement } the form element
         * @param uploadCallback  { Object } alternate callback method (of type file upload callback). The default will
         * fire PeopleInsite.documents.upload.globalDocumentUploadedEvent with the documentRef as an argument and open the
         * document's info page, or report an error.
         * @param dontValidate { boolean } if true, validation of essential parameters (such as a filename) are ignored
         **/
        submit : function(uploadFormEl, /*optional*/ uploadCallback, /*optional*/ dontValidate) {

            if (!uploadCallback) {
                uploadCallback = defaultUploadCallback;
            }

            PeopleInsite.calendar.refreshDatePickers(uploadFormEl);

            if (typeof Documents === 'object') {
                Documents.expiryDate.sync();
                Documents.collective.sync(uploadFormEl);
            }

            if ((dontValidate) || (PeopleInsite.validation.validate(uploadValidationSettings))) {

//                PeopleInsite.net.asyncSubmit(uploadFormEl, uploadCallback, null, true);

                YAHOO.util.Connect.resetFormState();
                if (YAHOO.env.ua.ie) {
                    YAHOO.util.Connect.setForm(uploadFormEl, true, true); // multi-part, IE SSL
                } else {
                    YAHOO.util.Connect.setForm(uploadFormEl, true); // multi-part
                }
                YAHOO.util.Connect.asyncRequest('POST', uploadFormEl.action, uploadCallback);
            }
        },
        /* Enable additional questions for special-case document types */
        checkDocumentType : function(el) {
            var documentType = el.options[el.selectedIndex].value;

            if (YAHOO.util.Dom.get("AWA_Lodgement")) {
                // if awa lodgement is supported, enable popup of these options
                if (documentType === "ITEA") {
                    showById("AWA_Lodgement");
                } else {
                    hideById("AWA_Lodgement");
                }
            }
            if (YAHOO.util.Dom.get("EC_Registration")) {
                // if EC registration is supported, enable popup of these options
                if (documentType === "EC") {
                    showById("EC_Registration");
                } else {
                    hideById("EC_Registration");
                }
            }
        },
        /*
        * Derive a document title from a filename selected, if not already set
        * @param fileEl { HTMLElement } The file input element
        * @param titleElId { String } the ID of the input that contains the title
        **/
        deriveTitle : function(fileEl, titleElId) {
            var titleEl = YAHOO.util.Dom.get(titleElId);
            if (titleEl) {
                var currentTitle = titleEl.value;

                if (currentTitle.length === 0) {
                    var selectedValue = fileEl.value;

                    // strip leading path
                    if (selectedValue.indexOf('/') >= 0) {
                        selectedValue = PeopleInsite.string.substringAfterLast(selectedValue, '/');
                    } else {
                        if (selectedValue.indexOf('\\') >=0) {
                            selectedValue = PeopleInsite.string.substringAfterLast(selectedValue, '\\');
                        }
                    }

                    // assign
                    titleEl.value = selectedValue;
                }
            }            
        }
    };
}();

PeopleInsite.alerts = function() {


    var ID_COLUMN = "c0";
    var TIMESTAMP_COLUMN = "c1";
    var ALERT_REF_COLUMN = "c2";
    var STATUS_COLUMN = "c3";

    var ALERT_LIST_URL = "/secure/alerts/list.json";
    var ALERT_ACK_URL = "/secure/alerts/ack.json";
    var VIEW_DOCUMENT_URL = "/secure/documents/view.action?documentId=";
    var VIEW_EMPLOYEE_URL = "/secure/employees/view.action?employeeId=";
    var VIEW_CLIENT_URL = "/secure/clients/view.action?clientId=";
    var VIEW_PROPERTY_URL = "/secure/properties/view.action?propertyId=";
    var VIEW_RECORD_URL = "/secure/records/show.action?id=";

    var ICONS = {
        "Document" : "/static/images/icons/page_white.gif",
        "Employee" : "/static/images/icons/employees.gif",
        "Contractor" : "/static/images/icons/contractors.gif",
        "Client" : "/static/images/icons/clients.gif",
        "Property" : "/static/images/icons/house.gif",
        "Record" : "/static/images/icons/employees.gif"
    };

    var RECORD_ICONS = {
        "employee" : "/static/images/icons/employees.gif",
        "contractor" : "/static/images/icons/contractors.gif",
        "client" : "/static/images/icons/clients.gif",
        "customer" : "/static/images/icons/clients.gif",
        "supplier" : "/static/images/icons/clients.gif",
        "property" : "/static/images/icons/house.gif",
        "record" : "/static/images/icons/employees.gif",
        "Sales" : "/static/images/icons/sales.gif",
        "PropMgt" : "/static/images/icons/leases.gif"
    };

    var alertsEmptyMsg =
            "<div class='pad'><p>No alerts to display. Alerts are created for notes, document expiry reminders and record events.</p></div>";

    function calculateURL(alertType, referenceId) {
        var url = "";
        if (alertType == "Document") {
            url = VIEW_DOCUMENT_URL + referenceId;
        } else {
            if (alertType == "Employee") {
                url = VIEW_EMPLOYEE_URL + referenceId;
            } else {
                if (alertType == "Contractor") {
                    url = VIEW_EMPLOYEE_URL + referenceId;  // same as an employee
                } else {
                    if (alertType == "Client") {
                        url = VIEW_CLIENT_URL + referenceId;
                    } else {
                        if (alertType == "Property") {
                            url = VIEW_PROPERTY_URL + referenceId;
                        } else {
                            if (alertType == "Record") {
                                url = VIEW_RECORD_URL + referenceId;
                            }
                        }
                    }
                }
            }
        }
        return url;
    }

    function calculateIcon(alert) {
        if (alert.alertType === 'Record') {
            var icon = RECORD_ICONS[alert.recordTypeKey];
            if (!icon) {
                return ICONS['Record'];
            } else {
                return icon;
            }
        } else {
            return ICONS[alert.alertType];
        }
    }

    /* DataTable custom formatter */
    function formatAlert(elCell, oRecord, oColumn, alert) {
        var html = "";
        if (alert.referenceId) {
            var iconUrl = calculateIcon(alert);
            if (iconUrl) {
                html += "<img src='" + iconUrl + "' alt='" + alert.alertType + "' width='16' height='16'/>";
            }
            if (alert.name) {
                html += "<a href='" + calculateURL(alert.alertType, alert.referenceId) + "'>" + PeopleInsite.dom.escapeHTML(alert.name) + "</a> ";
            } else {
                html += "<a href='" + calculateURL(alert.alertType, alert.referenceId) + "'>" + PeopleInsite.dom.escapeHTML(alert.alertType) + "</a> ";
            }

            if ((alert.alertType === 'Document' || alert.alertType === 'Agreement')) {
                // include the record name if available
                if (alert.recordName) {
                    html += " (" + PeopleInsite.dom.escapeHTML(alert.recordName) + ")";
                }
            }

            html += ": ";
        }
        html += PeopleInsite.dom.escapeHTML(alert.bodyText);
        elCell.innerHTML = html;
    }

    function formatTimestamp(elCell, oRecord, oColumn, reminder) {

        if (reminder) {
            var date = reminder.timestamp;
            var period = reminder.period;

            var html = PeopleInsite.calendar.formatSystemJSDate(date);
            var dateObject = PeopleInsite.calendar.convertDate(date);
            var jsDate = new Date();
            jsDate.setFullYear(dateObject.year, (dateObject.month - 1) % 12, dateObject.day);

            var today = new Date();
            if (today < jsDate) {
                html += " (future)";
            }

            if (period && period !== 'None') {
                html += " <img src='/static/images/icons/control_repeat.gif' title='Repeats " + period + "'/>";
            }

            elCell.innerHTML = html;
        } else {
            PeopleInsite.dom.clearHTML(elCell);
        }
    }

    /**
     * @description pushes through the wrapper to sort by timestamp
     * @param columnKey
     * @param a
     * @param b
     * @param desc
     */
    function sortReminder(columnKey, a, b, desc) {
        var comp = YAHOO.util.Sort.compare;
        var reminderA = a.getData(columnKey);
        var reminderB = b.getData(columnKey);
        return comp(reminderA.timestamp, reminderB.timestamp, desc);
    }

    var AckListener = function(alertId, containerId, dataTable) {

        var alert = alertId;
        var container = containerId;
        var dt = dataTable;

        return function(e) {
            YAHOO.util.Event.preventDefault(e);
            PeopleInsite.alerts.ack(alert, container, dt);
        };
    };

    function formatButton(elCell, oRecord, oColumn) {
        var status = oRecord.getData(STATUS_COLUMN);
        if (("Active" === status) || ("Planned" === status)) {
            var node = YAHOO.util.Dom.create("a", {
                id : "ack" + oRecord.getData(ALERT_REF_COLUMN).alertId,
                href: "#",
                listener: ['click', new AckListener(oRecord.getData(ALERT_REF_COLUMN).alertId, this._elContainer.id, this)]
            }, "Ok");

            if (elCell.firstChild) {
                YAHOO.util.Event.purgeElement(elCell.firstChild, true);  // clear existing listeners
                elCell.replaceChild(node, elCell.firstChild);
            } else {
                elCell.appendChild(node);
            }
        }
    }

    // show/hide the alarm & counter
    function updateAlertCount(alertsCount) {
        var ac = document.getElementById("alarmIcon");
        if (ac !== null) {
            PeopleInsite.dom.clearHTML(ac);
            if (alertsCount > 0) {
                var alertsAlarm = YAHOO.util.Dom.create("img", {
                    id: "alertsAlarm",
                    src: "/static/images/icons/clock_red.gif"
                });
                ac.appendChild(alertsAlarm);
            } else {
                var alertsNoAlarm = YAHOO.util.Dom.create("img", {
                    id: "alertsNoAlarm",
                    src: "/static/images/icons/alerts.gif"
                });
                ac.appendChild(alertsNoAlarm);
            }
        }
    }

    var listAlertsCallback = {
        success: function(o) {
            var containerId = this.containerId; // from the scope param
            var emptyMsg = this.emptyMsg;

            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                var customFormatters = {
                    "Alert"    : formatAlert,
                    "Reminder" : formatTimestamp,
                    "Button"   : formatButton
                };

                if (responseObject.alerts) {

                    var tableModel = responseObject.alerts;
                    var tableProperties = PeopleInsite.dataTable.defaultProperties(tableModel.rows.length);

                    PeopleInsite.dataTable.insertButtonColumn("clear", tableModel);
                    tableModel.columns[1]['width'] = "120px";  // timestamp
                    tableModel.columns[1]['sortFunction'] = sortReminder;
                    tableModel.columns[3]['width'] = "70px";  // status

                    var dataTable = PeopleInsite.dataTable.render(containerId, tableModel, customFormatters, emptyMsg, tableProperties);

                    if (dataTable !== null) {
                        var alertsCount = 0;
                        // set the class of each row based on the status
                        // also detect whether any alerts are active
                        var records = dataTable.getRecordSet().getRecords();
                        for (var recordNo = 0; recordNo < records.length; recordNo++) {
                            var record = records[recordNo];
                            var trEl = dataTable.getTrEl(record);
                            // (not all records are visible)
                            var status = record.getData(STATUS_COLUMN);
                            if (trEl) {
                                YAHOO.util.Dom.addClass(trEl, "alert-" + status);
                            }
                            if ("Active" === status) {
                                alertsCount++;
                            }
                        }

                        updateAlertCount(alertsCount);
                    } else {
                        updateAlertCount(0);
                    }
                } else {
                    PeopleInsite.tools.reportError(containerId + "Error", "Invalid/incomplete response received from the server");
                }
            } else {
                PeopleInsite.tools.reportError(containerId + "Error", "Unexpected response received from the server");
            }
        },
        failure: function(o) {
            var containerId = this.containerId; // from the scope param

            PeopleInsite.tools.reportError(containerId + "Error", PeopleInsite.net.errorMessage(o));
        }
    };

    var ackCallback = {
        success: function(o) {
            var containerId = this.containerId; // from the scope param
            var dataTable = this.dataTable;
            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                if (responseObject.okay) {
                    // update the displayed alert status
                    var alert = responseObject.alert;
                    if (dataTable !== null) {
                        var recordSet = dataTable.getRecordSet();
                        var recordId;

                        // find the affected record
                        var records = recordSet.getRecords();
                        var record;
                        for (var recordNo = 0; recordNo < records.length; recordNo++) {
                            record = records[recordNo];
                            var alertRef = record.getData(ALERT_REF_COLUMN);
                            if (alertRef.alertId === alert.alertRef.alertId) {
                                recordId = record.getId();

                                // adjust the manually applied styles and ok link
                                var trEl = dataTable.getTrEl(record);
                                if (trEl) {
                                    // clear the highlight and ok button
                                    YAHOO.util.Dom.addClass(trEl, "alert-" + alert.status);
                                    var linkEl = document.getElementById("ack" + alertRef.alertId);
                                    if (linkEl) {
                                        //  PeopleInsite.dom.clearHTML(linkEl);
                                        YAHOO.util.Event.purgeElement(linkEl, true);  // clear existing listeners
                                        while (linkEl.firstChild) {
                                            linkEl.removeChild(linkEl.firstChild);
                                        }
                                    }
                                }
                                break;
                            }
                        }

                        if (recordId) {
                            // bind new date to columns
                            var oData = {};
                            oData[ID_COLUMN] = record.getData(ID_COLUMN);
                            oData[TIMESTAMP_COLUMN] = record.getData(TIMESTAMP_COLUMN);
                            oData[ALERT_REF_COLUMN] = record.getData(ALERT_REF_COLUMN);
                            oData[STATUS_COLUMN] = alert.status;

                            // and update and refresh if visible
                            dataTable.updateRow(record, oData);
                        }
                    }
                } else {
                    PeopleInsite.tools.reportError(containerId + "Error", responseObject.message);
                }
            } else {
                PeopleInsite.tools.reportError(containerId + "Error", "Unexpected response received from the server");
            }
        },
        failure: function(o) {
            var containerId = this.containerId; // from the scope param
            PeopleInsite.tools.reportError(containerId + "Error", PeopleInsite.net.errorMessage(o));
        }
    };

    return {
        /** Renders a table of alerts in the specified container */
        list : function(formId, containerId) {
            PeopleInsite.tools.clearError(containerId + 'Error');
            YAHOO.util.Connect.resetFormState();
            YAHOO.util.Connect.setForm(formId);
            YAHOO.util.Connect.asyncRequest('GET', ALERT_LIST_URL, {
                success: listAlertsCallback.success,
                failure: listAlertsCallback.failure,
                scope: { containerId: containerId,
                    emptyMsg: alertsEmptyMsg
                },
                cache: false
            });
        },
        ack : function(alertId, containerId, dataTable) {
            PeopleInsite.tools.clearError(containerId + 'Error');
            YAHOO.util.Connect.resetFormState();
            YAHOO.util.Connect.asyncRequest('POST', ALERT_ACK_URL + "?alertId=" + alertId, {
                success: ackCallback.success,
                failure: ackCallback.failure,
                scope: {
                    containerId: containerId,
                    dataTable: dataTable
                },
                cache: false
            });
        }
    };


}();

PeopleInsite.branch = function() {

    var LIST_SUBBRANCHES_URL = "/secure/account/branch/listSubBranches.json?id=";

    /**
     * Listener for the onchange event on the select.  Requests a switch to the selected branch.
     * @scope {
     *  selectEl : selectEl,
     *  redirectPath: redirectPath
     *  }
     *
     */
    var onChangeSwitchBranch = function() {
        window.location='/secure/switch?id='+PeopleInsite.dom.select.getSelectedValue(this.selectEl, '')+'&redirectPath='+this.redirectPath;
    };

    /**
     * @scope {
     *  sourceEl : sourceEl,
     *  redirectPath : {String} redirectPath
     * }
     */
    var fetchSubBranchesCallback = {
        success: function(o) {
            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                if (responseObject.subBranches) {

                    var currentId = responseObject.currentId;
                    // create the select element adjacent to the sourceEl if it doesn't already exist
                    var selectEl = YAHOO.util.Dom.get("selector_"+currentId);
                    if (!selectEl) {
                        selectEl = YAHOO.util.Dom.create("select", {'id':'selector_'+currentId});
                    }

                    var subBranches = responseObject.subBranches;
                    var options = [];
                    options[0] = new Option("Select...", "", false, false);
                    for (var i = 0; i < subBranches.length; i++) {
                        options[i+1] = new Option(subBranches[i].description, subBranches[i].key, false, false);
                    }

                    PeopleInsite.dom.select.setOptions(selectEl, options);
                    // select the current branch if in this list
                    PeopleInsite.dom.select.setSelectedValue(selectEl, responseObject.currentId);

                    YAHOO.util.Event.addListener(selectEl, "change", onChangeSwitchBranch, {
                        selectEl: selectEl,
                        redirectPath: this.redirectPath
                    }, true);
                    YAHOO.util.Dom.insertAfter(selectEl, this.sourceEl);
                }

            }
        },
        failure : function(o) {
        }
    };

    /**
     *
     * @param parentBranchId { String }
     * @param sourceEl { HTMLElement } The select will be rendered adjacent to this element
     * @param redirectPath { String } optional path to use for redirect after a branch selection
     */
    var fetchSubBranches = function(parentBranchId, sourceEl, redirectPath) {
        YAHOO.util.Connect.resetFormState();
        YAHOO.util.Connect.asyncRequest('GET', LIST_SUBBRANCHES_URL + parentBranchId, {
            success: fetchSubBranchesCallback.success,
            failure: fetchSubBranchesCallback.failure,
            scope: {
                sourceEl: sourceEl,
                redirectPath: redirectPath
            },
            cache:false
        });
    };

     /**
     *
     * @param parentBranchId { String }
     * @param sourceEl { HTMLElement } The select will be rendered adjacent to this element
     * @param redirectPath { String } optional path to use for redirect after a branch selection
     */
    var fetchBranches = function(parentBranchId, sourceEl, redirectPath) {
        YAHOO.util.Connect.resetFormState();
        YAHOO.util.Connect.asyncRequest('GET', LIST_SUBBRANCHES_URL + parentBranchId, {
            success: fetchSubBranchesCallback.success,
            failure: fetchSubBranchesCallback.failure,
            scope: {
                sourceEl: sourceEl,
                redirectPath: redirectPath
            },
            cache: false
        });
    };

    return {
        /**
         * Renders a dropdown for selecting a different branch and set ups the listener to make a selection
         *
         * @param parentBranchId { String }
         * @param sourceEl { HTMLElement } The select will be rendered adjacent to this element
         * @param redirectPath { String } optional path to use for redirect after a branch selection
         */
        populateBranchSelector : function(parentBranchId, sourceEl, redirectPath) {
            fetchSubBranches(parentBranchId, sourceEl, redirectPath)
        }
    };
}();


/**
 * Calls the callback if not reset for the specified number of ticks to wait
 **/
PeopleInsite.IdleTimer = function(tickInterval, millisToWait, callback, callbackScope) {

    var tickCounter;
    var lastFired;
    var ticksToWait;

    /** Executed every interval tick */
    function tickListener() {
        tickCounter++;
        if (tickCounter - lastFired > ticksToWait) {
            callback.apply(callbackScope, []);
            lastFired = tickCounter;
        }
    }

    function init() {
        tickCounter = 0;
        lastFired = 0;
        ticksToWait = (millisToWait / tickInterval);
        setInterval(tickListener, tickInterval);
    }

    init();

    return {
        reset : function() {
            tickCounter = 0;
            lastFired = 0;
        }
    };
};

(function() {

    var Dom = YAHOO.util.Dom;

    /** The number of milliseconds to wait before posting a search request */
    var CHANGE_TIMEOUT = 5000;
    var TICK_INTERVAL = 1000;

    // temporary global tab of search tab controllers to handle tab nesting
    // (invoke refresh on controller of child tab)
    // key is contentId
    PeopleInsite.searchTabControllerRegistry = {};

    /**
     * Generic controller for a search tab. Works with records or documents.
     *
     * @constructor
     * @param {String | HTMLElement } formID (optional) If not included, no search
     * @param {Function} requestFunction
     * @param {Function} resetFunction
     * @param {Function} clearFunction
     */
    PeopleInsite.SearchTabController = function(formId, requestFunction, resetFunction, clearFunction) {

        var form;
        if (YAHOO.lang.isString(formId)) {
            form = Dom.get(formId);
        } else {
            form = formId;
        }
               
        this.requestFunction = requestFunction;
        this.resetFunction = resetFunction;
        this.clearFunction = clearFunction;

        var searchNameEl;
        this.inputChanged = false;

        if (form) {
            formId = YAHOO.util.Dom.getAttribute(form, "id"); //use getAttribute in case form has an input named id
            YAHOO.util.Event.addListener(formId + "SearchBtn", "click", onSearch, this, true);
            if (form) {
                YAHOO.util.Event.addListener(form, "submit", onSearch, this, true);
                searchNameEl = Dom.get(formId + "_searchName");
                YAHOO.util.Event.addListener(searchNameEl, "keyup", this.searchNameChangedListener, this, true);
            }

            YAHOO.util.Event.addListener(formId + "ResetBtn", "click", onReset, this, true);

            // this._idleTimer = new PeopleInsite.IdleTimer(TICK_INTERVAL, CHANGE_TIMEOUT, this.idleCallback, this);
        }
    };

    var proto = PeopleInsite.SearchTabController.prototype;

    /** Pass though a reference to the tabView for use by the listeners */
    proto.setTabView = function(oTabView) {
        this.tabView = oTabView;
    };

    /**
     * Handler for the automatic search
     *
     * @scope SearchTabController
     */
    proto.searchNameChangedListener = function(event) {
        //        this._idleTimer.reset();
        this.inputChanged = true;
    };

    proto.clearInputChangedFlag = function() {
        this.inputChanged = false;
    };

    proto.isInputChanged = function() {
        return this.inputChanged;
    };

    /** When idle, check if the searchName has changed
     *
     * @scope SearchTabController
     * */
    proto.idleCallback = function() {
        if (this.isInputChanged()) {
            //            this._idleTimer.reset();
            this.clearInputChangedFlag();
            this.requestFunction.call(this);
        }
    };

    /**
     * @scope SearchTabController
     * @param e
     */
    function onSearch(e) {
        YAHOO.util.Event.stopEvent(e);
        //        this._idleTimer.reset();
        this.clearInputChangedFlag();

        this.requestFunction.call(this);
    }

    /**
     * @scope SearchTabController
     * @param e
     */
    function onReset(e) {
        //        this._idleTimer.reset();
        this.clearInputChangedFlag();

        if (e.type === 'submit') {
            YAHOO.util.Event.preventDefault(e);
        } else {
            YAHOO.util.Event.preventDefault(e);
            this.resetFunction.call(this);   // reset the form
            this.requestFunction.call(this);                       
        }
    }

    /**
     * The listener for a change in the visibility of a tab
     * A false to true transition means the requestFunction should be invoked to populate the tab
     * Otherwise the clear function should be invoked.
     * @public */
    proto.contentVisibleChangeListener = function(e) {
        var prevValue = e.prevValue;
        var newValue = e.newValue;
        if (prevValue === false && newValue === true) {
            this.requestFunction.call(this);
        } else {
            if (this.clearFunction) {
                this.clearFunction.call(this);
            }
        }

    };

    /**
     * Refresh the content of this tab
     */
    proto.refresh = function() {
        this.requestFunction.call(this);  
    };

    proto.clear = function() {
        if (this.clearFunction) {
            this.clearFunction.call(this);
        }
    };

})();

(function() {


    /** DataTable custom formatter: Render a table cell that contains a checkbox */
    function formatCheckbox(elCell, oRecord, oColumn, document) {
       //        elCell.innerHTML = "<input id='chk" + oRecord.getId() + "' type='checkbox' name='chk." + oRecord.getId() + "' onclick='Records.documents.shared.toggleRow(\"" + oRecord.getId() + "\")'/>";
       var checkboxEl = YAHOO.util.Dom.create("input", { type:"checkbox", name:"chk." + oRecord.getId(), id:"chk" + oRecord.getId(), listener: ['click', checkboxClickListener, { oRecord: oRecord, dataTable: this }, true]});
       PeopleInsite.dom.clearHTML(elCell);
       elCell.appendChild(checkboxEl);
    }

    function setCheckbox(rowId, checked) {
        var elCheckbox = YAHOO.util.Dom.get("chk" + rowId);
        if (elCheckbox) {
            elCheckbox.checked = checked;
        }
    }

   /**
    * @scope object with oRecord and dataTable
    */
   var checkboxClickListener = function(e) {
       // prevent propagation to the row click event listener
       YAHOO.util.Event.stopPropagation(e);
       if (this.dataTable.isSelected(this.oRecord)) {
           this.dataTable.unselectRow(this.oRecord);
       } else {
           this.dataTable.selectRow(this.oRecord);
       }
   };

    function preselectRows(dataTable) {
        // select rows for currently assigned documents
        var records = dataTable.getRecordSet().getRecords();
        for (var recordNo = 0; recordNo < records.length; recordNo++) {
            var record = records[recordNo];
            if (record.getData()['assigned']) {
                dataTable.selectRow(record);
            }
        }
        refreshCheckboxes(dataTable);
    }

    /**
     * params oArgs[0] is the datatable
     *
     * @scope dataTable
     */
    function onEventSelectRowSelectCheckbox(oArgs) {
        refreshCheckboxes(this);
    }

    /**
     * Extract the documentReference from an oRecord in the DataTable
     * @param oRecord
     */
    function getDocumentReferenceFromRow(oRecord) {
        var docReference = oRecord.getData('c1');
        return docReference;
    }

    /**
     * DataTable callback function on row selected
     *
     * @scope dataTable
     * @param oArgs object with event and tagrget
     * @param callback function that accepts the oDocReference as a parameter
     */
    function onEventSelectRowInvokeCallback(oArgs, callback) {
        // extract the selected document id
        var sMode = this.get("selectionMode");
        if ((sMode === "singlecell") || (sMode === "cellblock") || (sMode === "cellrange")) {
            return;
        }

        var evt = oArgs.event;
        var elTarget = oArgs.target;
        var elTargetRow = this.getTrEl(elTarget);
        var oTargetRecord = this.getRecord(elTargetRow);

        var oDocReference = getDocumentReferenceFromRow(oTargetRecord);

        // invoke the callback
        if (typeof callback === "function") {
            callback(oDocReference);
        }
    }

    function refreshCheckboxes(dataTable) {
       var records = dataTable.getRecordSet().getRecords();

       for (var recordNo = 0; recordNo < records.length; recordNo++) {
           setCheckbox(records[recordNo].getId(), dataTable.isSelected(records[recordNo]));
       }
    }

    /**
     * @scope DocumentSearchController
     */
    var listDocumentsCallback = {
        success: function(o) {
            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                var customFormatters = {
                    "Document" : Records.documents.dataTable.formatDocument,
                    "View" : PeopleInsite.documents.list.formatViewLink
                };

                var tableModel = responseObject.documents;
                var tableProperties = PeopleInsite.dataTable.defaultProperties(tableModel.rows.length);

                Records.documents.dataTable.decorateColumns(tableModel);
                PeopleInsite.dataTable.render(this.containerEl, tableModel, customFormatters, null, tableProperties);
            } else {
                PeopleInsite.tools.reportError(this.errorContainerEl, "Unexpected response received from the server");
            }
        },
        failure: function(o) {
            PeopleInsite.tools.reportError(this.errorContainerEl, PeopleInsite.net.errorMessage(o));
        }
    };

    /**
     * Throw an event when a document is selected in the table
     *
     * @param oDocReference  the document reference object
     */
    var onDocumentSelected = function(oDocReference) {
        Records.documents.globalDocumentSelectedEvent.fire(oDocReference);
    };

    /**
     * @scope DocumentSearchController
     */
     var listDocumentsForSelectionCallback = {
        success: function(o) {
            var responseObject = PeopleInsite.net.deserializeJSON(o.responseText);
            if (responseObject) {
                var customFormatters = {
                    "Document" : Records.documents.dataTable.formatDocumentWithoutLink,
                    "View" : PeopleInsite.documents.list.formatViewLink
//                    "Checkbox" : formatCheckbox
                };

                var tableModel = responseObject.documents;
                var tableProperties = PeopleInsite.dataTable.defaultProperties(tableModel.rows.length);

                Records.documents.dataTable.decorateColumns(tableModel);
//                PeopleInsite.dataTable.insertCheckboxColumn("assigned", tableModel);

                var dataTable = PeopleInsite.dataTable.render(this.containerEl, tableModel, customFormatters, null, tableProperties);

                dataTable.set("selectionMode","single");

                dataTable.subscribe("rowMouseoverEvent", dataTable.onEventHighlightRow);
                dataTable.subscribe("rowMouseoutEvent", dataTable.onEventUnhighlightRow);
                dataTable.subscribe("rowClickEvent", dataTable.onEventSelectRow);
                dataTable.subscribe("rowClickEvent", onEventSelectRowSelectCheckbox);

                if (this.onDocumentSelectedCallback) {
                    dataTable.subscribe("rowClickEvent", onEventSelectRowInvokeCallback, this.onDocumentSelectedCallback);
                }
            } else {
                PeopleInsite.tools.reportError(this.errorContainerEl, "Unexpected response received from the server");
            }
        },
        failure: function(o) {
            PeopleInsite.tools.reportError(this.errorContainerEl, PeopleInsite.net.errorMessage(o));
        },
        cache: false
    };


    /**
     * @scope DocumentSearchController
     */
    var requestFunction = function() {
        this.issueSearchRequest();
    };

    /**
     * @scope DocumentSearchController
     */
    var resetFunction = function() {
        // reset function
        this.searchFormEl.searchName.value = "";
        this.issueSearchRequest();
    };

    /**
     * @scope DocumentSearchController
     */
    var clearFunction = function() {
        PeopleInsite.dom.clearHTML(this.errorContainerEl);
        PeopleInsite.dom.clearHTML(this.containerEl);
    };


    /**
     * Default behaviour is to fire the global event that a document has been selected
      * @param oDocReference
     */
    var defaultDocumentSelectionCallback = function(oDocReference) {
        if (Records.documents) {
            Records.documents.globalDocumentSelectedEvent.fire(oDocReference);
        }
    };

    /**
     * Specialisation of the SearchTabController that includes default listeners for searching documents and an optional callback
     * for selection of a document
     *
     * @constructor
     * @extends SearchTabController
     * @param searchFormEl {HTMLElement}
     * @param singleSelection { Boolean } (optional)
     * @param onDocumentSelectedCallack { Function } (optional)
     * @param folderId { String } optional string identifing the folder to list documents in, Used, if searchFormEl is null
     */
    PeopleInsite.DocumentSearchController = function(searchFormEl, containerEl, errorContainerEl, singleSelection, onDocumentSelectedCallack, folderId) {
        // chain the constructors
        // note that getAttribute is used here because there may be a form element with "name" id
//        var searchTabId = YAHOO.util.Dom.getAttribute(searchFormEl, "id");

        PeopleInsite.DocumentSearchController.superclass.constructor.call(this, searchFormEl, requestFunction, resetFunction, clearFunction);

        this.searchFormEl = searchFormEl;
        this.singleSelection = singleSelection;
        this.onDocumentSelectedCallback = onDocumentSelectedCallack || defaultDocumentSelectionCallback;

        this.containerEl = containerEl;
        this.errorContainerEl = errorContainerEl;

        if (this.searchFormEl) {
            if (YAHOO.util.Dom.hasClass(searchFormEl, "record")) {
                this.requestURL = "/secure/documents/record/list.json";
            } else {
                if (YAHOO.util.Dom.hasClass(searchFormEl, "folder")) {
                     this.requestURL = "/secure/documents/folder/list.json";
                }
            }
        } else {
             this.requestURL = "/secure/documents/folder/list.json?folderId="+folderId;
        }
    };

    // setup the prototype extension
    YAHOO.lang.extend(PeopleInsite.DocumentSearchController, PeopleInsite.SearchTabController);

    var proto = PeopleInsite.DocumentSearchController.prototype;

       /**
     * List table of documents.
     * @param singleSection   if true, table is initialised for the selection of a single document, otherwise its
     * just a list and users can click on the link to the document
     * @scope DocumentSearchController
     * todo: should not be static and should not be using IDs
     */
    proto.issueSearchRequest = function() {
        PeopleInsite.tools.clearError('documentError');
        YAHOO.util.Connect.resetFormState();
        if (this.searchFormEl) {
            YAHOO.util.Connect.setForm(this.searchFormEl);
        }

        if (!this.singleSelection) {
            YAHOO.util.Connect.asyncRequest('GET', this.requestURL, {
                success: listDocumentsCallback.success,
                failure: listDocumentsCallback.failure,
                scope:  this,
                cache: false
            });
        } else {
            YAHOO.util.Connect.asyncRequest('GET', this.requestURL, {
                success: listDocumentsForSelectionCallback.success,
                failure: listDocumentsForSelectionCallback.failure,
                scope:  this,
                cache: false
            });
        }
    };

}());

PeopleInsite.home = function() {

    var Dom = YAHOO.util.Dom;

    var RECENT_DOCS_TAB = "recent";
    var COMMON_DOCS_TAB = "shared";
    var ALERTS_TAB = "alerts";

    var SELECTED_TAB_COOKIE = "selectedTab";

    var LOADING_TEXT = "<div class='lcw'><div class='loadingContainer'>Loading...</div></div>";

    /** A beforeContentVisibleChange listener for a tab to clear its content
     * when its hidden - needed for IE6
     * @param tabContentId
     */
    var ClearTabContentWhenHiddenListener = function(tabContentId) {
        return function(e) {
            var prevValue = e.prevValue;
            var newValue = e.newValue;

            if (prevValue === false && newValue === true) {
            } else {
                // no longer visible - clear the content
                PeopleInsite.dom.clearHTML(tabContentId);
            }

            return true;
        };
    };

    /**
     * @description setup the listeners for the specified tab
     *
     * If the tab is visible (reported by contentVisible attribute) it is refreshed immediately.
     *
     * @param tabContentId
     * @param formId
     * @param requestFunction
     * @param resetFunction
     * @param lazyLoad  if false, the content of the tab is loaded when the tab becomes visible
     * @param focusId   optional id of the element to focus on when the tab is displayed
     */
    function initTab(tabView, tabContentId, formId /* optional */, requestFunction /* optional */, resetFunction /* optional */, clearFunction /*optional */, lazyLoad, focusId) {
        var tab = PeopleInsite.tabView.getTabByContentId(tabView, tabContentId);
        if (tab) {
            var tabController = new PeopleInsite.SearchTabController(formId, requestFunction, resetFunction, clearFunction);
            tabController.setTabView(tabView);
            // keep a reference
            PeopleInsite.searchTabControllerRegistry[tabContentId] = tabController;

            if (!lazyLoad) {
                // in IE6 we need to clear the content of the tab when switching because it leaves table row artefacts behind
//                if (YAHOO.env.ua.ie === 6) {
//                    tab.addListener("beforeContentVisibleChange", new ClearTabContentWhenHiddenListener(tabContentId));
//                }
                tab.addListener("contentVisibleChange", tabController.contentVisibleChangeListener, tabController, true);
            }

//            tab.addListener("contentVisibleChange", tabController.contentVisibleChangeListener, tabController, true);


            if (focusId) {
                tab.addListener("contentVisibleChange", function(e) {
                    var el = Dom.get(focusId);
                    if (el) {
                        var prevValue = e.prevValue;
                        var newValue = e.newValue;
                        if (prevValue === false && newValue === true) {
                            // put focus where requested
                            //el.focus();    // focus disabled because it causes the page to jump
                        } else {
                            //el.blur();
                        }
                    }
                });
            }
            if (tab.get('contentVisible')) {
                tabController.refresh();
            }
        }
    }

    /**
     * initialize a general records tab
     * @param tabContentId
     */
    function initRecordsTab(tabView, tabContentId) {

        var forms = Dom.getElementsByClassName("recordsSearch", "form", tabContentId);
        var form = forms[0];
        var lazyLoad = (YAHOO.util.Dom.getAttribute(form, "data-eager") === "false");  // false by default

        initTab(tabView, tabContentId, form.id, function() {
            // search function
//            createCookie(SELECTED_TAB_COOKIE, tabContentId, 60);
            writeSelectedTabCookie(tabView, tabContentId);

            PeopleInsite.dom.replaceHTML(tabContentId + "_Container", LOADING_TEXT, true);
            PeopleInsite.records.list(tabContentId + "_Search", tabContentId + "_Container");
        }, function() {
            // reset function
            Dom.get(tabContentId + "_searchName").value = "";
        }, function() {
            PeopleInsite.dom.clearHTML(tabContentId + "_Container");
        }, lazyLoad, tabContentId + "_searchName");

    }

    function recentDocsSearch() {
//        createCookie(SELECTED_TAB_COOKIE, RECENT_DOCS_TAB + "_", 60);
        writeSelectedTabCookie(this.tabView, RECENT_DOCS_TAB+"_");
        PeopleInsite.dom.replaceHTML("recentDocumentsContainer", LOADING_TEXT, true);
        PeopleInsite.documents.list.listRecentDocs('recentSearch', 'recentDocumentsContainer');
    }

    function recentDocsReset() {
        var formEl = YAHOO.util.Dom.get("recentSearch");
        if (formEl) {
            formEl.searchName.value = "";
        }
    }

    function recentDocsClear(e) {
        PeopleInsite.dom.clearHTML("recentDocumentsContainer");
    }


    /**
     * initialize the tab of recently updated records
     *
     * @param tabContentId
     */
    function initRecentRecordsTab(tabView, tabContentId) {

        var forms = Dom.getElementsByClassName("recentRecordsSearch", "form", tabContentId);
        var form = forms[0];
        initTab(tabView, tabContentId, form.id, function() {
            // search function
            writeSelectedTabCookie(tabView, tabContentId);                    
            PeopleInsite.dom.replaceHTML("recentRecords_Container", LOADING_TEXT, true);
            PeopleInsite.records.list("recentRecords_Search", "recentRecords_Container");
        }, function() {
            // reset function
            form.searchName.value = "";
        }, function() {
            PeopleInsite.dom.clearHTML("recentRecords_Container");
        }, false, null);
    }

    /** For a tabContainer tab, update the class of the content when it's visible
     *
     * @scope object with TabView and contentId (of the tab) */
    function containerTabClickListener(event) {
        var parentContentId  = this.tabView.get("id");
        var el = PeopleInsite.dom.getFirstElementByClass(parentContentId, "div", "yui-content");
        var tabsEl =  PeopleInsite.dom.getFirstElementByClass(parentContentId, "ul", "yui-nav");

        var activeTab = this.childTabView.get("activeTab");
        var childController;
        if (activeTab) {
            // clear the content of the active tab as long as it's not a containerTab
            var contentEl = activeTab.get("contentEl");

            if (!YAHOO.util.Dom.hasClass(contentEl, "ContainerTab")) {
                childController = PeopleInsite.searchTabControllerRegistry[contentEl.id];
            }
        }

        if (!event.prevValue && event.newValue) {
            // now visible
            writeSelectedTabCookie(this.tabView, this.contentId);

            YAHOO.util.Dom.addClass(el, "nested-tabs");
            // update the class of the outer tab
            YAHOO.util.Dom.addClass(tabsEl, "outer-tabs");

            // the content on the active tab needs to be refreshed
            if (childController) {
                childController.refresh();
            }
        } else {
            YAHOO.util.Dom.removeClass(el, "nested-tabs");
            YAHOO.util.Dom.removeClass(tabsEl, "outer-tabs");

            // the content on the active tab needs to be refreshed
            if (childController) {
                childController.clear();
            }
        }

    }

    /**
     * initialize the tab of other tabs.
     * When the visibility of a container tab changes to visible, then it needs to get its selected visible tab
     * to refresh itself
     *
     * @param tabContentId
     */
    function initContainerTab(tabView, tabContentId) {
        var element = PeopleInsite.dom.getFirstElementByClass(tabContentId, "div", "yui-navset");

        YAHOO.util.Dom.generateId(element); // id is mandatory for the tabview
        var child = new YAHOO.widget.TabView(element);

        // see if the selected tab is in a cookie so it can be selected before the tabs are initialised
        setupSelectedTab(child);
        initCommonTabs(child);

        var tab = PeopleInsite.tabView.getTabByContentId(tabView, tabContentId);
        if (tab) {
            tab.addListener("contentVisibleChange", containerTabClickListener, {
                tabView : tabView,
                contentId : tabContentId,
                childTabView : child
            }, true);
        }
    }

    /**
     * initialize a general documents tab for the specified folder
     * @param tabContentId
     */
    function initDocumentsTab(tabView, tabContentId) {

        var forms = Dom.getElementsByClassName("documentsSearch", "form", tabContentId);
        var form = forms[0];
        var folderId = form.folderId.value;
        initTab(tabView, tabContentId, form.id, function() {
            // search function
//            createCookie(SELECTED_TAB_COOKIE, "document_" + folderId, 60);
            writeSelectedTabCookie(tabView, tabContentId);
            PeopleInsite.dom.replaceHTML("documents_" + folderId + '_Container', LOADING_TEXT, true);
            PeopleInsite.documents.list.listFolderDocs("documents_" + folderId + 'Search', "documents_" + folderId + '_Container');
        }, function() {
            // reset function
            form.searchName.value = "";
        }, function() {
            PeopleInsite.dom.clearHTML("documents_" + folderId + '_Container');
        }, false, "documents_" + folderId + "searchName");
    }


    function commonDocsReset() {
        var formEl = PeopleInsite.dom.getFormById("commonDocSearch");
        if (formEl) {
            formEl.searchName.value = "";
        }
    }

    function commonDocsClear(e) {
        PeopleInsite.dom.clearHTML("commonDocumentsContainer");
    }

    var alertsAckCallback = {
        refresh: function() {
            //alertsSearch();     // todo: gone?
        }
    };

    function alertsReset() {
        var formEl = PeopleInsite.dom.getFormById("alertsSearch");
        if (formEl) {
            formEl.searchName.value = "";
        }
    }

    function alertsClear(e) {
        PeopleInsite.dom.clearHTML("alertsContainer");
    }

    /**
     * initialize a tab og RecordChecKlist instances of a specific type
     * @param tabContentId
     */
    function initCheckListsTab(tabView, tabContentId) {

        var forms = Dom.getElementsByClassName("checkListsSearch", "form", tabContentId);
        var form = forms[0];
        var lazyLoad = (YAHOO.util.Dom.getAttribute(form, "data-eager") === "false");  // false by default

        initTab(tabView, tabContentId, form.id, function() {
            // search function
//            createCookie(SELECTED_TAB_COOKIE, tabContentId, 60);
            writeSelectedTabCookie(tabView, tabContentId);

            PeopleInsite.dom.replaceHTML(tabContentId + "_Container", LOADING_TEXT, true);
            Records.checkList.list.listCheckLists(tabContentId + "_Search", tabContentId + "_Container");
        }, function() {
            // reset function
            Dom.get(tabContentId + "_searchName").value = "";
        }, function() {
            PeopleInsite.dom.clearHTML(tabContentId + "_Container");
        }, lazyLoad, tabContentId + "_searchName");

    }


    /**
     * @description determine which tabs are available for this account and enable their controllers
     *
     */
    function initCommonTabs(tabView) {
        var container = tabView.get("id");

        var CLASS_MARKER_TO_SETUP_FUNCTION = {
            "RecentTab" : function(contentId) {
                            initTab(tabView, contentId, 'recentSearch', recentDocsSearch, recentDocsReset, recentDocsClear, false, "recentSearch_searchName");
                          },
            "RecordsTab": function(contentId) {
                            initRecordsTab(tabView, contentId);
                          },
            "SharedTab" : function(contentId) {
                             // a shared documents tab
                            initTab(tabView, contentId, 'commonDocSearch', function() {
                                writeSelectedTabCookie(tabView, contentId);
                                PeopleInsite.dom.replaceHTML("commonDocumentsContainer", LOADING_TEXT, true);
                                PeopleInsite.documents.list.listCommonDocs('commonDocSearch', 'commonDocumentsContainer');
                            }, commonDocsReset, commonDocsClear, false, "commonDocSearch_searchName");
                          },
            "DocumentsTab": function(contentId) {
                            initDocumentsTab(tabView, contentId);
                          }, // a general documents tab
            "RecentRecordsTab" : function(contentId) {
                            initRecentRecordsTab(tabView, contentId);
                          },
            "ContainerTab" : function(contentId) {
                            initContainerTab(tabView, contentId);
                          },
            "CheckListsTab" : function(contentId) {
                            initCheckListsTab(tabView, contentId);
                          },
            "alert" : function(contentId) {
                            // an alerts tab
                            initTab(tabView, ALERTS_TAB, 'alertsSearch', function() {
                                // when the tab is selected refresh the alert list
                                writeSelectedTabCookie(tabView, ALERTS_TAB);
                                PeopleInsite.alerts.list('alertsSearch', 'alertsContainer', alertsAckCallback);
                            }, alertsReset, alertsClear, false, null);
                          }
        };

        if (container) {
            var tabs = Dom.getElementsByClassName("tab", "li", container);
            for (var i = 0; i < tabs.length; i++) {
                var tabEl = tabs[i];
                // only process the tab if it is an immediate child of this tabView, not a child of a nested tabView
                var tabAncestorEl = Dom.getAncestorByClassName(tabEl, "yui-navset");
                if (tabAncestorEl.id === container) {
                    var contentId = YAHOO.util.Dom.getAttribute(tabEl, "data-id");

                    for (var key in CLASS_MARKER_TO_SETUP_FUNCTION) {
                        if (CLASS_MARKER_TO_SETUP_FUNCTION.hasOwnProperty(key)) {
                            if (Dom.hasClass(tabs[i], key)) {
                                var setupFunction = CLASS_MARKER_TO_SETUP_FUNCTION[key];
                                if (setupFunction) {
                                    setupFunction(contentId);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Read the cookie that identifies the ID of the currently selected tab in this tabView
     * @param tabView
     */
    function readSelectedTabCookie(tabView) {
        var id = tabView.get('id');
        return YAHOO.util.Cookie.get(SELECTED_TAB_COOKIE+id);
    }

    /**
     * Write a cookie that stores which was the last selected tab in this tabView.  The ID of the tabView
     * is used as part of the cookie name so this will persist between pages if the ID is consistent.
     *
     * @param tabView
     * @param name
     */
    function writeSelectedTabCookie(tabView, name) {
        var id = tabView.get('id');

        YAHOO.util.Cookie.set(SELECTED_TAB_COOKIE+id, name, {
            path: "/",
            expires: PeopleInsite.calendar.now(60, 0)
        });
    }

    /** Sets up the initially selected tab for the tabView */
    function setupSelectedTab(tabView) {

        // set the default tab
        var selectedTab = readSelectedTabCookie(tabView);
        var tabWidget;
        if (selectedTab) {
            var defaultTabIndex = PeopleInsite.tabView.getTabIndexByContentId(tabView, selectedTab);
            if ((defaultTabIndex !== null) && (defaultTabIndex >= 0)) {
                tabView.set('activeIndex', defaultTabIndex);
                tabWidget = tabView.getTab(defaultTabIndex);
            } else {
                tabView.set('activeIndex', 0);
            }

        } else {
            tabView.set('activeIndex', 0);
        }

        if (!tabWidget) {
            tabWidget = tabView.getTab(0);
        }
        if (tabWidget) {
            // refresh the selected tab
            tabWidget.fireEvent('click');
        }
    }

    /** The success method of this callback is invoked if there's an intro to display to a user */
    var introDialogCallback = {
        success: function(o) {
            // render the response in an overly

            if (YAHOO.lang.trim(o.responseText).length > 0) {
                // use the context property to align to the top left of bd of the document
                var overlay = new YAHOO.widget.Overlay("introOverlay", {
                    context: ["bdContent", "tl", "tl", ["beforeShow", "windowResize"]],
                    visible: false
                });

                overlay.setBody(o.responseText);
                overlay.render(document.body);
                overlay.show();

                YAHOO.util.Event.addListener("introOverlay", "click", overlay.destroy, overlay, true);

                createCookie("introDialogShown", "true", 120);
            }
        },
        failure: function(o) {
            // nothing to do
        }
    };

    /**
     * If enabled in the page header, make a request to load the content of a dialog that will
     * be displayed to the user. eg. for new user help
     */
    function setupIntroDialog() {
        var INTRO_DIALOG_URL = "/secure/account/message.xhtml";

        var showMessage = PeopleInsite.dom.readMetaAttribute("showMessage");

        if (showMessage === "true") {
            var shown = readCookie("introDialogShown");

            if (!shown) {
                PeopleInsite.net.asyncGet(INTRO_DIALOG_URL, null, introDialogCallback);
            }
        }
    }

    function init(tabView) {
        initCommonTabs(tabView);
        setupSelectedTab(tabView);
    }

    return {
        initHomePage : function() {
            var homeTabView = new YAHOO.widget.TabView("tabsContainer");
            init(homeTabView);

            // initialise the banner if placeholder defined
            // todo: generic
            var bannerEl = YAHOO.util.Dom.get("consultingSWF");
            if (bannerEl) {
                if (YAHOO.env.ua.ie === 6) {
                    hideById("consultingSWF"); // todo: disabled in ie6
                } else {
                    var so = new SWFObject("/cobrand/images/ara-trp/PI_ARA_230x120v1.swf", "consultingAnim", 230, 120, "7", "#44A53C");
                    so.addParam("wmode", "transparent");
                    so.write("consultingSWF");
                }
            }

            // show the introduction dialog if required
            setupIntroDialog();

        },
        initTabs : function(tabView) {
            initCommonTabs(tabView);
        },
        refreshAlerts : function() {
            alertsSearch();
        }
    };
}();

/** @description handle error messages passed in via a cookie or a request parameter */
(function() {

    var DELAYED_WRITE_PERIOD_MS = 500;
    var CLEAR_WRITE_PERIOD_MS = 20000;

    var _errorMessage;
    var _interval;


    /**
     * replace + with ' '
     * replace %xx with equivalent character
     * @param text
     */
    function urlDecode(encoded) {
        var HEXCHARS = "0123456789ABCDEFabcdef";
        var string = "";

        var i = 0;
        while (i < encoded.length) {
            var ch = encoded.charAt(i);
            if (ch === "+") {
                string += " ";
                i++;
            } else {
                if (ch === "%") {
                    if ((i < (encoded.length - 2)
                            && HEXCHARS.indexOf(encoded.charAt(i + 1)) != -1
                            && HEXCHARS.indexOf(encoded.charAt(i + 2)) != -1)) {
                        string += unescape(encoded.substr(i, 3));
                        i += 3;
                    } else {
                        // invalid - skip it
                        i++;
                    }
                } else {
                    string += ch;
                    i++;
                }
            }
        }


        return string;
    }

    function escape(text) {
        //var result = text.replace(/\%20/g, " ");
        var result = unescape(text);
        result = result.replace(/\+/g, " ");
        return result.split("&").join("&amp;").split("<").join("&lt;").split(">").join("&gt;");
    }

    function getContainer() {
        var el = document.getElementById("mainErrorContainer");
        if (!el) {
            // see if there's a login form to use
            el = document.getElementById("loginform_msg");
        }
        return el;
    }

    function clearLater() {
        _errorMessage = null;
        setTimeout(delayedWriteCallback, CLEAR_WRITE_PERIOD_MS);
    }

    function writeError(el) {
        while (el.firstChild) {
            el.removeChild(el.firstChild);
        }

        if (_errorMessage) {
            el.innerHTML = "<span>" + escape(_errorMessage) + "</span>";
            el.style.display = "block";
            clearLater();
        } else {
            el.style.display = "none";
        }
    }

    function delayedWriteCallback() {
        var el = getContainer();
        if (el) {
            writeError(el);
            if (_interval) {
                clearInterval(_interval);
            }
        }
    }

    function reportError(msg) {
        var el = getContainer();
        _errorMessage = msg;
        if (el) {
            writeError(el);
        } else {
            _interval = setInterval(delayedWriteCallback, DELAYED_WRITE_PERIOD_MS);
        }
    }

    function clearError() {
        var el = getContainer();
        _errorMessage = null;
        if (el) {
            writeError(el);
        } else {
            _interval = setInterval(delayedWriteCallback, DELAYED_WRITE_PERIOD_MS);
        }
    }

    function checkForErrors() {
        var uri = document.URL;

        var message = readCookie("lastErrorMessage");
        if (!message) {
            // try the request parameters
            var pos = uri.indexOf("message", uri.indexOf("?"));
            if (pos === -1) {
                pos = uri.indexOf("errorMessage", uri.indexOf("?"));
            }
            if (pos >= 0) {
                message = uri.substring(pos);
                var startPos = message.indexOf("=");
                var endPos = message.indexOf("&");
                if (startPos >= 0) {
                    message = message.substring(startPos + 1, (endPos > startPos ? endPos : message.length));
                }
            }
        } else {
            deleteCookie("lastErrorMessage");
        }
        if (message && message.length > 0) {
            reportError(message);
        } else {
            clearError();
        }
    }

    YAHOO.util.Event.onDOMReady(checkForErrors);
})();

(function() {

    PeopleInsite.demo = {};
    
    var MENU_URL = "/app/demo.xhtml";

    var onSuccess = function(o) {
        this.destroy();
    };
    
    var onFailure = function(o) {
        this.destroy();
    };
     
    /**
     * Render the demo dialog content and make it visible.
     *
     * @param url  URl of the content. If flash, will render object/embed code
     */
    function renderDemoDialog(url) {
        var container = PeopleInsite.dom.prepareDialogContainer("demoDialog");

        var isFlash = (url.indexOf("swf") >= 0);
        var isSecure = document.URL.indexOf("https") >= 0;

        // the response needs to be valid dialog markup
        var demoDialog = new YAHOO.widget.Panel(YAHOO.util.Dom.getFirstChild(container), {
            width: "820px",
            height: "600px",
            fixedcenter: "contained",
            visible: false,
            draggable: true,
            close: true,
            modal: true
        });

        var swfWidth = 789;
        var swfHeight = 549;

//        demoDialog.cfg.queueProperty("hideaftersubmit", true);
        demoDialog.setHeader("System Help Guide");
        if (isFlash) {
            demoDialog.setBody("<div id='flash'></div>");
        } else {
            demoDialog.setBody("<div id='demo'></div>");
        }
        // setup the handlers for the async request generated by the dialog
//        demoDialog.callback.success = onSuccess;
//        demoDialog.callback.failure = onFailure;
//        demoDialog.callback.cache = false;

        demoDialog.render();
        demoDialog.show();


        if (!isFlash) {
            PeopleInsite.net.asyncGet(url, "demo");
        } else {
            var so = new SWFObject(url, "captivatePlayer", swfWidth, swfHeight, "7", "#44A53C");
            so.addParam("wmode", "transparent");
            so.write("flash");
        }
//        //Create instance of SWFObject
//        var so = new SWFObject(url, "captivatePlayer", "840", "500", "7", "#c7e0ff");
//
//        //Pull Variables from the URL
//        //so.addVariable("variable1", "home");
//        so.addVariable("page", getQueryParamValue("page"));
//
//        //Write SWF to page
//        so.write("flash");
    }

     /**
     * @scope scope is an object that includes the commandURL and oArgs
     */
    var loadDemoCallback = {
        success: function(o) {
            renderDemoDialog(o.responseText);
        },
        failure: function(o) {
            PeopleInsite.tools.showErrorDialog(PeopleInsite.net.errorMessage(o));
        }
    };

    /**
     *
     * @param url { String | HTMLElement } Optional URL of the demo, otherwise element with href or value. If not specified,
     * @param url { String } Optional hub key
     *  load the menu
     */
    PeopleInsite.demo.play = function(url, hub) {
        if (url) {
            if (YAHOO.lang.isObject(url)) {
                if (url.href) {
                    url = url.href;
                } else {
                    if (url.value) {
                        url = url.value;
                    }
                }
            }
            renderDemoDialog(url);
        } else {
            if (hub) {
                renderDemoDialog(MENU_URL+"?hub="+hub);
            } else {
                renderDemoDialog(MENU_URL);
            }
        }
    };

})();

// Confirm for Cancel button
function confirmChoice(homepage) {
    var question = confirm("Are you sure you wish to exit? Click Cancel to continue with Terms & Conditions page.");
    if (question) {
        var newlocation = '';
        newlocation += homepage;
        location = newlocation;
    }
}

function confirmDeleteAgreement(type, name) {
    return confirm("Are you sure you wish to delete the " + type + ": '" + name + "'?");
}

function confirmDeleteDocument() {
    return confirm("Are you sure you wish to delete this document?");
}

function confirmDeleteTemplate(name) {
    return confirm("Are you sure you wish to delete the template: '" + name + "'?");
}

function confirmContactRequest() {
    return confirm("Would you like PeopleInsite to contact you regarding a license?");
}

function confirmPurgeBranch() {
    return confirm("Are you sure you wish to permanently delete *every* record in this branch?  This feature is intended to correct massive set up / import errors only. There is no way to recover this data.");
}


function getElementById(id) {
    return document.getElementById(id);
}

function trim(str) {
    if (str) {
        return str.replace(/^\s+|\s+$/g, '');
    } else {
        return "";
    }
}

function showById(ids, style) {
    var idList = ids.split(",");
    if ("inline-block" === style) {
        if (YAHOO.env.ua.ie) {
            style = "block";
        }
    }

    style = style || "inline";
    for (var i = 0; i < idList.length; i++) {
        var element = document.getElementById(trim(idList[i]));
        if (element !== null) {
            if (element.nodeName === "TR") {
                if (!YAHOO.env.ua.ie) {
                    element.style.display = "table-row";
                } else {
                    element.style.display = "block";
                }
            } else {
                if (element.nodeName === "TD") {
                    if (!YAHOO.env.ua.ie) {
                        element.style.display = "table-cell";
                    } else {
                        element.style.display = "block";
                    }
                } else {
                    element.style.display = style;
                }
            }

            if (YAHOO.env.ua.ie) {
                element.style.zoom = 1;
            }
        }
    }

}

function hideById(ids) {
    var idList = ids.split(",");
    for (var i = 0; i < idList.length; i++) {
        var element = document.getElementById(trim(idList[i]));
        if (element !== null) {
            element.style.display = "none";

            if (YAHOO.env.ua.ie) {
                element.style.zoom = 0;  // element should have 0 height in IE
            }
        }
    }
}

function toggleBlockVisibility(ids) {
    var idList = ids.split(",");
    for (var i = 0; i < idList.length; i++) {
        var element = document.getElementById(idList[i]);
        if (element !== null) {
            if (element.style.display === "none") {
                element.style.display = "block";
            } else {
                element.style.display = "none";
            }
        }
    }
}

function disableById(ids) {
    var idList = ids.split(",");
    for (var i = 0; i < idList.length; i++) {
        var element = document.getElementById(idList[i]);
        if (element !== null) {
            element.disabled = true;
        }
    }
}

function enableById(ids) {
    var idList = ids.split(",");
    for (var i = 0; i < idList.length; i++) {
        var element = document.getElementById(idList[i]);
        if (element !== null) {
            element.disabled = false;
        }
    }
}

// opens a new window containing message from the specified URL
// performs no operation if the url is null
function popupMessage(url) {
    if (url !== null) {
        var winl = (screen.width - 620) / 2;
        var wint = (screen.height - 500) / 2;
        var winprops = 'height=' + 500 + ',width=' + 620 + ',top=' + wint + ',left=' + winl + ',scrollbars=yes,resizable=yes,toolbar=no,status=no';

        window.open(url, 'NewWindow', winprops);
    }
}

// opens a new window containing message from the specified URL
// performs no operation if the url is null
function popupWindow(url) {
    if (url !== null) {
        window.open(url, '_blank');
    }
}

function createCookie(name, value, mins) {
    var expires;
    if (mins) {
        var date = new Date();
        date.setTime(date.getTime() + (mins * 60 * 1000));
        expires = "; expires=" + date.toGMTString();
    }
    else {
        expires = "";
    }
    document.cookie = name + "=" + value + expires + "; path=/";
}

function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1, c.length);
        }
        if (c.indexOf(nameEQ) === 0) {
            return c.substring(nameEQ.length, c.length);
        }
    }
    return null;
}

function deleteCookie(name) {
    createCookie(name, "", null);
}

// return the value of the radio button that is checked
// return an empty string if none are checked, or
// there are no radio buttons
function getCheckedValue(radioObj) {
    if (!radioObj) {
        return "";
    }
    var radioLength = radioObj.length;
    if (radioLength === undefined) {
        if (radioObj.checked) {
            return radioObj.value;
        } else {
            return "";
        }
    }

    for (var i = 0; i < radioLength; i++) {
        if (radioObj[i].checked) {
            return radioObj[i].value;
        }
    }
    return "";
}

/**
 * Set the checked value of a radio button list or individual checkbox
 * @param radioObjOrEl
 * @param newValue
 */
function setCheckedValue(radioObjOrEl, newValue) {
    if (!radioObjOrEl) {
        return;
    }

    if (radioObjOrEl.nodeName === "INPUT" && radioObjOrEl.type && radioObjOrEl.type.toUpperCase() === "CHECKBOX") {
        radioObjOrEl.checked = newValue;
    } else {
        setRadioCheckedValue(radioObjOrEl, newValue);
    }       
}

/*
// set the radio button with the given value as being checked
// do nothing if there are no radio buttons
// if the given value does not exist, all the radio buttons
// are reset to unchecked */
function setRadioCheckedValue(radioObj, newValue) {
    var radioLength = radioObj.length;
    if (radioLength === undefined) {
        radioObj.checked = (radioObj.value == newValue.toString());
        return;
    }
    for (var i = 0; i < radioLength; i++) {
        radioObj[i].checked = false;
        if (radioObj[i].value === newValue.toString()) {
            radioObj[i].checked = true;
        }
    }
}


/**
 * Provides Y.QueryString.stringify method for converting objects to Query Strings.
 *
 * @module querystring
 * @submodule querystring-stringify
 * @for QueryString
 * @static
 */

var QueryString = {};

/**
 * Provides Y.QueryString.escape method to be able to override default encoding
 * method.  This is important in cases where non-standard delimiters are used, if
 * the delimiters would not normally be handled properly by the builtin
 * (en|de)codeURIComponent functions.
 * Default: encodeURIComponent
 * @module querystring
 * @submodule querystring-stringify
 * @for QueryString
 * @static
 **/
QueryString.escape = encodeURIComponent;




