﻿/// <reference path="~/Scripts/app/references.js" />

// $(":asp(serverid)") - http://lanitdev.wordpress.com/2009/06/08/extending-jquery-to-select-asp-controls/
$.expr[':'].asp = function(elem, i, match) {
return (elem.id && elem.id.match(match[3] + "$"));
};

$.expr[':'].textEquals = function(a, i, m) {
    return $(a).text().match("^" + m[3] + "$");
};

if (typeof FLTK === "undefined" || !FLTK) {
    var FLTK = {};
}

FLTK.ajax = {
    showStatusMessage: function(message) {
        $("#ajaxstatus").text(message || "Loading").show();
    },
    hideStatusMessage: function() {
        $("#ajaxstatus").fadeOut('slow');
    }
};

FLTK.checkbox = {
    selectAll: function(checked, endingwith) {

        // Keep in mind that if you have asp id="myCheckBox" and asp id="CheckBox" and are trying to select
        // "CheckBox" it will also grab "myCheckBox" since it ends with it.  This problem *possibly* could be made
        // better by adding an underscore before the endingWith, since asp server ids are underscore delimited

        this.selectAllCollection(checked, $(":asp(" + endingwith + ")"));

    },
    selectAllInTable: function(checked, endingwith, $checkbox) {

        // Keep in mind that if you have asp id="myCheckBox" and asp id="CheckBox" and are trying to select
        // "CheckBox" it will also grab "myCheckBox" since it ends with it.  This problem *possibly* could be made
        // better by adding an underscore before the endingWith, since asp server ids are underscore delimited

        $checkboxes = $checkbox.closest("table").find(":asp(" + endingwith + ")");

        this.selectAllCollection(checked, $checkboxes);
    },
    selectAllBeg: function(checked, beginningwith) {
        this.selectAllCollection(checked, $("input[id^=" + beginningwith + "]"));
    },
    selectAllCollection: function(checked, $checkboxes) {

        // we don't want to check a box that is hidden on the page
        if (checked) {
            $checkboxes = $checkboxes.filter(":visible");
        }
        $checkboxes.attr("checked", checked);
    },
    selectedCount: function(checked, endingwith) {
        var $chk = $("table[id$=" + endingwith + "]");
        if ($chk.length > 0) { // input is the ID of an asp:CheckBoxList, so look for all the children
            $chk = checked ? $chk.find(":checked") : $chk.find(":not(:checked)");
        }
        else { // input is the id of checkboxes, so look within the collection
            $chk = $("input[id$=" + endingwith + "]");
            $chk = checked ? $chk.filter(":checked") : $chk.not(":checked");
        }
        return $chk.length;
    },
    requireChecked: function(endingwith, noneSelected, oneSelected, manySelected) {
        // Meant to be used on an 'onclick' event on a link to validate a set of checkboxes as input.
        // Works with the ID of <input runat="server" />, <asp:CheckBox />, or the ID of an <asp:CheckBoxList />

        var sel = 0, i;
        if ($.isArray(endingwith)) {
            // Can pass in as ["chkOne", "chkTwo"]
            for (i = 0; i < endingwith.length; i++) {
                sel += FLTK.checkbox.selectedCount(true, endingwith[i])
            }
        }
        else {
            sel = FLTK.checkbox.selectedCount(true, endingwith);
        }

        if (sel === 0) {
            alert(noneSelected);
            return false;
        }

        if (oneSelected && manySelected) {
            var message = (sel === 1) ? oneSelected : manySelected;
            return confirm(message);
        }

        // There was no param for confirming the action for one or many
        return true;
    }
};

FLTK.components = {
    instructions: {
        hideMessage: function(control, page, view) {
            $("#" + control).hide();
            $.cookie(page + "-" + control + "-" + view, "1");
        },
        loadMessage: function(control, page, view) {
            if ($.cookie(page + "-" + control + "-" + view) === "1") {
                $("#" + control).hide();
            }
        }
    },
    formViewer: {
        clearForm: function(control) {

            var inputs = control.getElementsByTagName("input");
            for (var i = 0; i < inputs.length; i++) {
                if (inputs[i].type == 'text' || inputs[i].type == 'hidden')
                    inputs[i].value = '';
                else if (inputs[i].type == 'checkbox' || inputs[i].type == 'radio')
                    inputs[i].checked = false;
            }
            var inputs = control.getElementsByTagName("textarea");
            for (var i = 0; i < inputs.length; i++) {
                inputs[i].value = '';
            }
            var inputs = control.getElementsByTagName("select");
            for (var i = 0; i < inputs.length; i++) {
                inputs[i].selectedIndex = 0;
            }
        }
    },
    userSearch: {
        init: function($searchFor, $searchBy) {
            var doHide = function() {
                $searchFor.closest("tr").siblings("tr").show();
                if ($searchFor.find(":checked").val() == "student" || $searchFor.find(":checked").val() == "") {
                    $searchBy.show();
                }
                else {
                    $searchBy.hide();
                }
            };
            doHide();
            $searchFor.click(doHide);
        }
    }
};

FLTK.datagrid = {
    init: function() {
        var $grids = $("#content").find("table.grid");
        
        FLTK.datagrid.initSelecting($grids);
        FLTK.datagrid.initSortable($grids.filter(".sortable"));
        FLTK.datagrid.initScrollable($grids.filter(".bodyscroll"));
        FLTK.datagrid.initReorder($grids.filter(".reorder-interactive"));
    },
    initSelecting: function($grids) {

        // helper function for the table row selecting
        var doSelect = function(checked, $row) {
            if (checked) {
                $row.addClass("selected");
            } else {
                $row.removeClass("selected");
            }
        };

        // keeps the top checkbox in sync with all of the others
        var setTopCheckState = function($rowChecks, $topCheck) {
            if ($rowChecks.length > 0 && ($rowChecks.length === $rowChecks.filter(":checked").length)) {
                $topCheck.attr("checked", "true");
            }
            else {
                $topCheck.removeAttr("checked");
            }
        };

        $grids.each(function() {
            var $rowCheckboxes = $(this).find("tbody .select input:checkbox");
            var $topCheckbox = $(this).find("thead .select input:checkbox");

            setTopCheckState($rowCheckboxes, $topCheckbox);  // make sure the 'select all' checkbox start out in correct state
            $rowCheckboxes.filter(":checked").parents("tr").addClass("selected"); // ones that are already selected to start need class

            $rowCheckboxes.click(function() { // select/deselect a single row
                doSelect(this.checked, $(this).parents("tr").eq(0));
                setTopCheckState($rowCheckboxes, $topCheckbox);
            });

            $topCheckbox.click(function() { // select/deselect all of the rows
                doSelect(this.checked, $rowCheckboxes.parents("tr"));
                setTopCheckState($rowCheckboxes, $(this));
            });
        });

    },
    initSortable: function($grids) {

        $grids.each(function() {

            if ($(this).find(".reorder:visible").size() > 0) //if reordering is on, don't allow sort
                return;

            var that = this,
                    cookieName = "sort_" + $(this).attr("id"),
                    cookie = $.cookie(cookieName),
                    sortList = (cookie) ? [cookie.split("_")] : undefined,
                    $notification = $(this).prev("div.notification");


            if ($notification.length > 0) {
                // bind the 'undo' link to remove the sort and hide the notification
                $notification.find("a").click(function() {
                    $.cookie(cookieName, null);
                    $(that).trigger("sorton", [[]]);
                    $(this).parent().slideUp(100);
                    return false;
                });

                if (sortList) {
                    // If there is a sort, set the text of the notification
                    var sortedBy = $(this).find("thead th").eq(sortList[0][0]);
                    $notification.show().removeAttr("style");
                    $notification.find(".sortstatus").text(sortedBy.text());
                }
            }

            // disable sort on headers with checkbox
            var headers = [];
            $(this).find("thead th.select").each(function(i) {
                headers[i] = {
                    sorter: false
                };
            });

            $(this).tablesorter({
                sortList: sortList,
                headers: headers,
                textExtraction: function(node) {
                    $node = $(node);
                    if ($node.find("span.dts").length > 0) {  // date
                        $node = $node.find("span.dts");
                    }
                    else if ($node.find("span.toggle").length > 0) {  // toggle checkboxes
                        $node = $node.find("span.toggle");
                    }
                    else if ($node.find("span.icon").length > 0) {  // file icons 
                        $node = $node.find("span.icon");
                    }
                    return $node.text();
                },
                sortComplete: function($table) {
                    // reset the zebra striping
                    $table.find("tbody tr").removeClass("alt").filter(":odd").addClass("alt");
                    FLTK.datagrid.resetScrollable($table);

                    if ($.browser.msie) {
                        // IE6 can lose checked value of boxes during sort, make sure they get checked
                        $table.find("tr.selected").find(".select input:checkbox:not(:checked)").attr("checked", "true");
                    }

                    // store sort value
                    var $column = $table.find("thead th.headerSortUp, thead th.headerSortDown").eq(0);
                    if ($column.length === 0) {
                        // Undo was clicked, or somehow there is no sorted column - don't want to set a cookie
                        return;
                    }

                    var val = $table.find("thead th").index($column);
                    var ASC = $column.hasClass("headerSortDown");
                    val = val + "_" + (ASC ? "0" : "1");
                    $.cookie(cookieName, val);

                    // show notification to remove if custom db sort is done
                    if ($notification.length > 0) {
                        $notification.slideDown(100);
                        $notification.find(".sortstatus").text($column.text());
                    }
                }
            });
        });
    },
    initScrollable: function($grids) {
        // Other browsers correcly implement the scrollable table in CSS, only need to handle IE
        if ($.browser.msie) {
            $grids.each(function() {
                var $container = $("<div/>").addClass("bodyscrollContainer");

                if ($.browser.version >= 7) {  // IE 6 gives extra room for scrollbar, others don't 
                    $container.css("padding-right", 16);
                }

                $(this).wrap($container);
            });
        }
    },
    resetScrollable: function($table) {
        // Jump back to the top of the table
        if ($table.is(".bodyscroll")) {
            var $scrollElement = ($.browser.msie) ? $table.parents(".bodyscrollContainer").eq(0) : $table.find("tbody");
            $scrollElement.scrollTop(0);
        }
    },
    reorderHelper: function(e, ui) {
        // Returns the helper element for the sortable function
        // See: http://lanitdev.wordpress.com/2009/07/23/make-table-rows-sortable-using-jquery-ui-sortable/
        ui.children().each(function() {
            $(this).width($(this).width());
        });
        return ui;
    },
    initReorder: function($grids) {
        $grids.each(function() {    
            var $grid = $(this),
                $hidSaveOrder = $("#" + $grid.attr("saveorder"));
            
           $(this).find("tbody").sortable({
                axis: "y",
                helper: FLTK.datagrid.reorderHelper,
                handle: ".reorder",
                //containment: "#body-content",
                start: function(e, ui) {
                    ui.item.addClass("dragging");
                },
                stop: function(e, ui) {
                    setTimeout(function() {
                        ui.item.removeClass("dragging"); }, 500);
                },
                update: function(e, ui) {                    
                    var order = [],
                        $allRows = $grid.find("tbody tr");
                    
                    $allRows.removeClass("alt").filter(":odd").addClass("alt");
                    
                    for (var i = 0; i < $allRows.length; i++) {
                        order[i] = $allRows.eq(i).find(".drag").attr("reorder");
                    }
                    
                    $hidSaveOrder.val(order.join(","));
                }
            }).disableSelection();
        });
    }
};

FLTK.error = {
    _callback: null,
    setCallback: function(fn) {
        if ($.isFunction(window.onerror)) {
            var _onerror = window.onerror;
            FLTK.error._callback = function() {
                // Call the original handler before new
                _onerror.apply(this, arguments);
                fn.apply(this, arguments);
            };
        }
        else {
            FLTK.error._callback = function() {
                fn.apply(window, arguments);
            };
        }

        window.onerror = function() {
            FLTK.error._callback.apply(this, arguments);
        };
    },
    report: function(ex) {
        var msg = ex.message;
        var lineNo = ex.lineNumber;
        var url = ex.fileName;
        var trace = ex.stackTrace || "";
        this._callback.apply(window, [msg, url, lineNo, trace]);
    }
};

FLTK.error.setCallback(function(msg, url, line, trace) {
    if (!serverVars.isDev) {
        //post error info, along with a time stamp to prevent server caching
        $.post(serverVars.errorURL, { message: msg, scriptUrl: url, line: line, pageUrl: window.location.href, stackTrace: trace, js: true, time: (new Date()).getTime() },
               function(response) { }
        );
    }
    else {
        FLTK.log("Error found (not posting to database)", { message: msg, url: url, line: line, stackTrace: trace });
    }
    return false;
});

FLTK.form = {
    init: function() {

        FLTK.form.initWaitMessage();

        // sometimes, dynamically named labels on "forms" (table with class "list") push the answers way right...limit the label width
        $("table.list").each(function() {
            try {
                if ($(this).find("th:first,td.main:first").width() > 250) {
                    if ($(this).find("td.main:first").size() === 0 || $(this).find("td.main:first").css("white-space") === "nowrap") {
                        $(this).find("th,td.main").each(function() {
                            $(this).css("width", "250px").css("min-width", "250px").css("max-width", "250px").css("white-space", "normal");
                            $(this).next().css("width", "").css("vertical-align", "bottom");
                        });
                        $(this).find("td:not(.main)").each(function() {
                            $(this).css("width", "auto").css("min-width", "auto").css("max-width", "auto");

                        });
                    }
                }
            } catch (e) { }
        });

        // Make sure dropdown fits on screen.  Ignore if it is in a form preview.
        $("select").each(function() {
            var $this = $(this);
            if ($this.parents("#formbody").length > 0) return; // $(select:not(#formbody > select")) was failing in safari

            if (!$this.is(".filteredList select")) {
                $this.find("option").each(function() {
                    // Strip the HTML out of each option - an option's .text() will return the actual html tags, but the div's .text() will not. 
                    var $div = $("<div>" + $(this).text() + "</div>");
                    if ($div.text() !== $(this).text()) {
                        $(this).text($div.text());
                    }
                });
                FLTK.form.validateDropdownWidth($this);
            }
        });
        // Expected behavior on certain textboxes of the "Enter" key submitting the form
        $("input:text[defaultButton]").keypress(function(e) {
            if (e.keyCode === 13) {
                $("#" + $(this).attr("defaultButton")).click();
                return false;
            }
        });
        
        if (($.browser.mozilla) || ($.browser.msie))
            FLTK.stylizeFileUpload($("div.realupload input")[0]);
    },
    validateDropdownWidth: function($dropdown) {
        if ($dropdown.width() > 30 && $.browser.msie) {
            // IE will crash if you try to set a negative maxwidth, and the width() returns 0 if element is hidden
            if ($.browser.version >= 8)  // IE8 reports the arrow as part of the width
                $dropdown.css("max-width", $dropdown.width()); 
            else  // Older versions need to account for the arrow width
                $dropdown.css("max-width", $dropdown.width() - 30);
        }
    },
    applyToAll: function(value, endingwith) {
        $(":asp("+endingwith+")").val(value);
    },
    enableValidator: function(validatorid, controlid, enable) {

        var $control = $("#" + controlid);
        // validatorenable calls Validate() - but we don't want the error text to show until a focus exit or submit click
        var val = $control.val(); // save orig value

        var addedoption = false;
        if ($control.is("select") && $control.find("option[value=0]").size() == 0) {
            addedoption = true;
            $control.append("<option value='0'>&nbsp;</option>");
        }
        $control[0].value = '0'; // make sure a valid value is there for nested validate call
        try// no validatorenable() function in some browsers
	    {
            ValidatorEnable($("#" + validatorid)[0], enable);
        } catch (e) { }
        if (addedoption)
            $control.find("option[value=0]").remove();
        $control[0].value = val; // change value back
    },
    initWaitMessage: function() {
        $(".dowait").click(function() {
            var $control = $(this);
            if ($control.parent().is("strong"))
                $control = $control.parent();

            if ($control.prev().is(".waitmessage")) {
                try {
                    Page_ClientValidate();
                }
                catch (exc) {
                    Page_IsValid = true;
                }
                if (Page_IsValid) {
                    $control.hide();
                    $control.prev().show();
                }
            }
        });
    },
    getRadioButton: function(groupname, value, label, attr) {
        var id = groupname + "_" + value;
        var $div = $("<div />").html("<input type='radio' value='"+value+"' name='"+groupname+"' id='"+id+"' /><label for='"+id+"'>"+label+"</label>");
        if (attr) {
            $div.find("input").attr(attr);
        }
        return $div.html();
    },
    getCheckbox: function(name, value, label, attr) {
        var id = name + "_" + value;
        var $div = $("<div />").html("<label><input type='checkbox' value='"+value+"' name='"+name+"' id='"+id+"' />"+label+"</label>"); //<label for='"+id+"'>"+label+"</label>");
        
        if (attr) {
            $div.find("input").attr(attr);
        }
        return $div.html();
    }
};

FLTK.isNumber = function(val) {
    return typeof val === 'number' && isFinite(val);
};

function log() {
    if (serverVars.isDev && window['console'] && console.log) {
        console.log(arguments);
    }
}
FLTK.log = log;

FLTK.logEvents = logEvents = function($el) {
    var e = $el.data('events');
    log("Logging Events for: ", $el);
    for (var i in e) {
        for (var i2 in e[i]) {
            log(i, e[i][i2], e[i][i2].toString());
        }    
    }
};

FLTK.menu = {
    initSections: function(menuCookieID) {
    
        $("#menu h4").click(function(e) {
            if (e.target != this) { // don't fire for sub-elements
                return;
            }
            var $this = $(this);
            if ($this.attr("class") === "over") {
                $.cookie('menuSec' + $this.attr("id") + '_' + menuCookieID, "1");
                $this.attr("class", "over-sel");
                $this.find("ul:first").show();
            }
            else {
                $.cookie('menuSec' + $this.attr("id") + '_' + menuCookieID, "0");
                $this.attr("class", "over");
                $this.find("ul:first").hide();
            }
        })
        .mouseover(function() {
            var $this = $(this);
            if ($this.attr("class") == "" || $this.attr("class") == null) {
                $this.attr("class", "over");
            }
            else {
                $this.attr("class", "over-sel");
            }
        })
        .mouseout(function() {
            var $this = $(this);
            if ($this.attr("class") == "over") {
                $this.attr("class", "");
            }
            else {
                $this.attr("class", "sel");
            }
        })
        .each(function() {
            var $this = $(this);
            var secVal = $.cookie('menuSec' + $this.attr("id") + '_' + menuCookieID);
            if (secVal == '1') {
                $this.addClass("sel");
                $this.find("ul:first").show();
            }
        });
    },
    sectionFade: function() {
        var $menuSec = $("#menuSec strong");
        $menuSec.css({ backgroundColor: "#f0ff99" });

        // relies on jQuery UI Effects Core to animate backgroundColor
        setTimeout(function() {
            $menuSec.animate({ backgroundColor: "transparent" }, 1000);
        }, 1500);
    }
};

FLTK.responseFilter = {
    on: true,
    init: function(target) {
        // Replaces page html which clears any previously attached events
        // if term replacement fails on server (because term is broken by buffering), do it here
        if (this.on) {
            try {
                target = target ? $(target)[0] : $("#content2")[0];
                if ((/\[\!\-\-/m).exec(target.innerHTML)) {
                    // don't do anything if it doesn't look like terms were missed
                    target.innerHTML = target.innerHTML.replace(/\[\!\-\-/gm, "").replace(/\-\-\!\]/gm, "");
                }
            } catch (e) { }


            //This grabs any textbox on the page that has html tags in it and replaces them with the bbcode equivalent
            $("textarea:not(.nobbcode), input:text:not(.nobbcode)").filter(function() {
                return $(this).val().match(/<\/?(.|\n)*?>/);
            }).each(function() {
                var parentid = $(this).parent().attr("id");
                if (parentid.indexOf("_") > 0)
                    parentid = parentid.substring(parentid.lastIndexOf("_"));


                if (parentid == "_htmlEditorArea") // "continue" - skip textareas that are for the wysiwyg box
                    return true;

                var val = $(this).val();

                var regexArr = [/<BR(.*?)\/>/gi,
                                /<UL[^>]*>/gi,
                                /<\/UL>/gi,
                                /<OL[^>]*>/gi,
                                /<\/OL>/gi,
                                /<LI>/gi,
                                /<\/li>/gi,
                                /<B>/gi,
                                /<\/B>/gi,
                                /<STRONG>/gi,
                                /<\/STRONG>/gi,
                                /<U>/gi,
                                /<\/U>/gi,
                                /<I>/gi,
                                /<\/I>/gi,
                                /<EM>/gi,
                                /<\/EM>/gi,
                                /<SUP>/gi,
                                /<\/SUP>/gi,
                                /<SUB>/gi,
                                /<\/SUB>/gi,
                                /<HR[^>]*>/gi,
                                /<STRIKE>/gi,
                                /<\/STRIKE>/gi,
                                /<h1>/gi,
                                /<\/h1>/gi,
                                /<h2>/gi,
                                /<\/h2>/gi,
                                /<h3>/gi,
                                /<\/h3>/gi];

                var bbcodeArr = ["[br]",
                                 "[ulist]",
                                 "[/ulist]",
                                 "[olist]",
                                 "[/olist]",
                                 "[*]",
                                 "",
                                 "[b]",
                                 "[/b]",
                                 "[strong]",
                                 "[/strong]",
                                 "[u]",
                                 "[/u]",
                                 "[i]",
                                 "[/i]",
                                 "[em]",
                                 "[/em]",
                                 "[sup]",
                                 "[/sup]",
                                 "[sub]",
                                 "[/sub]",
                                 "[hr]",
                                 "[s]",
                                 "[/s]",
                                 "[h1]",
                                 "[/h1]",
                                 "[h2]",
                                 "[/h2]",
                                 "[h3]",
                                 "[/h3]",
                                 ];

                //replace html with BBCode
                for (var i = 0; i < regexArr.length; i++) {
                    val = val.replace(regexArr[i], bbcodeArr[i]);
                }

                //replace anchors and images separate since they have attributes
                val = val.replace(/<A HREF=\"/gi, "[url=");
                val = val.replace(/<\/A>/gi, "[/url]");
                val = val.replace(/<IMG[\s\S]*?SRC=\"([\s\S]*?)\"[\s\S]*?>/gi, "[img]$1[\/img]");

                val = val.replace(/\">/g, "]");

                $(this).val(val);
            });
        }
    }
};

FLTK.scrollLocation = {
    $scroll: null,
    save: function() {
        this.$scroll.val($(window).scrollTop());
    },
    init: function(id) {
        this.$scroll = $('#' + id);
        var scrollLocation = parseInt(this.$scroll.val(), 10);
        
        if (FLTK.isNumber(scrollLocation) && scrollLocation > 0) {
            //$("html, body").animate({scrollTop:scrollLocation}, 100);
            scrollTo(0, scrollLocation);
            this.$scroll.val("");  // Reset the scroll location - don't persist between pages
        }
    }
};

FLTK.openFileEditor = function(url, allowDHTML) {

    // Opens a special instance of the popup where it will wait to unload until a new page has been loaded
    // if allowDHTML is false, then it will simply open the popup in a traditional window
    
    hidePopWin(false);
    FLTK.showDialog({
        windowname: "_blank",
        url: url,
        width: 10000,
        height: 10000,
        resizable: false,
        scrollbars: false,
        allowDHTML: allowDHTML,
        waitForUnload: true,
        returnFunc: function() {
            if (parent.getNewComments) {
                parent.getNewComments();
            }
        }
    });
};

FLTK.showDialog = function(opts) {

    var spec = {
        windowname: opts.windowname || "",
        url: opts.url || "",
        width: opts.width || 400,
        height: opts.height || 200,
        returnFunc: opts.returnFunc || null,
        allowDHTML: (opts.allowDHTML !== false),  //defaults to true
        resizable: (opts.resizable) ? "yes" : "0",
        scrollbars: (opts.scrollbars) ? "yes" : "auto",
        titleBarTitle: opts.titleBarTitle || "",
        titleBarClass: opts.titleBarClass || "",
        titleBarDescription: opts.titleBarDescription || "",
        titleBarCrumbInfo: opts.titleBarCrumbInfo || "",
        waitForUnload: opts.waitForUnload || false
    };

    if (spec.allowDHTML && serverVars.useDHTML) {
        spec.width += 4;
        showPopWin(spec.url, spec.width, spec.height, spec.returnFunc, spec.titleBarTitle, spec.titleBarClass,
                    spec.titleBarDescription, spec.titleBarCrumbInfo, spec.waitForUnload);
    }
    else {
        if (spec.width > 800) {
            spec.width = 800;
        }
        if (spec.height > 600) {
            spec.height = 600;
        }
        var menubar = 0;
        if (!opts.allowDHTML) {
            menubar = 1;
        }
        spec.windowname = spec.windowname.replace(" ", "_");

        var windowFeatures = "width=" + spec.width + ",height=" + spec.height + ",toolbar=0,location=0,directories=0,status=0,menubar=" + menubar + ",resizable=" + spec.resizable + ",scrollbars=" + spec.scrollbars;
        try {
            window.open(spec.url, spec.windowname, windowFeatures);
        } catch (e) {
            alert("Your browser blocked the popup '"+spec.windowname.replace("_"," ")+"'. Please disable your popup blocker to see this window.");
        }
    }
};

FLTK.showProcessing = function(opts) {
    // only show if passes dotnet validation
    try {
        Page_ClientValidate();
    }
    catch (exc) {
        Page_IsValid = true;
    }
    if (Page_IsValid) {
        var spec = {
            width: opts.width || 500,
            height: opts.height || 200,
            text: opts.text || "Processing... Please wait.",
            explanation: opts.explanation || ""
        };

        $("#processing").dialog('option', 'width', spec.width).dialog('option', 'height', spec.height).dialog("open");
        $("#processing div").eq(0).text(spec.text);
        $("#processing div.explanation").text(spec.explanation);
        $("#addprocessinggif").addClass("processinggif");
    }

};

/* File Upload Functions */

FLTK.uploadFile = function(opts) {
    var submitButton = $("#SubmitFileUpload a.ico_add");
    var file = $("#UploadFile input:first");
    
    eval(submitButton.attr("href"));    
    FLTK.animateAttach();
};

FLTK.cancelAttachFile = function(opts) {
    var file = $("#UploadFile input:first");
    var attachFileOption = $("#AttachFileOption");
    var saveFileOptions = $("#SaveFileOptions");

    saveFileOptions.addClass("hide");
    attachFileOption.show();
    file.val('');
};

FLTK.animateAttach = function(opts) {
    var attachAnimation = $("#AttachAnimation");
    var attachFileOption = $("#AttachFileOption");
    var saveFileOptions = $("#SaveFileOptions");
    var wording = $("#Attaching");

    attachAnimation.show();
    attachFileOption.hide();
    saveFileOptions.addClass("hide");

    wording.text(wording.text() + ".");

    if (wording.text() == ".....")
        wording.text("");    
};

/* This is really goofy javascript.  It basically moves the file upload control under the cursor as it moves.  This is used
   in IE and Firefox.
*/
FLTK.stylizeFileUpload = function(elem) {
    if (typeof elem == 'undefined')
        return;
    elem.parentNode.file = elem;

    var extraOffset = 0;
    if ($.browser.msie)
        extraOffset = 40;

    var minLeft = elem.offsetLeft - 260;
    var maxLeft = elem.offsetLeft + elem.offsetWidth;

    elem.parentNode.onmousemove = function(e) {
        if (typeof e == 'undefined') e = window.event;
        if (typeof e.pageY == 'undefined' && typeof e.clientX == 'number' && document.documentElement) {
            e.pageX = e.clientX + document.documentElement.scrollLeft;
            e.pageY = e.clientY + document.documentElement.scrollTop;
        };

        var ox = oy = 0;
        var elem = this;
        if (elem.offsetParent) {
            ox = elem.offsetLeft;
            oy = elem.offsetTop;
            while (elem = elem.offsetParent) {
                ox += elem.offsetLeft;
                oy += elem.offsetTop;
            };
        };

        var x = e.pageX - ox;
        var y = e.pageY - oy;
        var w = this.file.offsetWidth;
        var h = this.file.offsetHeight;

        var leftOffset = x - (w - 30);

        if (leftOffset < minLeft)
            leftOffset = minLeft + 260 + extraOffset;

        if (leftOffset > 0)
            leftOffset = minLeft;

        this.file.style.left = leftOffset + 'px';
    };
};





FLTK.fixDate = function(input) {// dotnet validators does not 
var $input = $(input);
    
    var dateparts = $input.val().split("/");
    if (dateparts.length == 1) {
        if (dateparts[0].length > 0) {
            $input.val((parseInt(new Date().getMonth()) + 1) + "/" + dateparts[0] + "/" + new Date().getFullYear());
            Page_ClientValidate();//re-check
        }
    }
    else if (dateparts.length == 2) {
        $input.val(dateparts[0] + "/" + dateparts[1] + "/" + new Date().getFullYear());
        Page_ClientValidate(); //re-check
    }
    else if (dateparts.length == 3) {
        var year = dateparts[2];
        if (year.length == 4)
            return;
            
        var curyear = new Date().getFullYear().toString();
        if (year.length == 0)
            year = curyear;
        else if (year.length == 1)
            year = curyear.substring(0, 3) + year;
        else if (year.length == 2)
            year = curyear.substring(0, 2) + year;
        else if (year.length == 3)
            year = curyear.substring(0, 1) + year;

        $input.val(dateparts[0] + "/" + dateparts[1] + "/" + year);
        Page_ClientValidate(); //re-check
    }
}

FLTK.timer = {
    timeout: null,
    start: function() {
        FLTK.timer.timeout = setTimeout(function() {
            try {
                FLTK.showDialog({
                    windowname: "warning",
                    url: serverVars.timeoutURL,
                    width: 300,
                    height: 190,
                    resizable: false,
                    scrollbars: false
                });
            } catch (exc) { }
        }, serverVars.timeoutLength);
    },
    clear: function() {
        clearTimeout(FLTK.timer.timeout);
    }
};

FLTK.reportfilter = {
    init: function() {        
        FLTK.reportfilter.showdatefilter();
        FLTK.reportfilter.showotherfilter();
    },
    showdatefilter: function() {
        var cbFilterByDate = $(":asp(cbFilterByDate)");
        var dateFilter = $("#DateFilterBlock");

        if (cbFilterByDate[0].checked) {
            dateFilter.show();
            cbFilterByDate.show();
        }
        else
            dateFilter.hide();

        FLTK.reportfilter.showdatefiltertype();
    },
    showdatefiltertype: function() {
        var rbFilterByMonth = $(":asp(rbFilterByMonth)");
        var monthFilterType = $("#MonthFilterType");
        var rangeFilterType = $("#RangeFilterType");

        monthFilterType.hide();
        rangeFilterType.hide();

        if (rbFilterByMonth[0].checked)
            monthFilterType.show();
        else
            rangeFilterType.show();
    },

    showotherfilter: function() {
        var cbFilterByOtherCriteria = $(":asp(cbFilterByOtherCriteria)");
        var otherFilter = $("#OtherFilterBlock");

        if (cbFilterByOtherCriteria[0].checked) 
            otherFilter.show();
        else
            otherFilter.hide();

        FLTK.reportfilter.showotherfiltertype();
    },
    showotherfiltertype: function() {
        var rbFilterByProgramGroup = $(":asp(rbFilterByProgramGroup)");
        var rbFilterByCourseSection = $(":asp(rbFilterByCourseSection)");
        var rbFilterByProfileField = $(":asp(rbFilterByProfileField)");

        var programGroupType = $("#ProgramGroupFilterType");
        var courseSectionType = $("#CourseSectionFilterType");
        var profileFieldType = $("#ProfileFieldFilterType");

        programGroupType.hide();
        courseSectionType.hide();
        profileFieldType.hide();

        if (rbFilterByProgramGroup[0].checked)
            programGroupType.show();
        else if (rbFilterByCourseSection[0].checked)
            courseSectionType.show();
        else
            profileFieldType.show();
    }
}

FLTK.ui = {
    init: function()  {
        this.initSortable();
        $("#processing").dialog({ autoOpen: false, modal: true });
    },
    roundCorners: function() {
        if ($.browser.msie) {
            // See  http://support.lanit.com/default.asp?23084_h8m6ocv3 for issue about getting rid of the rounded corners
            var $menu = $("#menu").css("border", "none").wrap("<div />");
            $menu.parent().css("padding", "3px").css("background-color", "#cfcfcf");
            $menu.find(".item").css("padding-top", "3px").css("padding-bottom", "3px").corners("3px");
            $menu.parent().corners("3px");
        }
    },
    initSortable: function() {

        var fixHelper = function(e, ui) {
            // Return a helper with preserved width of cells
            ui.children().each(function() {
                $(this).width($(this).width());
            });
            return ui;
        };

        $.ui.sortable.defaults = $.extend($.ui.sortable.defaults, {
            axis: "y",
            helper: fixHelper,
            cursor: "move"
        });
    },
    highlight: function($collection, time) {
        $collection.each(function() {
            var oldback = $(this).css("background-color");
            $(this).css("background-color", "#F7F796").animate({
                backgroundColor: oldback
            }, time || 2000);
        });
    }
};

//CheckBoxListValidator code
// ex : if ($("input:checkbox").ischecked())
$.fn.ischecked = function() {
    var $box = $(this);
    var checked = $box.attr("checked");
    return (checked == "checked" || checked);
}

function IsCBLValid(val) {
    var $control = $("#" + val.controltovalidate);
    var numNeeded = parseInt(val.minimumNumberOfSelectedCheckBoxes);

    var selectedItemCount = 0;
    $control.find("input:checkbox").each(function() {
        var $checkbox = $(this);
        if ($checkbox.ischecked()) {
            selectedItemCount++;
        }
    });

    return selectedItemCount >= numNeeded;
}

$.fn.outerHtml = function() {
    if (this[0]) {
        if (this[0].outerHTML) {
            return this[0].outerHTML;
        }
        var container = this[0].ownerDocument.createElement("div");
        return $(container).append($(this[0]).clone()).html();
    }
};

// JSON Parser for browsers that do not natively support JSON (http://www.json.org/json2.js)
if(!this.JSON){this.JSON={};}(function(){function f(n){return n<10?'0'+n:n;}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}if(typeof rep==='function'){value=rep.call(holder,key,value);}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value});};}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}return reviver.call(holder,key,value);}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}throw new SyntaxError('JSON.parse');};}}());
