// This JavaScript was automatically generated by
// Jayrock.JsonRpc.Web.JsonRpcProxyGenerator, Jayrock, Version=0.9.8316.0, Culture=neutral, PublicKeyToken=null
// on Wednesday, July 01, 2009 at 1:24:31 AM (Eastern Daylight Time)

// Proxy version 1.0

function JsonService(url)
{
    this["GetUserSummary"] = function(userDate, callback)
    {
        return call("GetUserSummary", [ userDate ], callback);
    }
    
    this["DeleteCategory"] = function(categoryID, callback)
    {
        return call("DeleteCategory", [ categoryID ], callback);
    }
    
    this["InsertCategory"] = function(category, callback)
    {
        return call("InsertCategory", [ category ], callback);
    }
    
    this["UpdateCategory"] = function(category, callback)
    {
        return call("UpdateCategory", [ category ], callback);
    }
    
    this["InsertSubCategory"] = function(subCategory, callback)
    {
        return call("InsertSubCategory", [ subCategory ], callback);
    }
    
    this["UpdateSubCategory"] = function(subCategory, callback)
    {
        return call("UpdateSubCategory", [ subCategory ], callback);
    }
    
    this["DeleteSubCategory"] = function(subCategoryID, callback)
    {
        return call("DeleteSubCategory", [ subCategoryID ], callback);
    }
    
    this["InsertTrans"] = function(trans, callback)
    {
        return call("InsertTrans", [ trans ], callback);
    }
    
    this["DeleteTrans"] = function(transID, callback)
    {
        return call("DeleteTrans", [ transID ], callback);
    }
    
    this["UpdateTrans"] = function(trans, callback)
    {
        return call("UpdateTrans", [ trans ], callback);
    }
    
    this["SearchTrans"] = function(startDate, endDate, categoryType, catIDString, amountOperator, amount, callback)
    {
        return call("SearchTrans", [ startDate, endDate, categoryType, catIDString, amountOperator, amount ], callback);
    }
    
    this["GetTransPieGraphForDefaultDateRange"] = function(defaultDateRange, categoryType, currentUserDate, callback)
    {
        return call("GetTransPieGraphForDefaultDateRange", [ defaultDateRange, categoryType, currentUserDate ], callback);
    }
    
    this["GetTransPieGraphForCustomDateRange"] = function(categoryType, startDate, endDate, callback)
    {
        return call("GetTransPieGraphForCustomDateRange", [ categoryType, startDate, endDate ], callback);
    }
    
    /* Returns an array of method names implemented by this service. */
    
    this["system.listMethods"] = function(callback)
    {
        return call("system.listMethods", [ ], callback);
    }
    
    /* Returns the version server implementation using the major, minor, build and revision format. */
    
    this["system.version"] = function(callback)
    {
        return call("system.version", [ ], callback);
    }
    
    /* Returns a summary about the server implementation for display purposes. */
    
    this["system.about"] = function(callback)
    {
        return call("system.about", [ ], callback);
    }

    var serviceURL = "http://" + window.location.host + "/Service/JsonService.ashx";
    var url = typeof (url) === 'string' ? url : serviceURL;
    var self = this;
    var nextId = 0;

    function call(method, params, callback)
    {
        var request = { id : nextId++, method : method, params : params };
        return callback == null ? 
            callSync(method, request) : callAsync(method, request, callback);
    }

    function callSync(method, request)
    {
        var http = newHTTP();
        http.open('POST', url, false, self.httpUserName, self.httpPassword);
        setupHeaders(http, method);
        http.send(JSON.stringify(request));
        if (http.status != 200)
            throw { message : http.status + ' ' + http.statusText, toString : function() { return message; } };
        var response = JSON.eval(http.responseText);
        if (response.error != null) throw response.error;
        return response.result;
    }

    function callAsync(method, request, callback)
    {
        var http = newHTTP();
        http.open('POST', url, true, self.httpUserName, self.httpPassword);
        setupHeaders(http, method);
        http.onreadystatechange = function() { http_onreadystatechange(http, callback); }
        http.send(JSON.stringify(request));
        return request.id;
    }

    function setupHeaders(http, method)
    {
        http.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');
        http.setRequestHeader('X-JSON-RPC', method);
    }

    function http_onreadystatechange(sender, callback)
    {
        if (sender.readyState == /* complete */ 4)
        {
            var response = sender.status == 200 ? 
                JSON.eval(sender.responseText) : {};
            
            response.xmlHTTP = sender;
                
            callback(response);
        }
    }

    function newHTTP()
    {
        if (typeof(window) != 'undefined' && window.XMLHttpRequest)
            return new XMLHttpRequest(); /* IE7, Safari 1.2, Mozilla 1.0/Firefox, and Netscape 7 */
        else
            return new ActiveXObject('Microsoft.XMLHTTP'); /* WSH and IE 5 to IE 6 */
    }
}

JsonService.rpcMethods = ["GetUserSummary","DeleteCategory","InsertCategory","UpdateCategory","InsertSubCategory","UpdateSubCategory","DeleteSubCategory","InsertTrans","DeleteTrans","UpdateTrans","SearchTrans","GetTransPieGraphForDefaultDateRange","GetTransPieGraphForCustomDateRange","system.listMethods","system.version","system.about"];
/*
Copyright (c) 2005 JSON.org
/*
    The global object JSON contains two methods.

    JSON.stringify(value) takes a JavaScript value and produces a JSON text.
    The value must not be cyclical.

    JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
    return false if there is an error.
*/
var JSON = function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            'boolean': function (x) {
                return String(x);
            },
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            },
            object: function (x) {
                if (x) {
                    var a = [], b, f, i, l, v;
                    if (x instanceof Array) {
                        a[0] = '[';
                        l = x.length;
                        for (i = 0; i < l; i += 1) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a[a.length] = v;
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = ']';
                    } else if (x instanceof Date) {
                        function p(n) { return n < 10 ? '0' + n : n; };
                        var tz = x.getTimezoneOffset();
                        if (tz != 0) {
                            var tzh = Math.floor(Math.abs(tz) / 60);
                            var tzm = Math.abs(tz) % 60;
                            tz = (tz < 0 ? '+' : '-') + p(tzh) + ':' + p(tzm);
                        }
                        else {
                            tz = 'Z';
                        }
                        return '"' + 
                                x.getFullYear() + '-' +
                                p(x.getMonth() + 1) + '-' +
                                p(x.getDate()) + 'T' +
                                p(x.getHours()) + ':' +
                                p(x.getMinutes()) + ':' +
                                p(x.getSeconds()) + tz + '"';
                    } else if (x instanceof Object) {
                        a[0] = '{';
                        for (i in x) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a.push(s.string(i), ':', v);
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = '}';
                    } else {
                        return;
                    }
                    return a.join('');
                }
                return 'null';
            }
        };
    return {
        copyright: '(c)2005 JSON.org',
        license: 'http://www.crockford.com/JSON/license.html',
/*
    Stringify a JavaScript value, producing a JSON text.
*/
        stringify: function (v) {
            var f = s[typeof v];
            if (f) {
                v = f(v);
                if (typeof v == 'string') {
                    return v;
                }
            }
            return null;
        },
/*
    Parse a JSON text, producing a JavaScript value.
    It returns false if there is a syntax error.
*/
        eval: function (text) {
            try {
                if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(text)) {
                    return eval('(' + text + ')');
                }
            } catch (e) {
            }
            throw new SyntaxError("eval");
        },

        parse: function (text) {
            var at = 0;
            var ch = ' ';

            function error(m) {
                throw {
                    name: 'JSONError',
                    message: m,
                    at: at - 1,
                    text: text
                };
            }

            function next() {
                ch = text.charAt(at);
                at += 1;
                return ch;
            }

            function white() {
                while (ch) {
                    if (ch <= ' ') {
                        next();
                    } else if (ch == '/') {
                        switch (next()) {
                            case '/':
                                while (next() && ch != '\n' && ch != '\r') {}
                                break;
                            case '*':
                                next();
                                for (;;) {
                                    if (ch) {
                                        if (ch == '*') {
                                            if (next() == '/') {
                                                next();
                                                break;
                                            }
                                        } else {
                                            next();
                                        }
                                    } else {
                                        error("Unterminated comment");
                                    }
                                }
                                break;
                            default:
                                error("Syntax error");
                        }
                    } else {
                        break;
                    }
                }
            }

            function string() {
                var i, s = '', t, u;

                if (ch == '"') {
    outer:          while (next()) {
                        if (ch == '"') {
                            next();
                            return s;
                        } else if (ch == '\\') {
                            switch (next()) {
                            case 'b':
                                s += '\b';
                                break;
                            case 'f':
                                s += '\f';
                                break;
                            case 'n':
                                s += '\n';
                                break;
                            case 'r':
                                s += '\r';
                                break;
                            case 't':
                                s += '\t';
                                break;
                            case 'u':
                                u = 0;
                                for (i = 0; i < 4; i += 1) {
                                    t = parseInt(next(), 16);
                                    if (!isFinite(t)) {
                                        break outer;
                                    }
                                    u = u * 16 + t;
                                }
                                s += String.fromCharCode(u);
                                break;
                            default:
                                s += ch;
                            }
                        } else {
                            s += ch;
                        }
                    }
                }
                error("Bad string");
            }

            function array() {
                var a = [];

                if (ch == '[') {
                    next();
                    white();
                    if (ch == ']') {
                        next();
                        return a;
                    }
                    while (ch) {
                        a.push(value());
                        white();
                        if (ch == ']') {
                            next();
                            return a;
                        } else if (ch != ',') {
                            break;
                        }
                        next();
                        white();
                    }
                }
                error("Bad array");
            }

            function object() {
                var k, o = {};

                if (ch == '{') {
                    next();
                    white();
                    if (ch == '}') {
                        next();
                        return o;
                    }
                    while (ch) {
                        k = string();
                        white();
                        if (ch != ':') {
                            break;
                        }
                        next();
                        o[k] = value();
                        white();
                        if (ch == '}') {
                            next();
                            return o;
                        } else if (ch != ',') {
                            break;
                        }
                        next();
                        white();
                    }
                }
                error("Bad object");
            }

            function number() {
                var n = '', v;
                if (ch == '-') {
                    n = '-';
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    n += ch;
                    next();
                }
                if (ch == '.') {
                    n += '.';
                    while (next() && ch >= '0' && ch <= '9') {
                        n += ch;
                    }
                }
                if (ch == 'e' || ch == 'E') {
                    n += 'e';
                    next();
                    if (ch == '-' || ch == '+') {
                        n += ch;
                        next();
                    }
                    while (ch >= '0' && ch <= '9') {
                        n += ch;
                        next();
                    }
                }
                v = +n;
                if (!isFinite(v)) {
                    ////error("Bad number");
                } else {
                    return v;
                }
            }

            function word() {
                switch (ch) {
                    case 't':
                        if (next() == 'r' && next() == 'u' && next() == 'e') {
                            next();
                            return true;
                        }
                        break;
                    case 'f':
                        if (next() == 'a' && next() == 'l' && next() == 's' &&
                                next() == 'e') {
                            next();
                            return false;
                        }
                        break;
                    case 'n':
                        if (next() == 'u' && next() == 'l' && next() == 'l') {
                            next();
                            return null;
                        }
                        break;
                }
                error("Syntax error");
            }

            function value() {
                white();
                switch (ch) {
                    case '{':
                        return object();
                    case '[':
                        return array();
                    case '"':
                        return string();
                    case '-':
                        return number();
                    default:
                        return ch >= '0' && ch <= '9' ? number() : word();
                }
            }

            return value();
        }
    };
}();// -------------------------------------------------------------------
// DHTML Window Widget- By Dynamic Drive, available at: http://www.dynamicdrive.com
// v1.0: Script created Feb 15th, 07'
// v1.01: Feb 21th, 07' (see changelog.txt)
// v1.02: March 26th, 07' (see changelog.txt)
// v1.03: May 5th, 07' (see changelog.txt)
// v1.1:  Oct 29th, 07' (see changelog.txt)
// -------------------------------------------------------------------

var dhtmlwindow =
{
    imagefiles: ['images/min.gif', 'images/close.gif', 'images/restore.gif', 'images/resize.gif'], //Path to 4 images used by script, in that order
    ajaxbustcache: true, //Bust caching when fetching a file via Ajax?
    ajaxloadinghtml: '<b>Loading Page. Please wait...</b>', //HTML to show while window fetches Ajax Content?

    minimizeorder: 0,
    zIndexvalue: 100,
    tobjects: [], //object to contain references to dhtml window divs, for cleanup purposes
    lastactivet: {}, //reference to last active DHTML window

    closeFunction: null,

    setCloseFunction: function(f)
    {
        this.closeFunction = f;
    },

    init: function(t)
    {
        var domwindow = document.createElement("div") //create dhtml window div
        domwindow.id = t
        domwindow.className = "dhtmlwindow"
        var domwindowdata = ''
        domwindowdata = '<div class="drag-handle">'
        domwindowdata += 'DHTML Window <div class="drag-controls"><img src="' + this.imagefiles[0] + '" title="Minimize" /><img src="' + this.imagefiles[1] + '" title="Close" /></div>'
        domwindowdata += '</div>'
        domwindowdata += '<div class="drag-contentarea"></div>'
        domwindowdata += '<div class="drag-statusarea"><div class="drag-resizearea" style="background: transparent url(' + this.imagefiles[3] + ') top right no-repeat;">&nbsp;</div></div>'
        domwindowdata += '</div>'
        domwindow.innerHTML = domwindowdata
        document.getElementById("dhtmlwindowholder").appendChild(domwindow)
        //this.zIndexvalue=(this.zIndexvalue)? this.zIndexvalue+1 : 100 //z-index value for DHTML window: starts at 0, increments whenever a window has focus
        var t = document.getElementById(t)
        var divs = t.getElementsByTagName("div")
        for (var i = 0; i < divs.length; i++)
        { //go through divs inside dhtml window and extract all those with class="drag-" prefix
            if (/drag-/.test(divs[i].className))
                t[divs[i].className.replace(/drag-/, "")] = divs[i] //take out the "drag-" prefix for shorter access by name
        }
        //t.style.zIndex=this.zIndexvalue //set z-index of this dhtml window
        t.handle._parent = t //store back reference to dhtml window
        t.resizearea._parent = t //same
        t.controls._parent = t //same
        t.onclose = function() { return true } //custom event handler "onclose"
        t.onmousedown = function() { dhtmlwindow.setfocus(this) } //Increase z-index of window when focus is on it
        t.handle.onmousedown = dhtmlwindow.setupdrag //set up drag behavior when mouse down on handle div
        t.resizearea.onmousedown = dhtmlwindow.setupdrag //set up drag behavior when mouse down on resize div
        t.controls.onclick = dhtmlwindow.enablecontrols
        t.show = function() { dhtmlwindow.show(this) } //public function for showing dhtml window
        t.hide = function() { dhtmlwindow.hide(this) } //public function for hiding dhtml window
        t.close = function() { dhtmlwindow.close(this) } //public function for closing dhtml window (also empties DHTML window content)
        t.setSize = function(w, h) { dhtmlwindow.setSize(this, w, h) } //public function for setting window dimensions
        t.moveTo = function(x, y) { dhtmlwindow.moveTo(this, x, y) } //public function for moving dhtml window (relative to viewpoint)
        t.isResize = function(bol) { dhtmlwindow.isResize(this, bol) } //public function for specifying if window is resizable
        t.isScrolling = function(bol) { dhtmlwindow.isScrolling(this, bol) } //public function for specifying if window content contains scrollbars
        t.load = function(contenttype, contentsource, title) { dhtmlwindow.load(this, contenttype, contentsource, title) } //public function for loading content into window
        this.tobjects[this.tobjects.length] = t
        return t //return reference to dhtml window div
    },

    open: function(t, contenttype, contentsource, title, attr, recalonload, onCloseFunction)
    {
        var d = dhtmlwindow //reference dhtml window object
        function getValue(Name)
        {
            var config = new RegExp(Name + "=([^,]+)", "i") //get name/value config pair (ie: width=400px,)
            return (config.test(attr)) ? parseInt(RegExp.$1) : 0 //return value portion (int), or 0 (false) if none found
        }
        if (document.getElementById(t) == null) //if window doesn't exist yet, create it
            t = this.init(t) //return reference to dhtml window div
        else
            t = document.getElementById(t)
        this.setfocus(t)
        t.setSize(getValue(("width")), (getValue("height"))) //Set dimensions of window
        var xpos = getValue("center") ? "middle" : getValue("left") //Get x coord of window
        var ypos = getValue("center") ? "middle" : getValue("top") //Get y coord of window
        //t.moveTo(xpos, ypos) //Position window
        if (typeof recalonload != "undefined" && recalonload == "recal" && this.scroll_top == 0)
        { //reposition window when page fully loads with updated window viewpoints?
            if (window.attachEvent && !window.opera) //In IE, add another 400 milisecs on page load (viewpoint properties may return 0 b4 then)
                this.addEvent(window, function() { setTimeout(function() { t.moveTo(xpos, ypos) }, 400) }, "load")
            else
                this.addEvent(window, function() { t.moveTo(xpos, ypos) }, "load")
        }
        t.isResize(getValue("resize")) //Set whether window is resizable
        t.isScrolling(getValue("scrolling")) //Set whether window should contain scrollbars
        t.style.visibility = "visible"
        t.style.display = "block"
        t.contentarea.style.display = "block"
        t.moveTo(xpos, ypos) //Position window
        t.load(contenttype, contentsource, title)
        if (t.state == "minimized" && t.controls.firstChild.title == "Restore")
        { //If window exists and is currently minimized?
            t.controls.firstChild.setAttribute("src", dhtmlwindow.imagefiles[0]) //Change "restore" icon within window interface to "minimize" icon
            t.controls.firstChild.setAttribute("title", "Minimize")
            t.state = "fullview" //indicate the state of the window as being "fullview"
        }
        return t
    },

    setSize: function(t, w, h)
    { //set window size (min is 150px wide by 100px tall)
        t.style.width = Math.max(parseInt(w), 150) + "px"
        t.contentarea.style.height = Math.max(parseInt(h), 100) + "px"
    },

    moveTo: function(t, x, y)
    { //move window. Position includes current viewpoint of document
        this.getviewpoint() //Get current viewpoint numbers
        t.style.left = (x == "middle") ? this.scroll_left + (this.docwidth - t.offsetWidth) / 2 + "px" : this.scroll_left + parseInt(x) + "px"
        t.style.top = (y == "middle") ? this.scroll_top + (this.docheight - t.offsetHeight) / 2 + "px" : this.scroll_top + parseInt(y) + "px"
    },

    isResize: function(t, bol)
    { //show or hide resize inteface (part of the status bar)
        t.statusarea.style.display = (bol) ? "block" : "none"
        t.resizeBool = (bol) ? 1 : 0
    },

    isScrolling: function(t, bol)
    { //set whether loaded content contains scrollbars
        t.contentarea.style.overflow = (bol) ? "auto" : "hidden"
    },

    load: function(t, contenttype, contentsource, title)
    { //loads content into window plus set its title (3 content types: "inline", "iframe", or "ajax")
        if (t.isClosed)
        {
            alert("DHTML Window has been closed, so no window to load contents into. Open/Create the window again.")
            return
        }
        var contenttype = contenttype.toLowerCase() //convert string to lower case
        if (typeof title != "undefined")
            t.handle.firstChild.nodeValue = title
        if (contenttype == "inline")
            t.contentarea.innerHTML = contentsource
        else if (contenttype == "div")
        {
            var inlinedivref = document.getElementById(contentsource)
            t.contentarea.innerHTML = (inlinedivref.defaultHTML || inlinedivref.innerHTML) //Populate window with contents of inline div on page
            if (!inlinedivref.defaultHTML)
                inlinedivref.defaultHTML = inlinedivref.innerHTML //save HTML within inline DIV
            inlinedivref.innerHTML = "" //then, remove HTML within inline DIV (to prevent duplicate IDs, NAME attributes etc in contents of DHTML window
            inlinedivref.style.display = "none" //hide that div
        }
        else if (contenttype == "iframe")
        {
            t.contentarea.style.overflow = "hidden" //disable window scrollbars, as iframe already contains scrollbars
            if (!t.contentarea.firstChild || t.contentarea.firstChild.tagName != "IFRAME") //If iframe tag doesn't exist already, create it first
                t.contentarea.innerHTML = '<iframe src="" style="margin:0; padding:0; width:100%; height: 100%" name="_iframe-' + t.id + '"></iframe>'
            window.frames["_iframe-" + t.id].location.replace(contentsource) //set location of iframe window to specified URL
        }
        else if (contenttype == "ajax")
        {
            this.ajax_connect(contentsource, t) //populate window with external contents fetched via Ajax
        }
        t.contentarea.datatype = contenttype //store contenttype of current window for future reference
    },

    setupdrag: function(e)
    {
        var d = dhtmlwindow //reference dhtml window object
        var t = this._parent //reference dhtml window div
        d.etarget = this //remember div mouse is currently held down on ("handle" or "resize" div)
        var e = window.event || e
        d.initmousex = e.clientX //store x position of mouse onmousedown
        d.initmousey = e.clientY
        d.initx = parseInt(t.offsetLeft) //store offset x of window div onmousedown
        d.inity = parseInt(t.offsetTop)
        d.width = parseInt(t.offsetWidth) //store width of window div
        d.contentheight = parseInt(t.contentarea.offsetHeight) //store height of window div's content div
        if (t.contentarea.datatype == "iframe")
        { //if content of this window div is "iframe"
            t.style.backgroundColor = "#F8F8F8" //colorize and hide content div (while window is being dragged)
            t.contentarea.style.visibility = "hidden"
        }
        document.onmousemove = d.getdistance //get distance travelled by mouse as it moves
        document.onmouseup = function()
        {
            if (t.contentarea.datatype == "iframe")
            { //restore color and visibility of content div onmouseup
                t.contentarea.style.backgroundColor = "white"
                t.contentarea.style.visibility = "visible"
            }
            d.stop()
        }
        return false
    },

    getdistance: function(e)
    {
        var d = dhtmlwindow
        var etarget = d.etarget
        var e = window.event || e
        d.distancex = e.clientX - d.initmousex //horizontal distance travelled relative to starting point
        d.distancey = e.clientY - d.initmousey
        if (etarget.className == "drag-handle") //if target element is "handle" div
            d.move(etarget._parent, e)
        else if (etarget.className == "drag-resizearea") //if target element is "resize" div
            d.resize(etarget._parent, e)
        return false //cancel default dragging behavior
    },

    getviewpoint: function()
    { //get window viewpoint numbers
        var ie = document.all && !window.opera
        var domclientWidth = document.documentElement && parseInt(document.documentElement.clientWidth) || 100000 //Preliminary doc width in non IE browsers
        this.standardbody = (document.compatMode == "CSS1Compat") ? document.documentElement : document.body //create reference to common "body" across doctypes
        this.scroll_top = (ie) ? this.standardbody.scrollTop : window.pageYOffset
        this.scroll_left = (ie) ? this.standardbody.scrollLeft : window.pageXOffset
        this.docwidth = (ie) ? this.standardbody.clientWidth : (/Safari/i.test(navigator.userAgent)) ? window.innerWidth : Math.min(domclientWidth, window.innerWidth - 16)
        this.docheight = (ie) ? this.standardbody.clientHeight : window.innerHeight
    },

    rememberattrs: function(t)
    { //remember certain attributes of the window when it's minimized or closed, such as dimensions, position on page
        this.getviewpoint() //Get current window viewpoint numbers
        t.lastx = parseInt((t.style.left || t.offsetLeft)) - dhtmlwindow.scroll_left //store last known x coord of window just before minimizing
        t.lasty = parseInt((t.style.top || t.offsetTop)) - dhtmlwindow.scroll_top
        t.lastwidth = parseInt(t.style.width) //store last known width of window just before minimizing/ closing
    },

    move: function(t, e)
    {
        t.style.left = dhtmlwindow.distancex + dhtmlwindow.initx + "px"
        t.style.top = dhtmlwindow.distancey + dhtmlwindow.inity + "px"
    },

    resize: function(t, e)
    {
        t.style.width = Math.max(dhtmlwindow.width + dhtmlwindow.distancex, 150) + "px"
        t.contentarea.style.height = Math.max(dhtmlwindow.contentheight + dhtmlwindow.distancey, 100) + "px"
    },

    enablecontrols: function(e)
    {
        var d = dhtmlwindow
        var sourceobj = window.event ? window.event.srcElement : e.target //Get element within "handle" div mouse is currently on (the controls)
        if (/Minimize/i.test(sourceobj.getAttribute("title"))) //if this is the "minimize" control
            d.minimize(sourceobj, this._parent)
        else if (/Restore/i.test(sourceobj.getAttribute("title"))) //if this is the "restore" control
            d.restore(sourceobj, this._parent)
        else if (/Close/i.test(sourceobj.getAttribute("title"))) //if this is the "close" control
            d.close(this._parent)
        return false
    },

    minimize: function(button, t)
    {
        dhtmlwindow.rememberattrs(t)
        button.setAttribute("src", dhtmlwindow.imagefiles[2])
        button.setAttribute("title", "Restore")
        t.state = "minimized" //indicate the state of the window as being "minimized"
        t.contentarea.style.display = "none"
        t.statusarea.style.display = "none"
        if (typeof t.minimizeorder == "undefined")
        { //stack order of minmized window on screen relative to any other minimized windows
            dhtmlwindow.minimizeorder++ //increment order
            t.minimizeorder = dhtmlwindow.minimizeorder
        }
        t.style.left = "10px" //left coord of minmized window
        t.style.width = "200px"
        var windowspacing = t.minimizeorder * 10 //spacing (gap) between each minmized window(s)
        t.style.top = dhtmlwindow.scroll_top + dhtmlwindow.docheight - (t.handle.offsetHeight * t.minimizeorder) - windowspacing + "px"
    },

    restore: function(button, t)
    {
        dhtmlwindow.getviewpoint()
        button.setAttribute("src", dhtmlwindow.imagefiles[0])
        button.setAttribute("title", "Minimize")
        t.state = "fullview" //indicate the state of the window as being "fullview"
        t.style.display = "block"
        t.contentarea.style.display = "block"
        if (t.resizeBool) //if this window is resizable, enable the resize icon
            t.statusarea.style.display = "block"
        t.style.left = parseInt(t.lastx) + dhtmlwindow.scroll_left + "px" //position window to last known x coord just before minimizing
        t.style.top = parseInt(t.lasty) + dhtmlwindow.scroll_top + "px"
        t.style.width = parseInt(t.lastwidth) + "px"
    },


    close: function(t)
    {
        if (this.closeFunction)
        {
            this.closeFunction();
        }

        try
        {
            var closewinbol = t.onclose()
        }
        catch (err)
        { //In non IE browsers, all errors are caught, so just run the below
            var closewinbol = true
        }
        finally
        { //In IE, not all errors are caught, so check if variable isn't defined in IE in those cases
            if (typeof closewinbol == "undefined")
            {
                alert("An error has occured somwhere inside your \"onclose\" event handler")
                var closewinbol = true
            }
        }
        if (closewinbol)
        { //if custom event handler function returns true
            if (t.state != "minimized") //if this window isn't currently minimized
                dhtmlwindow.rememberattrs(t) //remember window's dimensions/position on the page before closing
            if (window.frames["_iframe-" + t.id]) //if this is an IFRAME DHTML window
                window.frames["_iframe-" + t.id].location.replace("about:blank")
            else
                t.contentarea.innerHTML = ""
            t.style.display = "none"
            t.isClosed = true //tell script this window is closed (for detection in t.show())
        }
        return closewinbol
    },


    setopacity: function(targetobject, value)
    { //Sets the opacity of targetobject based on the passed in value setting (0 to 1 and in between)
        if (!targetobject)
            return
        if (targetobject.filters && targetobject.filters[0])
        { //IE syntax
            if (typeof targetobject.filters[0].opacity == "number") //IE6
                targetobject.filters[0].opacity = value * 100
            else //IE 5.5
                targetobject.style.filter = "alpha(opacity=" + value * 100 + ")"
        }
        else if (typeof targetobject.style.MozOpacity != "undefined") //Old Mozilla syntax
            targetobject.style.MozOpacity = value
        else if (typeof targetobject.style.opacity != "undefined") //Standard opacity syntax
            targetobject.style.opacity = value
    },

    setfocus: function(t)
    { //Sets focus to the currently active window
        this.zIndexvalue++
        t.style.zIndex = this.zIndexvalue
        t.isClosed = false //tell script this window isn't closed (for detection in t.show())
        this.setopacity(this.lastactivet.handle, 0.5) //unfocus last active window
        this.setopacity(t.handle, 1) //focus currently active window
        this.lastactivet = t //remember last active window
    },


    show: function(t)
    {
        if (t.isClosed)
        {
            alert("DHTML Window has been closed, so nothing to show. Open/Create the window again.")
            return
        }
        if (t.lastx) //If there exists previously stored information such as last x position on window attributes (meaning it's been minimized or closed)
            dhtmlwindow.restore(t.controls.firstChild, t) //restore the window using that info
        else
            t.style.display = "block"
        this.setfocus(t)
        t.state = "fullview" //indicate the state of the window as being "fullview"
    },

    hide: function(t)
    {
        t.style.display = "none"
    },

    ajax_connect: function(url, t)
    {
        var page_request = false
        var bustcacheparameter = ""
        if (window.XMLHttpRequest) // if Mozilla, IE7, Safari etc
            page_request = new XMLHttpRequest()
        else if (window.ActiveXObject)
        { // if IE6 or below
            try
            {
                page_request = new ActiveXObject("Msxml2.XMLHTTP")
            }
            catch (e)
            {
                try
                {
                    page_request = new ActiveXObject("Microsoft.XMLHTTP")
                }
                catch (e) { }
            }
        }
        else
            return false
        t.contentarea.innerHTML = this.ajaxloadinghtml
        page_request.onreadystatechange = function() { dhtmlwindow.ajax_loadpage(page_request, t) }
        if (this.ajaxbustcache) //if bust caching of external page
            bustcacheparameter = (url.indexOf("?") != -1) ? "&" + new Date().getTime() : "?" + new Date().getTime()
        page_request.open('GET', url + bustcacheparameter, true)
        page_request.send(null)
    },

    ajax_loadpage: function(page_request, t)
    {
        if (page_request.readyState == 4 && (page_request.status == 200 || window.location.href.indexOf("http") == -1))
        {
            t.contentarea.innerHTML = page_request.responseText
        }
    },


    stop: function()
    {
        dhtmlwindow.etarget = null //clean up
        document.onmousemove = null
        document.onmouseup = null
    },

    addEvent: function(target, functionref, tasktype)
    {
        //assign a function to execute to an event handler (ie: onunload)
        var tasktype = (window.addEventListener) ? tasktype : "on" + tasktype
        if (target.addEventListener)
            target.addEventListener(tasktype, functionref, false)
        else if (target.attachEvent)
            target.attachEvent(tasktype, functionref)
    },

    cleanup: function()
    {
        for (var i = 0; i < dhtmlwindow.tobjects.length; i++)
        {
            dhtmlwindow.tobjects[i].handle._parent = dhtmlwindow.tobjects[i].resizearea._parent = dhtmlwindow.tobjects[i].controls._parent = null
        }
        window.onload = null
    }

} //End dhtmlwindow object

document.write('<div id="dhtmlwindowholder"><span style="display:none">.</span></div>') //container that holds all dhtml window divs on page
window.onunload=dhtmlwindow.cleanup
/*	SWFObject v2.0 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}();/*
 * jQuery 1.2.3 - New Wave Javascript
 *
 * Copyright (c) 2008 John Resig (jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
 * $Rev: 4663 $
 */
(function(){if(window.jQuery)var _jQuery=window.jQuery;var jQuery=window.jQuery=function(selector,context){return new jQuery.prototype.init(selector,context);};if(window.$)var _$=window.$;window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;var isSimple=/^.[^:#\[\.]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}else if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem)if(elem.id!=match[3])return jQuery().find(selector);else{this[0]=elem;this.length=1;return this;}else
selector=[];}}else
return new jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector]);},jquery:"1.2.3",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;this.each(function(i){if(this==elem)ret=i;});return ret;},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value==undefined)return this.length&&jQuery[type||"attr"](this[0],name)||undefined;else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return!selector?this:this.pushStack(jQuery.merge(this.get(),selector.constructor==String?jQuery(selector).get():selector.length!=undefined&&(!selector.nodeName||jQuery.nodeName(selector,"form"))?selector:[selector]));},is:function(selector){return selector?jQuery.multiFilter(selector,this).length>0:false;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
return(this[0].value||"").replace(/\r/g,"");}return undefined;}return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=value.constructor==Array?value:[value];jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
this.value=value;});},html:function(value){return value==undefined?(this.length?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value==null){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data==undefined&&this.length)data=jQuery.data(this[0],key);return data==null&&parts[1]?this.data(parts[0]):data;}else
return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem);}else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.prototype.init.prototype=jQuery.prototype;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==1){target=this;i=0;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){if(target===options[name])continue;if(deep&&options[name]&&typeof options[name]=="object"&&target[name]&&!options[name].nodeType)target[name]=jQuery.extend(target[name],options[name]);else if(options[name]!=undefined)target[name]=options[name];}return target;};var expando="jQuery"+(new Date()).getTime(),uuid=0,windowData={};var exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i;jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/function/i.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
script.appendChild(document.createTextNode(data));head.appendChild(script);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!=undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){if(args){if(object.length==undefined){for(var name in object)if(callback.apply(object[name],args)===false)break;}else
for(var i=0,length=object.length;i<length;i++)if(callback.apply(object[i],args)===false)break;}else{if(object.length==undefined){for(var name in object)if(callback.call(object[name],name,object[name])===false)break;}else
for(var i=0,length=object.length,value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret;function color(elem){if(!jQuery.browser.safari)return false;var ret=document.defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=elem.style.outline;elem.style.outline="0 solid black";elem.style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&elem.style&&elem.style[name])ret=elem.style[name];else if(document.defaultView&&document.defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var getComputedStyle=document.defaultView.getComputedStyle(elem,null);if(getComputedStyle&&!color(elem))ret=getComputedStyle.getPropertyValue(name);else{var swap=[],stack=[];for(var a=elem;a&&color(a);a=a.parentNode)stack.unshift(a);for(var i=0;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(getComputedStyle&&getComputedStyle.getPropertyValue(name))||"";for(var i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var style=elem.style.left,runtimeStyle=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;elem.style.left=ret||0;ret=elem.style.pixelLeft+"px";elem.style.left=style;elem.runtimeStyle.left=runtimeStyle;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem=elem.toString();if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(fix[name]){if(value!=undefined)elem[fix[name]]=value;return elem[fix[name]];}else if(jQuery.browser.msie&&name=="style")return jQuery.attr(elem.style,"cssText",value);else if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method"))return elem.getAttributeNode(name).nodeValue;else if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem.setAttribute(name,""+value);}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem))return elem.getAttribute(name,2);return elem.getAttribute(name);}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(value!=undefined)elem[name]=value;return elem[name];}},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(typeof array!="array")for(var i=0,length=array.length;i<length;i++)ret.push(array[i]);else
ret=array.slice(0);return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]==elem)return i;return-1;},merge:function(first,second){if(jQuery.browser.msie){for(var i=0;second[i];i++)if(second[i].nodeType!=8)first.push(second[i]);}else
for(var i=0;second[i];i++)first.push(second[i]);return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv&&callback(elems[i],i)||inv&&!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!==null&&value!=undefined){if(value.constructor!=Array)value=[value];ret=ret.concat(value);}}return ret;}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,innerHTML:"innerHTML",className:"className",value:"value",disabled:"disabled",checked:"checked",readonly:"readOnly",selected:"selected",maxlength:"maxLength",selectedIndex:"selectedIndex",defaultValue:"defaultValue",tagName:"tagName",nodeName:"nodeName"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[];var cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&(!elem||n!=elem))r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval!=undefined)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=function(){return fn.apply(this,arguments);};handler.data=data;handler.guid=fn.guid;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){var val;if(typeof jQuery=="undefined"||jQuery.event.triggered)return val;val=jQuery.event.handle.apply(arguments.callee.elem,arguments);return val;});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data||[]);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event)data.unshift(this.fix({type:type,target:elem}));data[0].type=type;if(exclusive)data[0].exclusive=true;if(jQuery.isFunction(jQuery.data(elem,"handle")))val=jQuery.data(elem,"handle").apply(elem,data);if(!fn&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val;event=jQuery.event.fix(event||window.event||{});var parts=event.type.split(".");event.type=parts[0];var handlers=jQuery.data(this,"events")&&jQuery.data(this,"events")[event.type],args=Array.prototype.slice.call(arguments,1);args.unshift(event);for(var j in handlers){var handler=handlers[j];args[0].handler=handler;args[0].data=handler.data;if(!parts[1]&&!event.exclusive||handler.type==parts[1]){var ret=handler.apply(this,args);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}if(jQuery.browser.msie)event.target=event.preventDefault=event.stopPropagation=event.handler=event.data=null;return val;},fix:function(event){var originalEvent=event;event=jQuery.extend({},originalEvent);event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=originalEvent.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){return this.each(function(){jQuery.event.add(this,type,function(event){jQuery(this).unbind(event);return(fn||data).apply(this,arguments);},fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){if(this[0])return jQuery.event.trigger(type,data,this[0],false,fn);return undefined;},toggle:function(){var args=arguments;return this.click(function(event){this.lastToggle=0==this.lastToggle?1:0;event.preventDefault();return args[this.lastToggle].apply(this,arguments)||false;});},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.apply(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({load:function(url,params,callback){if(jQuery.isFunction(url))return this.bind("load",url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=(new Date).getTime();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){var jsonp,jsre=/=\?(&|$)/g,status,data;s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(s.type.toLowerCase()=="get"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&s.type.toLowerCase()=="get"){var ts=(new Date()).getTime();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&s.type.toLowerCase()=="get"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");if((!s.url.indexOf("http")||!s.url.indexOf("//"))&&s.dataType=="script"&&s.type.toLowerCase()=="get"){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xml=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();xml.open(s.type,s.url,s.async,s.username,s.password);try{if(s.data)xml.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xml.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xml.setRequestHeader("X-Requested-With","XMLHttpRequest");xml.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend)s.beforeSend(xml);if(s.global)jQuery.event.trigger("ajaxSend",[xml,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xml&&(xml.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xml)&&"error"||s.ifModified&&jQuery.httpNotModified(xml,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xml,s.dataType);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xml.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
jQuery.handleError(s,xml,status);complete();if(s.async)xml=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xml){xml.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xml.send(s.data);}catch(e){jQuery.handleError(s,xml,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xml,s]);}function complete(){if(s.complete)s.complete(xml,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xml,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xml;},handleError:function(s,xml,status,e){if(s.error)s.error(xml,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xml,s,e]);},active:0,httpSuccess:function(r){try{return!r.status&&location.protocol=="file:"||(r.status>=200&&r.status<300)||r.status==304||r.status==1223||jQuery.browser.safari&&r.status==undefined;}catch(e){}return false;},httpNotModified:function(xml,url){try{var xmlRes=xml.getResponseHeader("Last-Modified");return xml.status==304||xmlRes==jQuery.lastModified[url]||jQuery.browser.safari&&xml.status==undefined;}catch(e){}return false;},httpData:function(r,type){var ct=r.getResponseHeader("content-type");var xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0;var data=xml?r.responseXML:r.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
s.push(encodeURIComponent(j)+"="+encodeURIComponent(a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle(fn,fn2):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall);var hidden=jQuery(this).is(":hidden"),self=this;for(var p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return jQuery.isFunction(opt.complete)&&opt.complete.apply(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.apply(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(!elem)return undefined;type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",array?jQuery.makeArray(array):[]);return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].apply(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:{slow:600,fast:200}[opt.duration])||400;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.apply(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.apply(this.elem,[this.now,this]);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=(new Date()).getTime();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=(new Date()).getTime();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done&&jQuery.isFunction(this.options.complete))this.options.complete.apply(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.fx.step={scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}};jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),fixed=jQuery.css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&jQuery.css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(jQuery.css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&jQuery.css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||jQuery.css(offsetChild,"position")=="absolute"))||(mozilla&&jQuery.css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l)||0;top+=parseInt(t)||0;}return results;};})();/* Returns the week number for this date. dowOffset is the day of week the week
* "starts" on for your locale - it can be from 0 to 6. If dowOffset is 1 (Monday),
* the week returned is the ISO 8601 week number.
* getWeek() was developed by Nick Baicoianu at MeanFreePath: http://www.meanfreepath.com
* @param int dowOffset
* @return int
*/
Date.prototype.getWeek = function()
{
    //set dayOfWeekOffset based on user preference (0 = Sunday, 1=Monday) 
    var dowOffset = typeof (ExpViewGlobalData.userWeekStart) == 'int' ? ExpViewGlobalData.userWeekStart : 0;
    var newYear = new Date(this.getFullYear(), 0, 1);
    var day = newYear.getDay() - dowOffset; //the day of week the year begins on
    day = (day >= 0 ? day : day + 7);
    var daynum = Math.floor((this.getTime() - newYear.getTime() -
(this.getTimezoneOffset() - newYear.getTimezoneOffset()) * 60000) / 86400000) + 1;
    var weeknum;
    //if the year starts before the middle of a week
    if (day < 4)
    {
        weeknum = Math.floor((daynum + day - 1) / 7) + 1;
        if (weeknum > 52)
        {
            nYear = new Date(this.getFullYear() + 1, 0, 1);
            nday = nYear.getDay() - dowOffset;
            nday = nday >= 0 ? nday : nday + 7;
            /*if the next year starts before the middle of
            the week, it is week #1 of that year*/
            weeknum = nday < 4 ? 1 : 53;
        }
    }
    else
    {
        weeknum = Math.floor((daynum + day - 1) / 7);
    }
    return weeknum;
};


Date.prototype.getPriorWeek = function()
{
    var priorWeekNum = this.getWeek() - 1;

    if (priorWeekNum <= 0)
    {
        var today = new Date();
        var year = today.getFullYear() - 1;

        var prevNewYear = new Date(year, 0, 1);
        var prevOffset = 7 + 1 - prevNewYear.getDay();

        if (prevOffset == 2 || prevOffset == 8)
        {
            priorWeekNum = 53;
        }
        else
        {
            priorWeekNum = 52;
        }
    }

    return priorWeekNum;
}

Date.prototype.getPriorMonth = function()
{
    if (this.getMonth() === 0)
    {
        return 11;
    }
    else
    {
        return this.getMonth() - 1;
    }
}

function getDateFromDefaultDateString(dateString)
{
    //Make sure parameter is converted to string value
    dateString = dateString + "";

    //format == YYYY-MM- DD
    var dateArray = dateString.split("-");
    var yearValue = dateArray[0];
    var monthValue = dateArray[1];
    var dateValue = dateArray[2];

    //Month should be from 0-11, Convert from string of 1-12 when creating date object
    var date = new Date(yearValue, monthValue - 1, dateValue);

    return date;
}

//Converts the Formatted Date String value passed in to the default 
//date string format of YYYY-MM-DD
function getDateStringFromFormattedDateString(dateString)
{
    var date = getDateFromFormattedDateString(dateString);

    //format == YYYY-MM-DD
    if (date)
    {
        return "" + date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
    }
    else
    {
        return null;
    }
}

function getDateFromFormattedDateString(dateString)
{
    //Make sure parameter is converted to string value
    dateString = dateString + "";

    if (isValidFormattedDate(dateString))
    {
        //variables to store data attributes
        var yearValue;
        var monthValue;
        var dateValue;

        if (ExpViewGlobalData.userDateFormat == 1)
        {
            //format == YYYY-MM- DD
            var dateArray = dateString.split("-");
            yearValue = dateArray[0];
            monthValue = dateArray[1];
            dateValue = dateArray[2];
        }
        else if (ExpViewGlobalData.userDateFormat == 2)
        {
            //format == MM/DD/YYYY
            var dateArray = dateString.split("/");
            yearValue = dateArray[2];
            monthValue = dateArray[0];
            dateValue = dateArray[1];
        }
        else if (ExpViewGlobalData.userDateFormat == 3)
        {
            //format == DD/MM/YYYY
            var dateArray = dateString.split("/");
            yearValue = dateArray[2];
            monthValue = dateArray[1];
            dateValue = dateArray[0];
        }

        //Month should be from 0-11, Convert from string of 1-12 when creating date object
        var date = new Date(yearValue, monthValue - 1, dateValue);

        return date;
    }
    else
    {
        return null;
    }
}

//Returns a date string formatted according to the user's preferred format
//The method converts the dateString inputted from the standard format of YYYY-MM-DD
//to the user's preferred format.
function getFormattedDateString(dateString)
{
    //variables to store date attributes
    var date;

    //format = YYYY-MM- DD
    if (dateString)
    {
        dateString = dateString + "";    
        var dateArray = dateString.split("-");        
        date = new Date(dateArray[0], (dateArray[1] - 1), dateArray[2]);
    }
    else
    {
        //No in dateString specified, Default to today's date
        date = new Date();
    }

    //Append 0 if month or dayDate value is only one character
    var month = (date.getMonth() + 1) + "";
    if (month.length === 1)
    {
        month = "0" + month;
    }

    var dayDate = date.getDate() + "";
    if (dayDate.length === 1)
    {
        dayDate = "0" + dayDate;
    }
            
    //userDateFormat is set globally app initiation method
    if (ExpViewGlobalData.userDateFormat == 1)
    {
        //format == YYYY-MM-DD
        return "" + date.getFullYear() + "-" + month + "-" + dayDate;
    }
    else if (ExpViewGlobalData.userDateFormat == 2)
    {
        //format == MM/DD/YYYY
        return "" + month + "/" + dayDate + "/" + date.getFullYear();
    }
    else if (ExpViewGlobalData.userDateFormat == 3)
    {
        //format == DD/MM/YYYY
        return "" + dayDate + "/" + month + "/" + date.getFullYear();    
    }
}


function isValidFormattedDate(dateString)
{
    //Ensure that dateString is treated as a string
    dateString = dateString + "";
    
    //variables to store data attributes
    var yearValue;
    var monthValue;
    var dateValue;
    var dateRegExp;

    if (ExpViewGlobalData.userDateFormat == 1)
    {
        //format == YYYY-MM- DD
        dateRegExp = /^\d{4}(\-)\d{1,2}\1\d{1,2}$/;

        var dateArray = dateString.split("-");
        yearValue = dateArray[0];
        monthValue = dateArray[1];
        dateValue = dateArray[2];
    }
    else if (ExpViewGlobalData.userDateFormat == 2)
    {
        //format == MM/DD/YYYY
        dateRegExp = /^\d{1,2}(\/)\d{1,2}\1\d{4}$/

        var dateArray = dateString.split("/");
        yearValue = dateArray[2];
        monthValue = dateArray[0];
        dateValue = dateArray[1];
    }
    else if (ExpViewGlobalData.userDateFormat == 3)
    {
        //format == DD/MM/YYYY
        dateRegExp = /^\d{1,2}(\/)\d{1,2}\1\d{4}$/

        var dateArray = dateString.split("/");
        yearValue = dateArray[2];
        monthValue = dateArray[1];
        dateValue = dateArray[0];
    }
    
    //First check to see if format is correct
    if (!dateRegExp.test(dateString))
    {
        return false;
    }
    else
    {
        //Then check to see if the values specified fall into the right ranges
        var ALTERdDate = new Date(yearValue, monthValue - 1, dateValue);

        if ((ALTERdDate.getMonth() != monthValue-1) || (ALTERdDate.getDate() != dateValue) || (ALTERdDate.getFullYear() != yearValue))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}
function S4() 
{
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}

function createGuid() 
{
   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
function CategoryData(categoryArray)
{    
    var catHashtable;
    var subCatHashtable;
    
    var totalYearBudget;
    var totalMonthBudget;
    var totalWeekBudget;
    
    var totalVal;
    var totalYearVal;
    var totalPriorMonthVal;
    var totalMonthVal;
    var totalPriorWeekVal;
    var totalWeekVal;
    var totalCustomVal;

    var customStartDate;
    var customEndDate;
    var customDataLoaded = false;
    
    var catMonthAmountTable;
    var catMonthAmounts;
 
    calculateTotalBudgets();
       
    createHashtable();

    //Private Functions
    function createHashtable()
    {   
        catHashtable = new Object();
        subCatHashtable = new Object();
        
        var numCategories = categoryArray.length;
                
        for(var i=0; i<numCategories; i++)
        {
            var category = categoryArray[i];
            catHashtable[category.CategoryID] = category;
            
            if(category.SubCategories)
            {
                var numSubCategories = category.SubCategories.length;
                for (var j=0; j<numSubCategories; j++)
                {
                    var subCategory = category.SubCategories[j];
                    subCatHashtable[subCategory.SubCategoryID] = subCategory;
                }
            }
        }        
    }
    
    function getCategoryArrayIndex(categoryID)
    {
        var numCategories = categoryArray.length;
        
        for(var i=0; i<numCategories; i++)
        {
            if(categoryArray[i].CategoryID == categoryID)
            {
                return i;
            }
        }    
    }
    
    function calculateTotalBudgets()
    {
        if(categoryArray)
        {
            var numCategories = categoryArray.length;
            totalVal = 0;
            totalYearVal = 0;
            totalPriorMonthVal = 0;
            totalMonthVal = 0;
            totalPriorWeekVal = 0;
            totalWeekVal = 0;
            
            for(var i=0; i<numCategories; i++)
            {   
                totalVal += (categoryArray[i].TotalAmount  * 1);         
                totalYearVal += (categoryArray[i].YearAmount  * 1);
                totalPriorMonthVal += (categoryArray[i].PriorMonthAmount * 1);
                totalMonthVal += (categoryArray[i].MonthAmount * 1);
                totalPriorWeekVal += (categoryArray[i].PriorWeekAmount * 1);
                totalWeekVal += (categoryArray[i].WeekAmount * 1);     
                
                if(categoryArray[i].YearBudget)
                {   
                    if(!totalYearBudget)
                    {
                        totalYearBudget = 0;
                    }         
                    
                    totalYearBudget += (parseFloat(categoryArray[i].YearBudget));
                }
                
                if(categoryArray[i].MonthBudget)
                {
                    if(!totalMonthBudget)
                    {
                        totalMonthBudget = 0;
                    }         
                                
                    totalMonthBudget += (parseFloat(categoryArray[i].MonthBudget));
                }
                
                if(categoryArray[i].WeekBudget)
                {
                    if(!totalWeekBudget)
                    {
                        totalWeekBudget = 0;
                    }         
                                
                    totalWeekBudget += (parseFloat(categoryArray[i].WeekBudget));      
                }  
            }
        }        
    }    
    
    function sortCategoryArray() 
    {
        var numCategories = categoryArray.length;

        for (var i=0; i<(numCategories-1); i++)
        {
            for (var j=i+1; j<numCategories; j++)
            {

                if (categoryArray[j].Name.toUpperCase() < categoryArray[i].Name.toUpperCase()) 
                {
                    var dummyCategory = categoryArray[i];
                    categoryArray[i] = categoryArray[j];
                    categoryArray[j] = dummyCategory;
                }
            }
        }        
    }

    function addToTotalBudgets(yearBudget, monthBudget, weekBudget)
    {
        if(yearBudget)
        {        
            totalYearBudget += yearBudget*1;
        }
        if(monthBudget)
        {
            totalMonthBudget += monthBudget*1;        
        }
        if(weekBudget)
        {
            totalWeekBudget += weekBudget*1;        
        }    
    }

    function deleteFromTotalBudgets(yearBudget, monthBudget, weekBudget)
    {   
        if(yearBudget)
        {        
            totalYearBudget -= yearBudget*1;
        }
        if(monthBudget)
        {
            totalMonthBudget -= monthBudget*1;        
        }
        if(weekBudget)
        {
            totalWeekBudget -= weekBudget*1;        
        }    
    }

    function deleteFromTotalAmount(deletedCat)
    {
        if(deletedCat.YearAmount )
        {        
            totalYearVal -= deletedCat.YearAmount *1;
        }
        
        if(deletedCat.PriorMonthAmount)
        {
            totalPriorMonthVal -= deletedCat.PriorMonthAmount*1;        
        }

        if(deletedCat.MonthAmount)
        {
            totalMonthVal -= deletedCat.MonthAmount*1;        
        }
        
        if(deletedCat.PriorWeekAmount)
        {
            totalPriorWeekVal -= deletedCat.PriorWeekAmount*1;        
        }    

        if(deletedCat.WeekAmount)
        {
            totalWeekVal -= deletedCat.WeekAmount*1;        
        }    
    }
    
    
    function y2k(number) 
    { 
        return (number < 1000) ? number + 1900 : number; 
    }

    function getWeek(year, month, day) 
    {
        var when = new Date(year, month, day);
        var newYear = new Date(year,0,1);
        var offset = 7 + 1 - newYear.getDay();
        if (offset === 8) 
        {
            offset = 1;
        }
        
        var daynum = ((Date.UTC(y2k(year),when.getMonth(),when.getDate(  ),0,0,0) - Date.UTC(y2k(year),0,1,0,0,0)) /1000/60/60/24) + 1;
        var weeknum = Math.floor((daynum-offset+7)/7);
        if (weeknum === 0) 
        {
            year--;
            var prevNewYear = new Date(year,0,1);
            var prevOffset = 7 + 1 - prevNewYear.getDay();
            if (prevOffset == 2 || prevOffset == 8) 
            {
                weeknum = 53;
            }
            else 
            {
                weeknum = 52;
            }
        }
        return weeknum;
    }
    
    function addDeleteTrans(categoryID, amountString, dateString, operationType, subCategoryID)
    {        
        var transModifier;
        if(operationType == "Add")
        {
            transModifier = 1;
        }
        else if(operationType == "Delete")
        {
            transModifier = -1;
        }
            
        var amount = amountString * transModifier;
 
        //Identify the category to add the transaction to
        var category = catHashtable[categoryID];
        var subCategory = null;
              
        if(subCategoryID)
        {
            var numSubCategories = category.SubCategories.length;
            for(var subCatIndex=0; subCatIndex<numSubCategories; subCatIndex++)
            {
                if(category.SubCategories[subCatIndex].SubCategoryID == subCategoryID)
                {
                    subCategory = category.SubCategories[subCatIndex];                  
                }
            }
        }
        
        
        //Add or subtract amount from total amount values
        category.TotalAmount = roundAmount((category.TotalAmount  * 1) + amount);
        totalVal += amount;

        var transDate = getDateFromDefaultDateString(dateString);

        //ALTER a date represting current date
        var today = new Date();

        if(customStartDate && customEndDate)
        {
            if ((transDate >= customStartDate) && (transDate <= customEndDate))
            {
                category.CustomDateAmount = roundAmount((category.CustomDateAmount * 1) + amount);            
                totalCustomVal += amount;   
            }
        }
        
        if(transDate.getFullYear() == today.getFullYear())
        {        
            category.YearAmount = roundAmount((category.YearAmount * 1) + amount);            
            if(subCategory)
            {
                subCategory.YearAmount = roundAmount((subCategory.YearAmount * 1) + amount); 
            }
            
            totalYearVal += amount;

            //If Transaction ocurred in the prior month, add to the PriorMonthAmount total
            if(transDate.getMonth() == today.getPriorMonth())
            {
                category.PriorMonthAmount = roundAmount((category.PriorMonthAmount * 1) + amount);
                
                if(subCategory)
                {
                    subCategory.PriorMonthAmount = roundAmount((subCategory.PriorMonthAmount * 1) + amount); 
                }

                totalPriorMonthVal += amount;

                
                //If Transaction ocurred in the prior week, add to the .priorWeekAmount total
                //Otherwise, if it ocurred this week add it to the .weekAmount total.		        
	            if(transDate.getWeek() == today.getPriorWeek())
	            {	
                    category.PriorWeekAmount = roundAmount((category.PriorWeekAmount * 1) + amount);

                    if(subCategory)
                    {
                        subCategory.PriorWeekAmount = roundAmount((subCategory.PriorWeekAmount * 1) + amount); 
                    }
                    
                    totalPriorWeekVal += amount;
                }
	            else if(transDate.getWeek() == today.getWeek())
	            {
                    category.WeekAmount = roundAmount((category.WeekAmount * 1) + amount);

                    if(subCategory)
                    {
                        subCategory.WeekAmount = roundAmount((subCategory.WeekAmount * 1) + amount); 
                    }
                    
                    totalWeekVal += amount;                                      
	            }
	        }
            else if(transDate.getMonth() == today.getMonth())
            {                
                //If Transaction ocurred in this month , add to the MonthAmount total
                category.MonthAmount = roundAmount((category.MonthAmount * 1) + amount);
                
                if(subCategory)
                {
                    subCategory.MonthAmount = roundAmount((subCategory.MonthAmount * 1) + amount); 
                }

                totalMonthVal += amount;                                      

                //If Transaction ocurred in the prior week, add to the .priorWeekAmount total
                //Otherwise, if it ocurred this week add it to the .weekAmount total.		        
	            if(transDate.getWeek() == today.getPriorWeek())
	            {	
                    category.PriorWeekAmount = roundAmount((category.PriorWeekAmount * 1) + amount);
                    
                    if(subCategory)
                    {
                        subCategory.PriorWeekAmount = roundAmount((subCategory.PriorWeekAmount * 1) + amount); 
                    }

                    totalPriorWeekVal += amount;
                }
	            else if(transDate.getWeek() == today.getWeek())
	            {
                    category.WeekAmount = roundAmount((category.WeekAmount * 1) + amount);
                    
                    if(subCategory)
                    {
                        subCategory.WeekAmount = roundAmount((subCategory.WeekAmount * 1) + amount); 
                    }

                    totalWeekVal += amount;                                      
                }
            }
        }
        else if(transDate.getFullYear() == (today.getFullYear() - 1))
        {
            //If Transaction ocurred in the prior month, add to the PriorMonthAmount total
            if(transDate.getMonth() == today.getPriorMonth())
            {
                category.PriorMonthAmount = roundAmount((category.PriorMonthAmount * 1) + amount);

                if(subCategory)
                {
                    subCategory.PriorMonthAmount = roundAmount((subCategory.PriorMonthAmount * 1) + amount); 
                }

                totalPriorMonthVal += amount;

                //If Transaction ocurred in the prior week, add to the .priorWeekAmount total
                //Otherwise, if it ocurred this week add it to the .weekAmount total.		        
	            if(transDate.getWeek() == today.getPriorWeek())
	            {	
                    category.PriorWeekAmount = roundAmount((category.PriorWeekAmount * 1) + amount);

                    if(subCategory)
                    {
                        subCategory.PriorWeekAmount = roundAmount((subCategory.PriorWeekAmount * 1) + amount); 
                    }

                    totalPriorWeekVal += amount;                                                          
	            }
	        }        
        }     
    }
    
    this.setCategoryMonthAmount = function(catMonthAmountArray)
    {
        catMonthAmounts = catMonthAmountArray;
        catMonthAmountTable = new Object();
        
        var numMonths = catMonthAmountArray.length;

        for(var i=0; i<numMonths; i++)
        {
            var monthAmountKey = catMonthAmountArray[i].year + "" + catMonthAmountArray[i].month;
            catHashtable[monthAmountKey] = catMonthAmountArray[i];
        }        

    };
    
    this.getCategoryMonthAmount = function()
    {
        return catMonthAmounts;
    };
    
    this.setCustomDate = function(startDateString, endDateString)
    {
        var dateArray = startDateString.split("-");
        customStartDate = new Date(dateArray[0]*1, ((dateArray[1]*1)-1), dateArray[2]*1);
        
        dateArray = endDateString.split("-");
        customEndDate = new Date(dateArray[0], ((dateArray[1]*1)-1), dateArray[2]);
    };
    
    this.setCustomDateAmount = function(custDateArray)
    {        
        totalCustomVal = 0;
        
        var numCustom = custDateArray.length;        
        for(custIndex=0; custIndex<numCustom; custIndex++)
        {
            var custCategory = custDateArray[custIndex];            
            
            catHashtable[custCategory.categoryID].CustomDateAmount = custCategory.CustomDateAmount;
            
            if(custCategory.CustomDateAmount)
            {
                totalCustomVal += (custCategory.CustomDateAmount * 1);             
            }
        }
        
        customDataLoaded = true;
    };
    
    this.isCustomDataLoaded = function()
    {
        return customDataLoaded;
    };

    this.getCustomStartDate = function()
    {
        return customStartDate;
    };

    this.getCustomEndDate = function()
    {
        return customEndDate;
    };
    
    this.getCategoryName = function(catID)
    {
        if(catHashtable[catID])
        {
            return catHashtable[catID].Name;
        }            
    };

    
    this.getTotalYearBudget = function()
    {
        return roundAmount(totalYearBudget);
    };

    this.getTotalMonthBudget = function()
    {
        return roundAmount(totalMonthBudget);
    };

    this.getTotalWeekBudget = function()
    {
        return roundAmount(totalWeekBudget);
    };
    
    this.getTotalCustomDateAmount = function()
    {
        return totalCustomVal;
    };

    this.getTotalAllTimeAmount = function()
    {
        return roundAmount(totalVal);
    };

    this.getTotalYearAmount = function()
    {
        return roundAmount(totalYearVal);
    };

    this.getTotalPriorMonthAmount = function()
    {
        return roundAmount(totalPriorMonthVal);
    };
    
    this.getTotalMonthAmount = function()
    {
        return roundAmount(totalMonthVal);
    };

    this.getTotalPriorWeekAmount = function()
    {
        return roundAmount(totalPriorWeekVal);
    };
        
    this.getTotalWeekAmount = function()
    {
        return roundAmount(totalWeekVal);
    };

    this.getSubCategoryName = function(subCategoryId)
    {
        if (subCatHashtable[subCategoryId])
        {
            return subCatHashtable[subCategoryId].Name;
        }
    } 
    
    this.getSubCategory = function(subCategoryId)
    {
        return subCatHashtable[subCategoryId];
    } 

        
    this.addTrans = function(categoryID, amountString, dateString, subCategoryID)
    {
        addDeleteTrans(categoryID, amountString, dateString, "Add", subCategoryID);   
    };

    this.deleteTrans = function(categoryID, amountString, dateString, subCategoryID)
    {
        addDeleteTrans(categoryID, amountString, dateString, "Delete", subCategoryID);      
    };
    
    this.getCategories = function()
    {
        return categoryArray;
    };

    this.getNumCategories = function() 
    {
        return categoryArray.length;
    }

    this.getCategory = function(arrayIndex)
    {
        return categoryArray[arrayIndex];
    };   

    this.getCategoryByCategoryID = function(categoryID)
    {
        return catHashtable[categoryID];
    };   


    this.addCategory = function(newCategory)
    {   
        //Set Initial Trans Totals Values to 0
        newCategory.WeekAmount = 0;
        newCategory.PriorWeekAmount = 0;
        newCategory.MonthAmount = 0;
        newCategory.PriorMonthAmount = 0;        
        newCategory.YearAmount  = 0;

        var numCategories = categoryArray.length;
        categoryArray[numCategories] = newCategory;

        createHashtable();
                
        addToTotalBudgets(newCategory.YearBudget, newCategory.MonthBudget, newCategory.WeekBudget);
    };


    this.addSubCategory = function(categoryID, newSubCategory)
    {   
        //Set Initial Trans Totals Values to 0
        var category = this.getCategoryByCategoryID(categoryID);

        if(!category.SubCategories)
        {
            category.SubCategories = new Array();;
        }

        var numSubCategories = category.SubCategories.length;
        category.SubCategories[numSubCategories] = newSubCategory;

        createHashtable();
    };
    
    this.changeSubCategoryID = function(oldSubCategoryID, newSubCategoryID)
    {
        var subCategory = this.getSubCategory(oldSubCategoryID);
        
        subCategory.SubCategoryID = newSubCategoryID;
        
        //Now recreate hashtable to use new ID
        createHashtable(); 
    }
    
    
    this.changeCategoryID = function(oldCategoryID, newCategoryID)
    {
        var category = catHashtable[oldCategoryID];
        
        category.CategoryID = newCategoryID;
        
        //Now recreate hashtable to use new ID
        createHashtable(); 
    }


    this.updateCategory = function(categoryID, newCat)
    {   
        var currentCat = catHashtable[categoryID];
        deleteFromTotalBudgets(currentCat.YearBudget, currentCat.MonthBudget, currentCat.WeekBudget);
        addToTotalBudgets(newCat.YearBudget, newCat.MonthBudget, newCat.WeekBudget);
        
        currentCat.Name = newCat.Name; 
        currentCat.Description = newCat.Description; 
        currentCat.YearBudget = newCat.YearBudget;
        currentCat.MonthBudget = newCat.MonthBudget;
        currentCat.WeekBudget = newCat.WeekBudget;                                
    };
            
    this.deleteCategory = function(categoryID)
    {  
        var delCat = catHashtable[categoryID];
        deleteFromTotalBudgets(delCat.YearBudget, delCat.MonthBudget, delCat.WeekBudget);
        
        deleteFromTotalAmount(delCat);

        //Remove from cateogoryArray
        var arrayIndex = getCategoryArrayIndex(categoryID)        
        categoryArray.splice(arrayIndex, 1);
        
        createHashtable();
    };    
    
    this.deleteSubCategory = function(subCategoryID)
    {  
        var subCategory = subCatHashtable[subCategoryID];        
        deleteFromTotalAmount(subCategory);
        
        var category = catHashtable[subCategory.CategoryID];                
        var numSubCategories = category.SubCategories.length;
        
        for(var i=0; i<numSubCategories; i++)
        {
            if(category.SubCategories[i].SubCategoryID == subCategoryID)
            {
                //Remove this sub category from the SubCategor array
                category.SubCategories.splice(i, 1);
                break;
            }
        }        
                
        createHashtable();
    };    

};
function TransData(transArray)
{
    //private vars used to determine sort direction for transArray values
    var dateSortDirection = 1;
    var catSortDirection = 1;
    var amountSortDirection = 1;
    var descSortDirection = 1;

    this.getTransArray = function() 
    {
        return transArray;
    }
    
    
    //Returns the Transaction associated by the TransID
    this.getTransByTransID = function(transID) 
    {
        var numTrans = transArray.length;
        for (var i = 0; i < numTrans; i++) 
        {
            if (transArray[i].TransID === transID) 
            {
                return transArray[i];
            }
        }
    }
    
    
    //Deletes the transaction with the specified TransactionID
    this.deleteTransByTransID = function(transID)
    {
        var numTrans = transArray.length;
        for(var i=numTrans; i>0; i--)
        {            
            var delIndex = i-1;        
            if(transArray[delIndex].TransID === transID)
            {
                transArray.splice(delIndex, 1);
                break;      
            }
        }                        
    };
    
    //Deletes All Transactions with the specified CategoryID
    this.deleteAllTransInCategory = function(categoryID)
    {
        var numTrans = transArray.length;
        for(var i=numTrans; i>0; i--)
        {    
            var delIndex = i-1;        
            if(transArray[delIndex].CategoryID == categoryID)
            {
                transArray.splice(delIndex, 1);
            }
        }
    };

    //Deletes All Transactions with the specified SubCategoryID
    this.deleteAllTransInSubCategory = function(subCategoryID)
    {
        var numTrans = transArray.length;
        for (var i = numTrans; i > 0; i--)
        {
            var delIndex = i - 1;
            if (transArray[delIndex].SubCategoryID == subCategoryID)
            {
                transArray.splice(delIndex, 1);
            }
        }
    };

    this.addTrans = function(trans) 
    {
        transArray.unshift(trans);
        var numRows = transArray.length;

        //transArray[numRows] = trans;

        return numRows;
    };


    this.updateTransByTransID = function(transID, trans) 
    {
        var numTrans = transArray.length;
        for (var i = 0; i < numTrans; i++) 
        {
            if (transArray[i].TransID === transID) 
            {
                transArray[i] = trans;
                break;
            }
        }
    };

    //Sorts the transArray based on the column name        
    this.sortData = function(fieldName)
    {
        var numTrans = transArray.length;

        for (var i = 0; i < (numTrans - 1); i++)
        {
            for (var j = i + 1; j < numTrans; j++)
            {
                if (fieldName === "Date")
                {
                    if (dateSortDirection === -1)
                    {
                        if ((transArray[j].Date < transArray[i].Date)
                            || ((transArray[j].Date == transArray[i].Date) && (transArray[j].TransID < transArray[i].TransID)))
                        {
                            var dummy1 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy1;
                        }
                    }
                    else
                    {
                        if ((transArray[j].Date > transArray[i].Date)
                            || ((transArray[j].Date == transArray[i].Date) && (transArray[j].TransID > transArray[i].TransID)))
                        {
                            var dummy2 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy2;
                        }
                    }
                }
                else if (fieldName === "Category")
                {
                    if (catSortDirection === -1)
                    {
                        if ((transArray[j].CategoryName < transArray[i].CategoryName)
                            || ((transArray[j].CategoryName == transArray[i].CategoryName) && (transArray[j].TransID < transArray[i].TransID)))
                        {
                            var dummy3 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy3;
                        }
                    }
                    else
                    {
                        if ((transArray[j].CategoryName > transArray[i].CategoryName)
                            || ((transArray[j].CategoryName == transArray[i].CategoryName) && (transArray[j].TransID > transArray[i].TransID)))
                        {
                            var dummy4 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy4;
                        }
                    }
                }
                else if (fieldName === "Amount")
                {
                    if (amountSortDirection === -1)
                    {
                        if (((transArray[j].Amount * 1) < (transArray[i].Amount * 1))
                            || (((transArray[j].Amount * 1) == (transArray[i].Amount * 1)) && (transArray[j].TransID < transArray[i].TransID)))
                        {
                            var dummy5 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy5;
                        }
                    }
                    else
                    {
                        if (((transArray[j].Amount * 1) > (transArray[i].Amount * 1))
                            || (((transArray[j].Amount * 1) == (transArray[i].Amount * 1)) && (transArray[j].TransID > transArray[i].TransID)))
                        {
                            var dummy6 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy6;
                        }
                    }
                }
                else if (fieldName === "Description")
                {
                    if (descSortDirection === -1)
                    {
                        if ((transArray[j].Description < transArray[i].Description)
                            || ((transArray[j].Description == transArray[i].Description) && (transArray[j].TransID < transArray[i].TransID)))
                        {
                            var dummy7 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy7;
                        }
                    }
                    else
                    {
                        if ((transArray[j].Description > transArray[i].Description)
                            || ((transArray[j].Description == transArray[i].Description) && (transArray[j].TransID > transArray[i].TransID)))
                        {
                            var dummy8 = transArray[i];
                            transArray[i] = transArray[j];
                            transArray[j] = dummy8;
                        }
                    }
                }
            }
        }

        if (fieldName === "Date")
        {
            dateSortDirection = dateSortDirection * -1;
        }
        else if (fieldName === "Category")
        {
            catSortDirection = catSortDirection * -1;
        }
        else if (fieldName === "Amount")
        {
            amountSortDirection = amountSortDirection * -1;
        }
        else if (fieldName === "Description")
        {
            descSortDirection = descSortDirection * -1;
        }
    }

}var graphData = new Object();

function setGraphData(id, value) 
{
    graphData[id] = value;
};

function getGraphData(id) 
{
    return graphData[id];
};
/*
Author: Rens Methratta
Copyright ExpenseView.com
This code is property of ExpenseView.com and cannot be used without explicit permission
from Rens Methratta.
*/


//Specifies the pages that make up the application
var pages = new Array('expensePage', 'incomePage', 'balancePage', 'loadingPage', 'welcomePage');

//Specifies the panels within the pages
var welcomePanels = new Array('div_welcomeOverviewPanel', 'div_welcomeAboutUsPanel', 'div_welcomeLatestUpdatesPanel');
var expensePanels = new Array('div_addExpensePanel', 'div_searchExpPanel', 'div_expCategoryPanel', 'div_expTrends', 'div_expPieChartPanel', 'div_expenseLoggedOutPanel');
var incomePanels = new Array('div_addIncomePanel', 'div_searchIncomePanel', 'div_incomeCategoryPanel', 'div_incomeTrends', 'div_incomePieChartPanel', 'div_incomeLoggedOutPanel');
var balancePanels = new Array('div_balanceSumPanel', 'div_balanceLoggedOutPanel');

var adPanels = new Array('expenseAds');

//Stores currently selected link for each Page
var currentExpLinkId = "addExpLink";
var currentIncomeLinkId = "addIncomeLink";
var currentBalanceLinkId = "balanceSumLink";
var currentWelcomeLinkId = "siteOverviewLink";

var linkMenus = new Array('welcomeLinks', 'expenseLinks', 'incomeLinks', 'balanceLinks');

var selectedTab = null;
var currentPage = "";

//Global Data Objects
var ExpViewGlobalData = ExpViewGlobalData ? ExpViewGlobalData : new Object();
var transData = null;
var expCategoryData = null;
var incomeCategoryData = null;
var recentExpData = null;
var recentIncomeData = null;
var isAuthenticated = false;

//JSON Service
var serviceURL = "http://" + window.location.host + "/Service/JsonService.ashx";
var jsonService = new JsonService(serviceURL);


/************************ Edit Settings Window Functions *********************/
function openEditAccountInfoWindow() {
    var editSettingsWin = dhtmlwindow.open("editSettingsBox", "iframe", "editAccountInfo.aspx", "Edit Account Info", "width=570px,height=350px,resize=0,scrolling=0,left=300,top=40,center=0")
    dhtmlwindow.setCloseFunction(reloadApp);
}

/************************ Edit Settings Window Functions *********************/
function openTransactionImportWindow() {
    var transactionImportWin = dhtmlwindow.open("transactionImportBox", "iframe", "TransactionImport.aspx", "Import Bank/Credit Card Statements", "width=700px,height=600px,resize=1,scrolling=0,left=300,top=40,center=0")
    dhtmlwindow.setCloseFunction(reloadApp);
}


/************************* Common Tab Menu Functions *************************/
function loadApp(isLoggedIn) {
    var userDate = new Date();
    isAuthenticated = isLoggedIn;

    if (isAuthenticated) {
        jsonService.GetUserSummary(userDate, viewFirstPage);
    }
    else {
        viewPage("welcome");
        Meebo('unhide');
        Meebo('domReady');
    }
}

function reloadApp() {
    location.reload(true);
}

function viewFirstPage(response) {
    transData = JSON.parse(response.result);

    //Set Global Variables
    ExpViewGlobalData.userDateFormat = transData.PreferredDateFormat;
    ExpViewGlobalData.userDisplayDecimals = transData.AmountDisplayDecimals;

    //0=Sunday, 1=Monday
    ExpViewGlobalData.userWeekStart = 0;

    //Create Expense Data Objects
    if (transData.ExpenseCategories) {
        expCategoryData = new CategoryData(transData.ExpenseCategories);
    }

    if (transData.RecentExpenses) {
        recentExpData = new TransData(transData.RecentExpenses);
    }

    //Create Income Data Objects
    if (transData.IncomeCategories) {
        incomeCategoryData = new CategoryData(transData.IncomeCategories);
    }

    if (transData.RecentIncome) {
        recentIncomeData = new TransData(transData.RecentIncome);
    }

    viewPage("expense");

    Meebo("domReady");
}

function viewPage(pageName, linkId) {
    if (pageName == "welcome") {
        currentPage = "welcome";
        highlightTab("welcome");
        showLinkMenu("welcome");
        showPage(pageName);
        viewWelcomePanel();
    }
    else {
    
        currentPage = pageName;
        highlightTab(pageName);
        showPage(pageName);

        if (isAuthenticated) 
        {
            showLinkMenu(pageName);
            showAd("expenseAds");

            if (pageName === "expense") 
            {
                viewExpensePanel(linkId);
            }
            else if (pageName === "income") 
            {
                viewIncomePanel(linkId);
            }
            else if (pageName === "balance") 
            {
                viewBalancePanel(linkId);
            }
        }
        else {
            //Done show any links
            showLinkMenu("");
            if (pageName === "expense") 
            {
                showPanel(expensePanels, "div_expenseLoggedOutPanel");
            }
            else if (pageName === "income") 
            {
                showPanel(incomePanels, "div_incomeLoggedOutPanel");
            }
            else if (pageName === "balance") 
            {
                showPanel(balancePanels, "div_balanceLoggedOutPanel");
            }
        }
    }
}

function showPage(pageName) {
    for (var i = 0; i < pages.length; i++) {
        document.getElementById(pages[i]).style.display = ((pageName + 'Page') == pages[i]) ? 'block' : 'none';
    }
}

function showPanel(panelArray, panelName) {
    for (var i = 0; i < panelArray.length; i++) {
        document.getElementById(panelArray[i]).style.display = (panelName == panelArray[i]) ? 'block' : 'none';
    }
}

function showLinkMenu(linkMenuName) {
    for (var i = 0; i < linkMenus.length; i++) {
        document.getElementById(linkMenus[i]).style.display = ((linkMenuName + 'Links') == linkMenus[i]) ? 'block' : 'none';
    }
}

/* Higlight the newly selected link and unhighlight the currently selected */
function selectLink(currentLinkId, newLinkId) {
    if (currentLinkId) {
        var currentLink = document.getElementById(currentLinkId);
        currentLink.className = "panelLink";
    }

    var selectedLink = document.getElementById(newLinkId);
    selectedLink.className = "selPanelLink";
}

function highlightTab(tabID) {
    if (selectedTab) {
        selectedTab.className = "tab";
    }

    selectedTab = document.getElementById((tabID + 'Tab'));
    selectedTab.className = "selectedTab";
}


/************************* Expense Page Menu Functions *************************/
function viewExpensePanel(linkId) {
    
    if (!linkId) {
        linkId = currentExpLinkId;
    }
    else {
        selectLink(currentExpLinkId, linkId);
    }

    if (linkId === "addExpLink") {
        drawAddExpensePanel();
        showPanel(expensePanels, "div_addExpensePanel");
    }
    else if (linkId === "searchExpLink") {
        drawSearchExpensePanel();
        showPanel(expensePanels, "div_searchExpPanel");
    }
    else if (linkId === "expCategoryLink") {
        drawExpCategoryPanel();
        showPanel(expensePanels, "div_expCategoryPanel");
    }
    else if (linkId === "expBreakdownLink") {
        drawExpensePieChartPanel();
        showPanel(expensePanels, "div_expPieChartPanel");
    }
    else if (linkId === "expTrends") {
        drawExpTrendsPanel();
    }

    currentExpLinkId = linkId;
}

/************************* Income Page Menu Functions *************************/
function viewIncomePanel(linkId) {

    if (!linkId) {
        linkId = currentIncomeLinkId;
    }
    else {
        //If PanelName is not specified, default to the current income panel
        selectLink(currentIncomeLinkId, linkId);
    }

    if (linkId === "addIncomeLink") {
        drawAddIncomePanel();
        showPanel(incomePanels, "div_addIncomePanel");
    }
    else if (linkId === "searchIncomeLink") {
        drawSearchIncomePanel();
        showPanel(incomePanels, "div_searchIncomePanel");
    }
    else if (linkId === "incomeCategoryLink") {
        drawIncomeCategoryPanel();
        showPanel(incomePanels, "div_incomeCategoryPanel");
    }
    else if (linkId === "incomeBreakdownLink") {
        drawIncomePieChartPanel();
        showPanel(incomePanels, "div_incomePieChartPanel");

    }

    currentIncomeLinkId = linkId;
}

/************************* Balance Page Menu Functions *************************/
function viewBalancePanel(linkId) {

    if (!linkId) {
        //If linkId is not specified, default to the currently displayed balance panel 
        linkId = currentBalanceLinkId;
    }
    else {
        selectLink(currentBalanceLinkId, linkId);
    }

    if (linkId === "balanceSumLink") 
    {
        drawBalanceSummary();
        showPanel(balancePanels, "div_balanceSumPanel");
    }

    currentBalanceLinkId = linkId;
}

/************************* Welcome Panel Menu Functions *************************/
function viewWelcomePanel(linkId) 
{
    if (!linkId) 
    {
        linkId = currentWelcomeLinkId;
    }
    else 
    {
        selectLink(currentWelcomeLinkId, linkId);
    }

    if (linkId === "siteOverviewLink") {
        showPanel(welcomePanels, "div_welcomeOverviewPanel");
    }
    else if (linkId === "aboutUsLink") {
        showPanel(welcomePanels, "div_welcomeAboutUsPanel");
    }
    else if (linkId === "latestUpdatesLink") {
        showPanel(welcomePanels, "div_welcomeLatestUpdatesPanel");
    }

    currentWelcomeLinkId = linkId;
}


//Required to load components when loading panel
function showAd(adType) {
    showPanel(adPanels, adType);
}
/************************************************************************************/
/* Adapted From Swazz Javascript Calendar ---
By Oliver Bryant
*************************************************************************************/
function getObj(objID)
{
    if (document.getElementById) {return document.getElementById(objID);}
    else if (document.all) {return document.all[objID];}
    else if (document.layers) {return document.layers[objID];}
}

function checkClick(e) {
	e?evt=e:evt=event;
	CSE=evt.target?evt.target:evt.srcElement;
	if (getObj('fc'))
		if (!isChild(CSE,getObj('fc')))
			getObj('fc').style.display='none';
}

function isChild(s,d) {
	while(s) {
		if (s==d) 
			return true;
		s=s.parentNode;
	}
	return false;
}

function Left(obj)
{
	var curleft = 0;

	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}

function Top(obj)
{
	var curtop = 0;

	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
		
	return curtop;
}
	
document.write('<table id="fc" style="position:absolute;border-collapse:collapse;background:#FFFFFF;border:1px solid #ABABAB;display:none;z-index:20;" cellpadding=2>');
document.write('<tr><td style="cursor:pointer" onclick="csubm()"><img src="images/arrowleftmonth.gif"></td><td colspan=5 id="mns" align="center" style="font:bold 13px Arial"></td><td align="right" style="cursor:pointer" onclick="caddm()"><img src="images/arrowrightmonth.gif"></td></tr>');
document.write('<tr><td align=center style="background:#ABABAB;font:12px Arial">S</td><td align=center style="background:#ABABAB;font:12px Arial">M</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">W</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">F</td><td align=center style="background:#ABABAB;font:12px Arial">S</td></tr>');
for(var kk=1;kk<=6;kk++) {
	document.write('<tr>');
	for(var tt=1;tt<=7;tt++) {
		num=7 * (kk-1) - (-tt);
		document.write('<td id="v' + num + '" style="width:18px;height:18px">&nbsp;</td>');
	}
	document.write('</tr>');
}
document.write('</table>');

document.all?document.attachEvent('onclick',checkClick):document.addEventListener('click',checkClick,false);


// Calendar script
var now = new Date;
var sccm=now.getMonth();
var sccy=now.getFullYear();
var ccm=now.getMonth();
var ccy = now.getFullYear();
var ccd = now.getDate();

var updobj;
function lcs(ielem) {
	updobj=ielem;
	getObj('fc').style.left=''+Left(ielem)+'px';
	getObj('fc').style.top=''+(Top(ielem)+ielem.offsetHeight)+'px';
	getObj('fc').style.display='';
	
	//Set CurrentDate based on value specified in input element
	curdt = ielem.value;
	if (curdt && isValidFormattedDate(curdt))
	{
	    var currentDate = getDateFromFormattedDateString(curdt);
	    if (currentDate)
	    {
            ccm = currentDate.getMonth();
            ccy = currentDate.getFullYear();
            ccd = currentDate.getDate();
	    }
	}
	
	prepcalendar(ccm,ccd,ccy);	
}

function evtTgt(e)
{
	var el;
	if(e.target)el=e.target;
	else if(e.srcElement)el=e.srcElement;
	if(el.nodeType==3)el=el.parentNode; // defeat Safari bug
	return el;
}
function EvtObj(e){if(!e)e=window.event;return e;}
function cs_over(e) {
	evtTgt(EvtObj(e)).style.background='#FFCC66';
}
function cs_out(e) {
	evtTgt(EvtObj(e)).style.background='#C4D3EA';
}
function cs_click(e) {
    updobj.value = getFormattedDateString(calvalarr[evtTgt(EvtObj(e)).id.substring(1, evtTgt(EvtObj(e)).id.length)]);
	getObj('fc').style.display='none';	
}

var mn=new Array('JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC');
var mnn=new Array('31','28','31','30','31','30','31','31','30','31','30','31');
var mnl=new Array('31','29','31','30','31','30','31','31','30','31','30','31');
var calvalarr=new Array(42);

function f_cps(obj) {
	obj.style.background='#C4D3EA';
	obj.style.font='10px Arial';
	obj.style.color='#333333';
	obj.style.textAlign='center';
	obj.style.textDecoration='none';
	obj.style.border='1px solid #6487AE';
	obj.style.cursor='pointer';
}

function f_cpps(obj) {
	obj.style.background='#C4D3EA';
	obj.style.font='10px Arial';
	obj.style.color='#ABABAB';
	obj.style.textAlign='center';
	obj.style.textDecoration='line-through';
	obj.style.border='1px solid #6487AE';
	obj.style.cursor='default';
}

function f_hds(obj) {
	obj.style.background='#FFF799';
	obj.style.font='bold 10px Arial';
	obj.style.color='#333333';
	obj.style.textAlign='center';
	obj.style.border='1px solid #6487AE';
	obj.style.cursor='pointer';
}

// day selected
function prepcalendar(cm,hd,cy) {
	now=new Date();
	sd=now.getDate();
	td=new Date();
	td.setDate(1);
	td.setFullYear(cy);
	td.setMonth(cm);
	cd=td.getDay();
	getObj('mns').innerHTML=mn[cm]+ ' ' + cy;
	marr=((cy%4)==0)?mnl:mnn;
	for (var d = 1; d <= 42; d++) 
	{
		f_cps(getObj('v'+parseInt(d)));
		if ((d >= (cd - (-1))) && (d <= cd - (-marr[cm])))
		{
		    htd = ((hd != '') && (d - cd == hd));
		    if (htd)
		        f_hds(getObj('v' + parseInt(d)));

		    getObj('v' + parseInt(d)).onmouseover = cs_over;
		    getObj('v' + parseInt(d)).onmouseout = cs_out;
		    getObj('v' + parseInt(d)).onclick = cs_click;

		    getObj('v' + parseInt(d)).innerHTML = d - cd;
		    var monthVal = '' + (cm - (-1));
		    if (monthVal.length === 1) { monthVal = "0" + monthVal };
		    var dateVal = '' + (d - cd);
		    if (dateVal.length === 1) { dateVal = "0" + dateVal };

		    //format == YYYY-MM- DD
		    calvalarr[d] = '' + cy + '-' + monthVal + '-' + dateVal;
		}
		else
		{
		    getObj('v' + d).innerHTML = '&nbsp;';
		    getObj('v' + parseInt(d)).onmouseover = null;
		    getObj('v' + parseInt(d)).onmouseout = null;
		    getObj('v' + parseInt(d)).style.cursor = 'default';
		}
	}
}

prepcalendar(ccm,'',ccy);
//getObj('fc'+cc).style.visibility='hidden';

function caddm() {
	marr=((ccy%4)==0)?mnl:mnn;
	
	ccm+=1;
	if (ccm>=12) {
		ccm=0;
		ccy++;
	}
	prepcalendar(ccm,'',ccy);
}

function csubm() {
	marr=((ccy%4)==0)?mnl:mnn;
	
	ccm-=1;
	if (ccm<0) {
		ccm=11;
		ccy--;
	}
	prepcalendar(ccm,'',ccy);
}
function AddCategoryModule(displayDiv, categoryType)
{
    var catFieldDesc = "";
    if(categoryType === "Expense") 
    { 
        catFieldDesc = "Budget"; 
    } 
    else 
    {
        catFieldDesc = "Amount";
    }

    this.drawModule = function()
    { 
        var sb = new StringBuffer();

        sb.append("<table class='fixedTable' border='0' cellpadding='0' cellspacing='0' width='760px'>");
        sb.append("<tr class='blueTableHeaderRow'>");
 
        sb.append("<td width='10px' class='blueTableTopLeftCorner'>&nbsp;</td>");        
        sb.append("<td width='140px' align='left'>Category Name</td>");
        sb.append("<td width='190px' align='left'>Description</td>");
        
        sb.append("<td width='100px' align='center'>Year " + catFieldDesc + "</td>");        
        sb.append("<td width='100px' align='center'>Month " + catFieldDesc + "</td>");
        sb.append("<td width='100px' align='center'>Week " + catFieldDesc + "</td>");
        
        sb.append("<td width='114px' class='blueTableTopRightCorner'>&nbsp;&nbsp;</td></tr>");
        sb.append("<tr align='left' valign='top' class='blueTableDataRow' id='addCategoryDataRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");
        sb.append("<td><input type='text' id='" + displayDiv + "addCatName' class='defaultText' size='18' tabindex='1' /></td>");

        sb.append("<td><input type='text' id='" + displayDiv + "addCatDesc' class='defaultText' size='25' tabindex='3' /></td>");
        
        sb.append("<td align='center'><input type='text' id='" + displayDiv + "addCatYearBudget' class='defaultText' size='10' tabindex='3' /></td>");
        sb.append("<td align='center'><input type='text' id='" + displayDiv + "addCatMonthBudget' class='defaultText' size='10' tabindex='4' /></td>");
        sb.append("<td align='center'><input type='text' id='" + displayDiv + "addCatWeekBudget' class='defaultText' size='10' tabindex='5' /></td>");
                    
        sb.append("<td class='blueTableLastColumn'><input type='button' id='addCatBtn' value='Add Category' onclick='javascript:" + displayDiv + "AddCategory();void(0);' class='addButton' size='11' tabindex='6'  style='width: 110px'/></td></tr>");
        sb.append("<tr class='blueTableFooterRow'>");
        sb.append("<td colspan='4' class='blueTableBotLeftCorner'></td>");        
        
       sb.append("<td class='blueTableBotRightCorner' colspan='3'></td></tr></table>");
        
        document.getElementById(displayDiv).innerHTML = sb.toString();                
    };

    this.getCategory = function()
    {
        var category = new Object();
        category.Name = getFieldValue(displayDiv+"addCatName");   
        category.description = getFieldValue(displayDiv+"addCatDesc");    

        category.yearBudget = getFieldValue(displayDiv+"addCatYearBudget");               
        category.monthBudget = getFieldValue(displayDiv+"addCatMonthBudget");
        category.weekBudget = getFieldValue(displayDiv+"addCatWeekBudget");
        
        if(categoryType === "Expense")
        {                        
            category.CategoryType = "E";                                     
        }
        else if(categoryType === "Income")
        {
            category.CategoryType = "I";
        }          
        
        return category;  
    };            
    
    //Clear out Fields 
    this.clearFields = function()
    {
        document.getElementById(displayDiv +"addCatName").value = "";
        document.getElementById(displayDiv +"addCatDesc").value = "";        
        document.getElementById(displayDiv +"addCatYearBudget").value = "";        
        document.getElementById(displayDiv +"addCatMonthBudget").value = "";        
        document.getElementById(displayDiv +"addCatWeekBudget").value = "";        
    };    
};// JScript File
//Add either expenses or income Category by (Year, Month, etc.)
function AddTransModule(panelName, categoryType, categoryArray)
{
    var displayDiv = panelName;

    this.toHTML = function(trans) {

        if (!categoryArray) {
            return;
        }
        
        var sb = new StringBuffer();

        //ALTER Table Headers
        sb.append("<table class='fixedTable' cellspacing='0' border='0' cellpadding='0' width='730px'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='10px' class='blueTableTopLeftCorner'></td>");
        sb.append("<td width='170px' align='left'>Category</td>");
        sb.append("<td width='110px' align='left'>Date</td>");
        sb.append("<td width='100px' align='left'>Amount</td>");
        sb.append("<td width='205px' align='left'>Comment</td>");
        sb.append("<td width='125px' class='blueTableTopRightCorner'>&nbsp;</td>");
        sb.append("</tr>");

        sb.append("<tr align='left' class='blueTableDataRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");
        sb.append("<td><select id='" + displayDiv + "_addTransCatList' class='defaultText' tabIndex='1' STYLE='width: 160px'>");

        //Fill in Drop Down Option Values For Categories
        var numCategories = 0;
        if (categoryArray) {
            numCategories = categoryArray.length;
        }
        for (i = 0; i < numCategories; i++) {
            var category = categoryArray[i];
            sb.append("<option value='");
            sb.append(category.CategoryID);
            sb.append("' ");
            sb.append(">");
            sb.append(category.Name);
            sb.append("</option>");

            if (category.SubCategories) {
                var numSubCategories = category.SubCategories.length;
                for (subCatIndex = 0; subCatIndex < numSubCategories; subCatIndex++) {
                    var subCategory = category.SubCategories[subCatIndex];

                    sb.append("<option value='");
                    sb.append(category.CategoryID + ":" + subCategory.SubCategoryID);
                    sb.append("' ");

                    sb.append(">&nbsp;");
                    sb.append(category.Name + " - " + subCategory.Name);
                    sb.append("</option>");
                }
            }
        }

        sb.append("</select></td>");

        sb.append("<td><input type='text' size='12' id='" + displayDiv + "_addTransDate' class='defaultText' tabIndex='2' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' value='" + getFormattedDateString() + "'  /></td>");
        sb.append("<td><input id='" + displayDiv + "_addTransAmount' size='10' type='text' class='defaultText' tabIndex='3' /></td>");
        sb.append("<td><input type='text' id='" + displayDiv + "_addTransComments' class='defaultText' size='30' tabIndex='4' /></td>");
        sb.append("<td class='blueTableLastColumn' align='center'>");
        sb.append("<input type='button' id='transAddBtn' value='Add " + categoryType + "' onclick='javascript:" + panelName + ".addTrans();void(0);' class='addButton' tabIndex='5' style='width: 110px'>");
        sb.append("</td></tr>");

        sb.append("<tr class='blueTableFooterRow'><td class='blueTableBotLeftCorner' colspan='3'></td><td class='blueTableBotRightCorner' colspan='3'></td>");
        sb.append("</tr></table>");

        return sb.toString();
    };

    this.getTrans = function()
    {
        var trans = new Object();
        trans.Date = getDateStringFromFormattedDateString(getFieldValue(displayDiv + "_addTransDate"));

        trans.Amount = roundAmount(getFieldValue(displayDiv + "_addTransAmount"));
        trans.DisplayAmount = trans.Amount;
        trans.Description = getFieldValue(displayDiv + "_addTransComments");

        var categoryList = document.getElementById(displayDiv + "_addTransCatList");
        if (categoryList)
        {
            var selectedIDs = categoryList.options[categoryList.selectedIndex].value.split(":");

            trans.CategoryID = selectedIDs[0];
            if (selectedIDs.length > 1)
            {
                trans.SubCategoryID = selectedIDs[1];
            }
        }

        if (categoryType === "Expense")
        {
            trans.CategoryType = "E";
        }
        else if (categoryType === "Income")
        {
            trans.CategoryType = "I";
        }

        return trans;
    };
    
    //Clear out Fields 
    this.clearFields = function()
    {
        document.getElementById(displayDiv +"_addTransAmount").value = "";
        document.getElementById(displayDiv +"_addTransComments").value = "";        
    }; 
    
    //Set focus back on Category drop-down list
    this.focus = function()
    {
        var categoryList = document.getElementById(displayDiv +"_addTransCatList");       

        if(categoryList) 
        { 
            categoryList.focus();             
        }
    };
}function BalanceChangeTable(displayDivName, expCatData, incomeCatData)
{    
    this.drawModule = function()
    {        
        var sb = new StringBuffer();        
        
        //ALTER Table Headers
        sb.append("<table class='fixedTable' width='790px' cellspacing='0' border='0' cellpadding='0'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='10px' class='blueTableTopLeftCorner'>&nbsp;</td>");            
        sb.append("<td width='210px' align='left'>&nbsp;</td>");    
        sb.append("<td width='115px' align='center'>This Year</td>");
        sb.append("<td width='115px' align='center'>Last Month</td>");
        sb.append("<td width='115px' align='center'>This Month</td>");
        sb.append("<td width='115px' align='center'>Last Week</td>");
        sb.append("<td width='110px' align='center' class='blueTableTopRightCorner'>This Week</td></tr>");

        //Income Data
        sb.append("<tr class='blueTableOddRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");                        
        sb.append("<td align='left'>Income</td>");
        sb.append("<td align='center'>" + getRoundedAmount(incomeCatData.getTotalYearAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(incomeCatData.getTotalPriorMonthAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(incomeCatData.getTotalMonthAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(incomeCatData.getTotalPriorWeekAmount()) + "</td>");
        sb.append("<td align='center' class='blueTableLastColumn'>" + getRoundedAmount(incomeCatData.getTotalWeekAmount()) + "</td>");
        sb.append("</tr>");				

        //Expense Data
        sb.append("<tr class='blueTableEvenRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");                        
        sb.append("<td align='left'>Expenses</td>");
        sb.append("<td align='center'>" + getRoundedAmount(expCatData.getTotalYearAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(expCatData.getTotalPriorMonthAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(expCatData.getTotalMonthAmount()) + "</td>");
        sb.append("<td align='center'>" + getRoundedAmount(expCatData.getTotalPriorWeekAmount()) + "</td>");
        sb.append("<td align='center' class='blueTableLastColumn'>" + getRoundedAmount(expCatData.getTotalWeekAmount()) + "</td>");
        sb.append("</tr>");				

        var totalYearSavings = (incomeCatData.getTotalYearAmount() * 1) - (expCatData.getTotalYearAmount() * 1);        
        var totalYearStyle = (totalYearSavings < (incomeCatData.getTotalYearBudget() - expCatData.getTotalYearBudget())) ? 'negativeAmount' : 'possitiveAmount';        

        var totalPriorMonthSavings = (incomeCatData.getTotalPriorMonthAmount() * 1) - (expCatData.getTotalPriorMonthAmount() * 1);        
        var totalPriorMonthStyle = (totalPriorMonthSavings < (incomeCatData.getTotalMonthBudget() - expCatData.getTotalMonthBudget())) ? 'negativeAmount' : 'possitiveAmount';        

        var totalMonthSavings = (incomeCatData.getTotalMonthAmount() * 1) - (expCatData.getTotalMonthAmount() * 1);        
        var totalMonthStyle = (totalMonthSavings < (incomeCatData.getTotalMonthBudget() - expCatData.getTotalMonthBudget())) ? 'negativeAmount' : 'possitiveAmount';        

        var totalPriorWeekSavings = (incomeCatData.getTotalPriorWeekAmount() * 1) - (expCatData.getTotalPriorWeekAmount() * 1);        
        var totalPriorWeekStyle = (totalPriorWeekSavings < (incomeCatData.getTotalWeekBudget() - expCatData.getTotalWeekBudget())) ? 'negativeAmount' : 'possitiveAmount';        

        var totalWeekSavings = (incomeCatData.getTotalWeekAmount() * 1) - (expCatData.getTotalWeekAmount() * 1);        
        var totalWeekStyle = (totalWeekSavings < (incomeCatData.getTotalWeekBudget() - expCatData.getTotalWeekBudget())) ? 'negativeAmount' : 'possitiveAmount';        

                
        sb.append("<tr class='blueTableFooterRow'>");
        sb.append("<td class='blueTableBotLeftCorner'></td>");
        sb.append("<td align='left'><b>Balance Change</b></td>");
        sb.append("<td align='center' class='" + totalYearStyle + "'>" + getRoundedAmount(totalYearSavings) + "</td>");
        sb.append("<td align='center' class='" + totalPriorMonthStyle + "'>" + getRoundedAmount(totalPriorMonthSavings) + "</td>");
        sb.append("<td align='center' class='" + totalMonthStyle + "'>" + getRoundedAmount(totalMonthSavings) + "</td>");
        sb.append("<td align='center' class='" + totalPriorWeekStyle + "'>" + getRoundedAmount(totalPriorWeekSavings) + "</td>");
        sb.append("<td  align='center' class='blueTableBotRightCorner " + totalWeekStyle +"'>" + getRoundedAmount(totalWeekSavings) + "</td></tr>");        
        sb.append("</table>");
        
        document.getElementById(displayDivName).innerHTML = sb.toString();
    };
}//ALTERs a Table displaying the Expenses by Category by (Year, Month, etc.)
function CategoryTableModule(panelName, categoryData, categoryType)
{
    //Get a shallow copy of categories
    
    var categoryArray;
    if (categoryData) 
    {
        categoryArray = categoryData.getCategories();
    }
        
    var catFieldDesc = "";
    if(categoryType === "Expense") 
    { 
        catFieldDesc = "Budget"; 
    } 
    else 
    {
        catFieldDesc = "Amount";
    }

    this.toHTML = function() {
        var numCategories = 0;

        if (categoryArray) {
            numCategories = categoryArray.length;
        }

        var sb = new StringBuffer();

        //ALTER Table Headers
        sb.append("<table class='fixedTable' cellspacing='0' border='0' cellpadding='0' width='800px'>");

        sb.append("<thead><tr><th width='30px'></th>");
        sb.append("<th width='140px'></th>");
        sb.append("<th width='200px'></th>");
        sb.append("<th width='100px'></th>");
        sb.append("<th width='100px'></th>");
        sb.append("<th width='100px'></th>");
        sb.append("<th width='100px'></th>");
        sb.append("<th width='10px'></th></tr>");

        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td colspan='2' width='170px' class='blueTableTopLeftCorner'>");
        sb.append("&nbsp;Category Name</td>");
        sb.append("<td width='200px' align='left'>Description</td>");

        sb.append("<td width='100px' align='center'>Year " + catFieldDesc + "</td>");
        sb.append("<td width='100px' align='center'>Month " + catFieldDesc + "</td>");
        sb.append("<td width='100px' align='center'>Week " + catFieldDesc + "</td>");

        sb.append("<td width='100px'>&nbsp;</td>");
        sb.append("<td width='10px' class='blueTableTopRightCorner'>&nbsp;</td></tr>");

        sb.append("<tr align='left' valign='top' class='blueCategoryTableDataRow' id='addCategoryDataRow'>");
        sb.append("<td class='blueTableFirstColumn' colspan='2'>&nbsp;");
        sb.append("<input type='text' id='" + panelName + "addCatName' class='defaultText' size='18' tabindex='1' /></td>");

        sb.append("<td><input type='text' id='" + panelName + "addCatDesc' class='defaultText' size='25' tabindex='3' /></td>");

        sb.append("<td align='center'><input type='text' id='" + panelName + "addCatYearBudget' class='defaultText' size='10' tabindex='3' /></td>");
        sb.append("<td align='center'><input type='text' id='" + panelName + "addCatMonthBudget' class='defaultText' size='10' tabindex='4' /></td>");
        sb.append("<td align='center'><input type='text' id='" + panelName + "addCatWeekBudget' class='defaultText' size='10' tabindex='5' /></td>");

        sb.append("<td class='blueTableLastColumn' colspan='2'><input type='button' id='addCatBtn' value='Add Category' onclick='javascript:" + panelName + ".addCategory();void(0);' class='addButton' size='11' tabindex='6'  style='width: 110px'/></td></tr>");

        for (var rowIndex = 0; rowIndex < numCategories; rowIndex++) {
            var style = (rowIndex % 2 === 0) ? 'blueTableEvenRow' : 'blueTableOddRow';
            var category = categoryArray[rowIndex];

            //Clear out any Null Values so they are not displayed
            if (!category.MonthBudget) {
                category.MonthBudget = "";
            }
            if (!category.YearBudget) {
                category.YearBudget = "";
            }
            if (!category.WeekBudget) {
                category.WeekBudget = "";
            }
            if (!category.Description) {
                category.Description = "";
            }

            if (category.Selected) {
                sb.append("<tr align='left' id='catTableRow");
                sb.append(i);
                sb.append("' class='" + style + "'>");
                sb.append("<td width='30' class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "CatRow" + rowIndex + "','" + panelName + "ClickIcon" + rowIndex + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + rowIndex + "\" style=\"cursor: pointer; cursor: hand;\">");
                sb.append(this.getSubCategoryToggleIcon(panelName + "ClickIcon" + rowIndex));
                sb.append("</td>");
                sb.append("<td width='140' align='left'><input type='text' id='" + panelName + "editCatName" + category.CategoryID + "' class='defaultText' size='18' value='" + escapeQuote(category.Name) + "' /></td>");
                sb.append("<td align='left'><input type='text' id='" + panelName + "editCatDesc" + category.CategoryID + "' class='defaultText' size='25' value='" + escapeQuote(category.Description) + "' /></td>");

                sb.append("<td align='center'><input type='text' id='" + panelName + "editCatYearBudget" + category.CategoryID + "' class='defaultText' size='10' value='" + padZeros(category.YearBudget) + "' /></td>");
                sb.append("<td align='center'><input type='text' id='" + panelName + "editCatMonthBudget" + category.CategoryID + "' class='defaultText' size='10' value='" + padZeros(category.MonthBudget) + "' /></td>");
                sb.append("<td align='center'><input type='text' id='" + panelName + "editCatWeekBudget" + category.CategoryID + "' class='defaultText' size='10' value='" + padZeros(category.WeekBudget) + "' /></td>");

                sb.append("<td align='right'><a href='javascript:" + panelName + ".updateCategory(" + category.CategoryID + ");void(0);'>Update</a>&nbsp;<a href='javascript:" + panelName + ".toggleCategoryEdit(" + category.CategoryID + ");void(0);'>Cancel</a></td>");
                sb.append("<td class='blueTableLastColumn'>&nbsp;</td></tr>");
            }
            else {
                sb.append("<tr align='left' id='catTableRow" + rowIndex + "' class='" + style + "'>");
                sb.append("<td class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "CatRow" + rowIndex + "','" + panelName + "ClickIcon" + rowIndex + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + rowIndex + "\" style=\"cursor: pointer; cursor: hand;\">");
                sb.append(this.getSubCategoryToggleIcon(panelName + "ClickIcon" + rowIndex));
                sb.append("</td>");
                sb.append("<td align='left'>" + escapeQuote(category.Name) + "</td>");
                sb.append("<td align='left'>" + escapeQuote(category.Description) + "</td>");
                sb.append("<td align='center'>" + padZeros(category.YearBudget) + "</td>");
                sb.append("<td align='center'>" + padZeros(category.MonthBudget) + "</td>");
                sb.append("<td align='center'>" + padZeros(category.WeekBudget) + "</td>");

                if (!category.State || category.State === "Current") {
                    sb.append("<td align='right'><a href='javascript:" + panelName + ".deleteCategory(" + category.CategoryID + ");void(0);'>");
                    sb.append("<img src='images/delete.gif' alt='Delete Category' border='0' /></a>");
                    sb.append("<a href='javascript:" + panelName + ".toggleCategoryEdit(" + category.CategoryID + ");void(0);'>");
                    sb.append("<img src='images/table_edit.gif' alt='Edit Category' border='0' /></a></td>");
                }
                else if (category.State === "Adding" || category.State === "Updating" || category.State === "Deleting") {
                    sb.append("<td align='right'>");
                    sb.append("<img src='images/loading.gif' alt='loading' border='0' />...");
                    sb.append(category.State + "</td>");
                }
                else if (category.State === "AddFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".retryAddCategory(" + category.CategoryID + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Add</a></td>");
                }
                else if (category.State === "UpdateFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".retryUpdateCategory(" + category.CategoryID + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Update</a></td>");
                }
                else if (category.State === "DeleteFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".deleteCategory(" + category.CategoryID + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Delete</a></td>");
                }


                sb.append("<td class='blueTableLastColumn'>&nbsp;</td></tr>");
            }

            if (category.SubCatTableOpen) {
                sb.append("<tbody align='left' valign='middle' id=\"" + panelName + "CatRow" + rowIndex + "\">");
            }
            else {
                sb.append("<tbody align='left' valign='middle' id=\"" + panelName + "CatRow" + rowIndex + "\" style=\"display:none\">");
            }

            sb.append("<tr class='" + style + "'><td class='blueTableFirstColumn'>&nbsp;&nbsp;</td>");
            sb.append("<td align='left'>&nbsp;&nbsp;<input type='text' id='" + panelName + "addSubCatName" + category.CategoryID + "' class='defaultText' size='15' /></td>");
            sb.append("<td align='left' colspan='5'>&nbsp;<input type='button' id='addSubCatBtn' value='Add SubCategory' onclick='javascript:" + panelName + ".addSubCategory(" + category.CategoryID + ");void(0);' class='addButton' size='9' tabindex='6'  style='width: 120px'/></td>");
            sb.append("<td align='center' class='blueTableLastColumn'>&nbsp;</td></tr>");

            if (category.SubCategories) {
                var numSubCategories = category.SubCategories.length;

                for (var j = 0; j < numSubCategories; j++) {
                    var subCategory = category.SubCategories[j];
                    sb.append("<tr class='" + style + "'><td class='blueTableFirstColumn'>&nbsp;&nbsp;</td>");

                    if (!subCategory.Selected) {
                        sb.append("<td align='left'>&nbsp;&nbsp;" + subCategory.Name + "</td>");

                        if (!subCategory.State || subCategory.State === "Current") {
                            sb.append("<td align='left' colspan='5'><a href='javascript:" + panelName + ".deleteSubCategory(" + subCategory.SubCategoryID + ");void(0);'>");
                            sb.append("<img src='images/delete.gif' alt='Delete SubCategory' border='0' /></a>");
                            sb.append("<a href='javascript:" + panelName + ".toggleSubCategoryEdit(" + subCategory.SubCategoryID + ");void(0);'>");
                            sb.append("<img src='images/table_edit.gif' alt='Edit SubCategory' border='0' /></a></td>");
                        }
                        else if (subCategory.State === "Adding" || subCategory.State === "Updating" || subCategory.State === "Deleting") {
                            sb.append("<td align='left' colspan='5'>");
                            sb.append("<img src='images/loading.gif' alt='loading' border='0' />...");
                            sb.append(subCategory.State + "</td>");
                        }
                        else if (subCategory.State === "AddFailed") {
                            sb.append("<td align='left' colspan='5'>");
                            sb.append("<a href='javascript:" + panelName + ".retryAddSubCategory(" + subCategory.SubCategoryID + ");void(0);'>");
                            sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Add</a></td>");
                        }
                        else if (subCategory.State === "UpdateFailed") {
                            sb.append("<td align='left' colspan='5'>");
                            sb.append("<a href='javascript:" + panelName + ".retryUpdateSubCategory(" + subCategory.SubCategoryID + ");void(0);'>");
                            sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Update</a></td>");
                        }
                        else if (subCategory.State === "DeleteFailed") {
                            sb.append("<td align='left' colspan='5'>");
                            sb.append("<a href='javascript:" + panelName + ".deleteSubCategory(" + subCategory.SubCategoryID + ");void(0);'>");
                            sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Delete</a></td>");
                        }
                    }
                    else {
                        sb.append("<td align='left'>&nbsp;&nbsp;<input type='text' id='" + panelName + "editSubCatName" + subCategory.SubCategoryID + "' class='defaultText' size='15' value='" + escapeQuote(subCategory.Name) + "' /></td>");
                        sb.append("<td align='left' colspan='5'><a href='javascript:" + panelName + ".updateSubCategory(" + subCategory.SubCategoryID + ");void(0);'>Update</a>&nbsp;<a href='javascript:" + panelName + ".toggleSubCategoryEdit(" + subCategory.SubCategoryID + ");void(0);'>Cancel</a></td>");
                    }

                    sb.append("<td align='center' class='blueTableLastColumn'>&nbsp;</td></tr>");
                }
            }

            sb.append("</tbody>");
        }

        sb.append("<tr class='blueTableFooterRow'><td class='blueTableBotLeftCorner'></td>");

        sb.append("<td>Total</td><td>&nbsp;</td>");
        if (categoryData) {
            sb.append("<td align='center'>" + categoryData.getTotalYearBudget() + "</td>");
            sb.append("<td align='center'>" + categoryData.getTotalMonthBudget() + "</td>");
            sb.append("<td align='center'>" + categoryData.getTotalWeekBudget() + "</td>");
        }
        else {
            sb.append("<td align='center'>0</td>");
            sb.append("<td align='center'>0</td>");
            sb.append("<td align='center'>0</td>");
        }
        
        sb.append("<td class='blueTableBotRightCorner' colspan='2'></td>");
        sb.append("</tr></table>");

        return sb.toString();

        //document.getElementById(panelName).innerHTML = sb.toString();
    };

    this.getRow = function(rowIndex)
    {
        return categoryArray[rowIndex];
    };
    
    this.getModifiedRow = function(categoryID)
    {
        var category = new Object();
        category.CategoryID = categoryID;
        category.Name = document.getElementById(panelName + "editCatName"+categoryID).value;
        category.Description = document.getElementById(panelName + "editCatDesc"+categoryID).value;

        category.YearBudget = document.getElementById(panelName + "editCatYearBudget"+categoryID).value;               
       
        category.MonthBudget = document.getElementById(panelName + "editCatMonthBudget"+categoryID).value;

        category.WeekBudget = document.getElementById(panelName + "editCatWeekBudget"+categoryID).value;                      

        if(categoryType === "Expense")
        {
            category.CategoryType = "E";
        }
        else if(categoryType === "Income")
        {
            category.CategoryType = "I";        
        }
      
        return category;    
    };
    
    
    this.getAddingCategory = function()
    {
        var category = new Object();
        category.Name = getFieldValue(panelName+"addCatName");   
        category.Description = getFieldValue(panelName+"addCatDesc");    

        category.YearBudget = getFieldValue(panelName+"addCatYearBudget");               
        category.MonthBudget = getFieldValue(panelName+"addCatMonthBudget");
        category.WeekBudget = getFieldValue(panelName+"addCatWeekBudget");
        
        if(categoryType === "Expense")
        {                        
            category.CategoryType = "E";                                     
        }
        else if(categoryType === "Income")
        {
            category.CategoryType = "I";
        }          
                
        return category;  
    };            
    
    this.getSubCategoryToggleIcon = function(clickIcon)
    {
        var icon = document.getElementById(clickIcon);
        if(icon)
        {
            return icon.innerHTML;
        }
        else
        {
            return "<img src='images/show.png' />";
        }
    }
            
    this.toggleSubCategories = function(tbodyID,clickIcon,categoryID) 
    {
        var category = categoryData.getCategoryByCategoryID(categoryID);        
        
        if (document.getElementById(clickIcon).innerHTML.match("images/show.png"))
        {
            category.SubCatTableOpen = true;
            document.getElementById(clickIcon).innerHTML = "<img src='images/hide.png' />";
            document.getElementById(tbodyID).style.display = "";            
        } 
        else 
        {
            category.SubCatTableOpen = false;
            document.getElementById(tbodyID).style.display = "none";
            document.getElementById(clickIcon).innerHTML = "<img src='images/show.png' />";
        }
    };
    
    this.getModifiedSubCategory = function(subCategoryID)
    {
        var subCategory = categoryData.getSubCategory(subCategoryID);
        subCategory.Name = getFieldValue(panelName+"editSubCatName" + subCategoryID);

        return subCategory;         
    };    
    
    this.getAddingSubCategory = function(categoryID)
    {
        var subCategory = new Object();
        subCategory.CategoryID = categoryID;
        subCategory.Name = getFieldValue(panelName+"addSubCatName" + categoryID);

        return subCategory;         
    };        
};/******************************* Expected Savings ****************************/

function ExpectedBalanceTableModule(displayDivName, expCatData, incomeCatData)
{    
    this.drawModule = function()
    {        
        var sb = new StringBuffer();        
        
        //ALTER Table Headers
        sb.append("<table class='fixedTable' width='570px' cellspacing='0' border='0' cellpadding='0'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='10px' class='blueTableTopLeftCorner'>&nbsp;</td>");            
        sb.append("<td width='215px' align='left'>&nbsp;&nbsp;</td>");    
        sb.append("<td width='115px' align='center'>Year</td>");
        sb.append("<td width='115px' align='center'>Month</td>");
        sb.append("<td width='115px' align='center' class='blueTableTopRightCorner'>Week</td></tr>");

        //Income Data
        sb.append("<tr class='blueTableOddRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");                        
        sb.append("<td align='left'>Expected Income</td>");
        sb.append("<td align='center'>" + incomeCatData.getTotalYearBudget() + "</td>");
        sb.append("<td align='center'>" + incomeCatData.getTotalMonthBudget() + "</td>");
        sb.append("<td align='center' class='blueTableLastColumn'>" + incomeCatData.getTotalWeekBudget() + "</td></tr>");

        //Expense Data
        sb.append("<tr class='blueTableEvenRow'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");                        
        sb.append("<td align='left'>Budgeted Expense Amount</td>");
        sb.append("<td align='center'>" + expCatData.getTotalYearBudget() + "</d>");
        sb.append("<td align='center'>" + expCatData.getTotalMonthBudget() + "</td>");
        sb.append("<td align='center' class='blueTableLastColumn'>" + expCatData.getTotalWeekBudget() + "</td></tr>");

        //Expected Savings
        sb.append("<tr class='blueTableFooterRow'>");
        sb.append("<td class='blueTableBotLeftCorner'></td>");
        sb.append("<td align='left'><b>Expected Balance Change</b></td>");
        sb.append("<td align='center'>" + roundAmount(incomeCatData.getTotalYearBudget() - expCatData.getTotalYearBudget()) + "</td>");
        sb.append("<td align='center'>" + roundAmount(incomeCatData.getTotalMonthBudget() - expCatData.getTotalMonthBudget()) + "</td>");
        sb.append("<td align='center' class='blueTableBotRightCorner'>" + roundAmount(incomeCatData.getTotalWeekBudget() - expCatData.getTotalWeekBudget()) + "</td></tr>");
        
        document.getElementById(displayDivName).innerHTML = sb.toString();
    };
}function SearchTransModule(panelName, categoryType)
{
    this.getTransSearch = function()
    {
        var transSearch = new Object();
        transSearch.CategoryType = categoryType;
        transSearch.StartDate = document.getElementById(panelName + "searchStartDate").value;
        if (isValidFormattedDate(transSearch.StartDate))
        {
            transSearch.StartDate = getDateStringFromFormattedDateString(transSearch.StartDate);
        }

        transSearch.EndDate = document.getElementById(panelName + "searchEndDate").value;
        if (isValidFormattedDate(transSearch.EndDate))
        {
            transSearch.EndDate = getDateStringFromFormattedDateString(transSearch.EndDate);
        }


        var categoryList = document.getElementById(panelName + "searchTransCategory");
        transSearch.CategoryId = categoryList.options[categoryList.selectedIndex].value;

        var amountList = document.getElementById(panelName + "searchTransAmountList");
        transSearch.AmountOperator = amountList.options[amountList.selectedIndex].value;
        transSearch.Amount = document.getElementById(panelName + "txtSearchTransAmount").value;

        return transSearch;
    };

    this.toHTML = function(categoryArray) 
    {
        var sb = new StringBuffer();
        var srchBtnTitle;
        if (categoryType === "Expense") 
        {
            srchBtnTitle = "Get Expenses";
        }
        else if (categoryType === "Income") 
        {
            srchBtnTitle = "Get Income";
        }

        var today = new Date();
        var lastMonth = today.getFullYear() + "-" + (today.getPriorMonth()+1) + "-" + today.getDate();

        
        //ALTER Table Headers
        sb.append("<table cellspacing='0' border='0' cellpadding='2' width='790px'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='600px' class='blueTableTopLeftCorner' colspan='2'>Parameters</td>");
        sb.append("<td width='190px' class='blueTableTopRightCorner'></td></tr>");

        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;<b>Date Range</b></td>");
        sb.append("<td align='left'><table cellpadding='0' cellspacing='0'><tr valign='bottom'><td>Start Date:&nbsp;</td><td><input type='text' size=9' class='defaultText' id='" + panelName + "searchStartDate' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' value='" + getFormattedDateString(lastMonth) + "'  /></td>");
        sb.append("<td>&nbsp;&nbsp;&nbsp;End Date:&nbsp;<input type='text' size=9' class='defaultText' id='" + panelName + "searchEndDate' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)'  value='" + getFormattedDateString() + "'/></td></tr></table></td>");
        sb.append("<td align='center' class='blueTableLastColumn' align='center'><input type='button' id='searchTransBtn' value='" + srchBtnTitle + "' onclick='javascript:" + panelName + ".searchTrans();void(0);' class='addButton' tabIndex='5'  style='width: 130px'></tr>");

        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td align='left' class='blueTableFirstColumn'>&nbsp;<b>Category</b></td>");
        sb.append("<td align='left' class='blueTableLastColumn' colspan='2'>");

        sb.append("<select id='" + panelName + "searchTransCategory' class='defaultText' STYLE='width: 150px'>");
        sb.append("<option value='Any'>All Categories</option>");

        //Fill in Drop Down Option Values For Categories
        var numCategories = categoryArray.length;
        for (i = 0; i < numCategories; i++) {
            var category = categoryArray[i];
            sb.append("<option value='");
            sb.append(category.CategoryID);
            sb.append("'>");
            sb.append(category.Name);
            sb.append("</option>");
        }

        sb.append("</select></td></tr>");


        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td align='left' class='blueTableFirstColumn'>&nbsp;<b>Amount</b></td>");
        sb.append("<td align='left' class='blueTableLastColumn' colspan='3'>");

        sb.append("<select id='" + panelName + "searchTransAmountList' class='defaultText' STYLE='width: 150px'>");
        sb.append("<option value='Any'>Any Amount</option>");
        sb.append("<option value='Equal'>Equal To</option>");
        sb.append("<option value='Greater'>Greater Than</option>");
        sb.append("<option value='Less'>Less Than</option>");
        sb.append("</select>&nbsp;");

        sb.append("<input type='text' id='" + panelName + "txtSearchTransAmount' class='defaultText' size='8' /></td></tr>");

        sb.append("<tr class='blueTableFooterRow'><td class='blueTableBotLeftCorner' colspan='1'></td><td class='blueTableBotRightCorner' colspan='3'></td>");
        sb.append("</tr></table>");

        return sb.toString();
    };
}function TransSummaryTableModule(panelName, catData, catType)
{
    var panelName = panelName;
    var categoryArray;

    if (catData) 
    {
        categoryArray = catData.getCategories();
    }
        
    function getRoundedAmount(amount)
    {
        if(!amount || amount === "")
        {
            return "0";
        }
        else
        {
            return roundAmount(amount);
        }
    }

    this.toHTML = function() {

        if (!catData) {
            return;
        }

        var sb = new StringBuffer();

        var numCategories;
        if (categoryArray) {
            numCategories = categoryArray.length;
        }
        else {
            numCategories = 0;
            return;
        }

        //ALTER Table Headers
        sb.append("<table class='fixedTable' width='805px' cellspacing='0' border='0' cellpadding='0'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='25px' class='blueTableTopLeftCorner'>&nbsp;</td>");
        sb.append("<td width='210px' align='left'>Category</td>");
        sb.append("<td width='115px' align='center'>This Year</td>");
        sb.append("<td width='115px' align='center'>Last Month</td>");
        sb.append("<td width='115px' align='center'>This Month</td>");
        sb.append("<td width='115px' align='center'>Last Week</td>");
        sb.append("<td width='110px' align='center' class='blueTableTopRightCorner'>This Week</td></tr>");

        for (i = 0; i < numCategories; i++) {
            var style = (i % 2 === 0) ? 'blueTableEvenRow' : 'blueTableOddRow';
            var category = categoryArray[i];

            var yearColumnStyle = (category.YearBudget && (category.YearAmount * 1 > category.YearBudget * 1)) ? 'overAmountColumn' : 'default';
            var priorMonthColumnStyle = (category.MonthBudget && (category.PriorMonthAmount * 1 > category.MonthBudget * 1)) ? 'overAmountColumn' : 'default';
            var monthColumnStyle = (category.MonthBudget && (category.MonthAmount * 1 > category.MonthBudget * 1)) ? 'overAmountColumn' : 'default';
            var priorWeekColumnStyle = (category.WeekBudget && (category.PriorWeekAmount * 1 > category.WeekBudget * 1)) ? 'overAmountColumn' : 'default';
            var weekColumnStyle = (category.WeekBudget && (category.WeekAmount * 1 > category.WeekBudget * 1)) ? 'overAmountColumn' : 'default';

            sb.append("<tr class='" + style + "'>");

            if (category.SubCategories && category.SubCategories.length > 0) {
                if (category.SubCatDisplayed) {
                    sb.append("<td class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "Row" + i + "','" + panelName + "ClickIcon" + i + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + i + "\" style=\"cursor: pointer; cursor: hand;\"><img src='images/hide.png' /></td>");
                }
                else {
                    sb.append("<td class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "Row" + i + "','" + panelName + "ClickIcon" + i + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + i + "\" style=\"cursor: pointer; cursor: hand;\"><img src='images/show.png' /></td>");
                }
            }
            else {
                sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");
            }

            sb.append("<td align='left'>" + category.Name + "</td>");
            sb.append("<td align='center' class='" + yearColumnStyle + "'>" + getRoundedAmount(category.YearAmount) + "</td>");
            sb.append("<td align='center' class='" + priorMonthColumnStyle + "'>" + getRoundedAmount(category.PriorMonthAmount) + "</td>");
            sb.append("<td align='center' class='" + monthColumnStyle + "'>" + getRoundedAmount(category.MonthAmount) + "</td>");
            sb.append("<td align='center' class='" + priorWeekColumnStyle + "'>" + getRoundedAmount(category.PriorWeekAmount) + "</td>");
            sb.append("<td align='center' class='blueTableLastColumn " + weekColumnStyle + "'>" + getRoundedAmount(category.WeekAmount) + "</td>");
            sb.append("</tr>");

            if (category.SubCategories && category.SubCategories.length > 0) {
                var numSubCategories = category.SubCategories.length;
                if (category.SubCatDisplayed) {
                    sb.append("<tbody id=\"" + panelName + "Row" + i + "\">");
                }
                else {
                    sb.append("<tbody id=\"" + panelName + "Row" + i + "\" style=\"display:none\">");
                }

                for (var j = 0; j < numSubCategories; j++) {
                    var subCategory = category.SubCategories[j];
                    sb.append("<tr class='" + style + "'><td class='blueTableFirstColumn'>&nbsp;&nbsp;</td>");
                    sb.append("<td align='left'>&nbsp;&nbsp;" + subCategory.Name + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.YearAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.PriorMonthAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.MonthAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.PriorWeekAmount) + "</td>");
                    sb.append("<td align='center' class='blueTableLastColumn'>" + getRoundedAmount(subCategory.WeekAmount) + "</td>");
                }

                sb.append("</tr></tbody>");
            }
        }

        var totalYearStyle = ((catType === "Expense") && catData.getTotalYearBudget() && (catData.getTotalYearAmount() * 1 > catData.getTotalYearBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalPriorMonthStyle = ((catType === "Expense") && catData.getTotalMonthBudget() && (catData.getTotalPriorMonthAmount() * 1 > catData.getTotalMonthBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalMonthStyle = ((catType === "Expense") && catData.getTotalMonthBudget() && (catData.getTotalMonthAmount() * 1 > catData.getTotalMonthBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalPriorWeekStyle = ((catType === "Expense") && catData.getTotalWeekBudget() && (catData.getTotalPriorWeekAmount() * 1 > catData.getTotalWeekBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalWeekStyle = ((catType === "Expense") && catData.getTotalWeekBudget() && (catData.getTotalWeekAmount() * 1 > catData.getTotalWeekBudget() * 1)) ? 'overAmountColumn' : 'default';

        sb.append("<tr class='blueTableFooterRow'>");
        sb.append("<td class='blueTableBotLeftCorner'></td>");
        sb.append("<td align='left'>Total</td>");
        sb.append("<td align='center' class='" + totalYearStyle + "'>" + getRoundedAmount(catData.getTotalYearAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalPriorMonthStyle + "'>" + getRoundedAmount(catData.getTotalPriorMonthAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalMonthStyle + "'>" + getRoundedAmount(catData.getTotalMonthAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalPriorWeekStyle + "'>" + getRoundedAmount(catData.getTotalPriorWeekAmount()) + "</td>");
        sb.append("<td  align='center' class='blueTableBotRightCorner " + totalWeekStyle + "'>" + getRoundedAmount(catData.getTotalWeekAmount()) + "</td></tr>");
        sb.append("</table>");

        return sb.toString();
    };
    
    this.toggleSubCategories = function(tbodyID,clickIcon,categoryID) 
    {
        var category = catData.getCategoryByCategoryID(categoryID);
        
        if (document.getElementById(clickIcon).innerHTML.match("images/show.png"))
        {
            category.SubCatDisplayed = true;
            document.getElementById(tbodyID).style.display = "";
            document.getElementById(clickIcon).innerHTML = "<img src='images/hide.png' />";
        } 
        else 
        {
            category.SubCatDisplayed = false;
            document.getElementById(tbodyID).style.display = "none";
            document.getElementById(clickIcon).innerHTML = "<img src='images/show.png' />";
        }
    }
}function SearchTransModule(panelName, categoryType)
{
    this.getTransSearch = function()
    {
        var transSearch = new Object();
        transSearch.CategoryType = categoryType;
        transSearch.StartDate = document.getElementById(panelName + "searchStartDate").value;
        if (isValidFormattedDate(transSearch.StartDate))
        {
            transSearch.StartDate = getDateStringFromFormattedDateString(transSearch.StartDate);
        }

        transSearch.EndDate = document.getElementById(panelName + "searchEndDate").value;
        if (isValidFormattedDate(transSearch.EndDate))
        {
            transSearch.EndDate = getDateStringFromFormattedDateString(transSearch.EndDate);
        }


        var categoryList = document.getElementById(panelName + "searchTransCategory");
        transSearch.CategoryId = categoryList.options[categoryList.selectedIndex].value;

        var amountList = document.getElementById(panelName + "searchTransAmountList");
        transSearch.AmountOperator = amountList.options[amountList.selectedIndex].value;
        transSearch.Amount = document.getElementById(panelName + "txtSearchTransAmount").value;

        return transSearch;
    };

    this.toHTML = function(categoryArray) 
    {
        var sb = new StringBuffer();
        var srchBtnTitle;
        if (categoryType === "Expense") 
        {
            srchBtnTitle = "Get Expenses";
        }
        else if (categoryType === "Income") 
        {
            srchBtnTitle = "Get Income";
        }

        var today = new Date();
        var lastMonth = today.getFullYear() + "-" + (today.getPriorMonth()+1) + "-" + today.getDate();

        
        //ALTER Table Headers
        sb.append("<table cellspacing='0' border='0' cellpadding='2' width='790px'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='600px' class='blueTableTopLeftCorner' colspan='2'>Parameters</td>");
        sb.append("<td width='190px' class='blueTableTopRightCorner'></td></tr>");

        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td class='blueTableFirstColumn'>&nbsp;<b>Date Range</b></td>");
        sb.append("<td align='left'><table cellpadding='0' cellspacing='0'><tr valign='bottom'><td>Start Date:&nbsp;</td><td><input type='text' size=9' class='defaultText' id='" + panelName + "searchStartDate' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' value='" + getFormattedDateString(lastMonth) + "'  /></td>");
        sb.append("<td>&nbsp;&nbsp;&nbsp;End Date:&nbsp;<input type='text' size=9' class='defaultText' id='" + panelName + "searchEndDate' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)'  value='" + getFormattedDateString() + "'/></td></tr></table></td>");
        sb.append("<td align='center' class='blueTableLastColumn' align='center'><input type='button' id='searchTransBtn' value='" + srchBtnTitle + "' onclick='javascript:" + panelName + ".searchTrans();void(0);' class='addButton' tabIndex='5'  style='width: 130px'></tr>");

        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td align='left' class='blueTableFirstColumn'>&nbsp;<b>Category</b></td>");
        sb.append("<td align='left' class='blueTableLastColumn' colspan='2'>");

        sb.append("<select id='" + panelName + "searchTransCategory' class='defaultText' STYLE='width: 150px'>");
        sb.append("<option value='Any'>All Categories</option>");

        //Fill in Drop Down Option Values For Categories
        var numCategories = categoryArray.length;
        for (i = 0; i < numCategories; i++) {
            var category = categoryArray[i];
            sb.append("<option value='");
            sb.append(category.CategoryID);
            sb.append("'>");
            sb.append(category.Name);
            sb.append("</option>");
        }

        sb.append("</select></td></tr>");


        sb.append("<tr style='background: #E7EFFF'>");
        sb.append("<td align='left' class='blueTableFirstColumn'>&nbsp;<b>Amount</b></td>");
        sb.append("<td align='left' class='blueTableLastColumn' colspan='3'>");

        sb.append("<select id='" + panelName + "searchTransAmountList' class='defaultText' STYLE='width: 150px'>");
        sb.append("<option value='Any'>Any Amount</option>");
        sb.append("<option value='Equal'>Equal To</option>");
        sb.append("<option value='Greater'>Greater Than</option>");
        sb.append("<option value='Less'>Less Than</option>");
        sb.append("</select>&nbsp;");

        sb.append("<input type='text' id='" + panelName + "txtSearchTransAmount' class='defaultText' size='8' /></td></tr>");

        sb.append("<tr class='blueTableFooterRow'><td class='blueTableBotLeftCorner' colspan='1'></td><td class='blueTableBotRightCorner' colspan='3'></td>");
        sb.append("</tr></table>");

        return sb.toString();
    };
}function TransSummaryTableModule(panelName, catData, catType)
{
    var panelName = panelName;
    var categoryArray;

    if (catData) 
    {
        categoryArray = catData.getCategories();
    }
        
    function getRoundedAmount(amount)
    {
        if(!amount || amount === "")
        {
            return "0";
        }
        else
        {
            return roundAmount(amount);
        }
    }

    this.toHTML = function() {

        if (!catData) {
            return;
        }

        var sb = new StringBuffer();

        var numCategories;
        if (categoryArray) {
            numCategories = categoryArray.length;
        }
        else {
            numCategories = 0;
            return;
        }

        //ALTER Table Headers
        sb.append("<table class='fixedTable' width='805px' cellspacing='0' border='0' cellpadding='0'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='25px' class='blueTableTopLeftCorner'>&nbsp;</td>");
        sb.append("<td width='210px' align='left'>Category</td>");
        sb.append("<td width='115px' align='center'>This Year</td>");
        sb.append("<td width='115px' align='center'>Last Month</td>");
        sb.append("<td width='115px' align='center'>This Month</td>");
        sb.append("<td width='115px' align='center'>Last Week</td>");
        sb.append("<td width='110px' align='center' class='blueTableTopRightCorner'>This Week</td></tr>");

        for (i = 0; i < numCategories; i++) {
            var style = (i % 2 === 0) ? 'blueTableEvenRow' : 'blueTableOddRow';
            var category = categoryArray[i];

            var yearColumnStyle = (category.YearBudget && (category.YearAmount * 1 > category.YearBudget * 1)) ? 'overAmountColumn' : 'default';
            var priorMonthColumnStyle = (category.MonthBudget && (category.PriorMonthAmount * 1 > category.MonthBudget * 1)) ? 'overAmountColumn' : 'default';
            var monthColumnStyle = (category.MonthBudget && (category.MonthAmount * 1 > category.MonthBudget * 1)) ? 'overAmountColumn' : 'default';
            var priorWeekColumnStyle = (category.WeekBudget && (category.PriorWeekAmount * 1 > category.WeekBudget * 1)) ? 'overAmountColumn' : 'default';
            var weekColumnStyle = (category.WeekBudget && (category.WeekAmount * 1 > category.WeekBudget * 1)) ? 'overAmountColumn' : 'default';

            sb.append("<tr class='" + style + "'>");

            if (category.SubCategories && category.SubCategories.length > 0) {
                if (category.SubCatDisplayed) {
                    sb.append("<td class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "Row" + i + "','" + panelName + "ClickIcon" + i + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + i + "\" style=\"cursor: pointer; cursor: hand;\"><img src='images/hide.png' /></td>");
                }
                else {
                    sb.append("<td class='blueTableFirstColumn' align=\"center\" onclick=\"" + panelName + ".toggleSubCategories('" + panelName + "Row" + i + "','" + panelName + "ClickIcon" + i + "'," + category.CategoryID + ")\" id=\"" + panelName + "ClickIcon" + i + "\" style=\"cursor: pointer; cursor: hand;\"><img src='images/show.png' /></td>");
                }
            }
            else {
                sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");
            }

            sb.append("<td align='left'>" + category.Name + "</td>");
            sb.append("<td align='center' class='" + yearColumnStyle + "'>" + getRoundedAmount(category.YearAmount) + "</td>");
            sb.append("<td align='center' class='" + priorMonthColumnStyle + "'>" + getRoundedAmount(category.PriorMonthAmount) + "</td>");
            sb.append("<td align='center' class='" + monthColumnStyle + "'>" + getRoundedAmount(category.MonthAmount) + "</td>");
            sb.append("<td align='center' class='" + priorWeekColumnStyle + "'>" + getRoundedAmount(category.PriorWeekAmount) + "</td>");
            sb.append("<td align='center' class='blueTableLastColumn " + weekColumnStyle + "'>" + getRoundedAmount(category.WeekAmount) + "</td>");
            sb.append("</tr>");

            if (category.SubCategories && category.SubCategories.length > 0) {
                var numSubCategories = category.SubCategories.length;
                if (category.SubCatDisplayed) {
                    sb.append("<tbody id=\"" + panelName + "Row" + i + "\">");
                }
                else {
                    sb.append("<tbody id=\"" + panelName + "Row" + i + "\" style=\"display:none\">");
                }

                for (var j = 0; j < numSubCategories; j++) {
                    var subCategory = category.SubCategories[j];
                    sb.append("<tr class='" + style + "'><td class='blueTableFirstColumn'>&nbsp;&nbsp;</td>");
                    sb.append("<td align='left'>&nbsp;&nbsp;" + subCategory.Name + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.YearAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.PriorMonthAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.MonthAmount) + "</td>");
                    sb.append("<td align='center'>" + getRoundedAmount(subCategory.PriorWeekAmount) + "</td>");
                    sb.append("<td align='center' class='blueTableLastColumn'>" + getRoundedAmount(subCategory.WeekAmount) + "</td>");
                }

                sb.append("</tr></tbody>");
            }
        }

        var totalYearStyle = ((catType === "Expense") && catData.getTotalYearBudget() && (catData.getTotalYearAmount() * 1 > catData.getTotalYearBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalPriorMonthStyle = ((catType === "Expense") && catData.getTotalMonthBudget() && (catData.getTotalPriorMonthAmount() * 1 > catData.getTotalMonthBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalMonthStyle = ((catType === "Expense") && catData.getTotalMonthBudget() && (catData.getTotalMonthAmount() * 1 > catData.getTotalMonthBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalPriorWeekStyle = ((catType === "Expense") && catData.getTotalWeekBudget() && (catData.getTotalPriorWeekAmount() * 1 > catData.getTotalWeekBudget() * 1)) ? 'overAmountColumn' : 'default';
        var totalWeekStyle = ((catType === "Expense") && catData.getTotalWeekBudget() && (catData.getTotalWeekAmount() * 1 > catData.getTotalWeekBudget() * 1)) ? 'overAmountColumn' : 'default';

        sb.append("<tr class='blueTableFooterRow'>");
        sb.append("<td class='blueTableBotLeftCorner'></td>");
        sb.append("<td align='left'>Total</td>");
        sb.append("<td align='center' class='" + totalYearStyle + "'>" + getRoundedAmount(catData.getTotalYearAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalPriorMonthStyle + "'>" + getRoundedAmount(catData.getTotalPriorMonthAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalMonthStyle + "'>" + getRoundedAmount(catData.getTotalMonthAmount()) + "</td>");
        sb.append("<td align='center' class='" + totalPriorWeekStyle + "'>" + getRoundedAmount(catData.getTotalPriorWeekAmount()) + "</td>");
        sb.append("<td  align='center' class='blueTableBotRightCorner " + totalWeekStyle + "'>" + getRoundedAmount(catData.getTotalWeekAmount()) + "</td></tr>");
        sb.append("</table>");

        return sb.toString();
    };
    
    this.toggleSubCategories = function(tbodyID,clickIcon,categoryID) 
    {
        var category = catData.getCategoryByCategoryID(categoryID);
        
        if (document.getElementById(clickIcon).innerHTML.match("images/show.png"))
        {
            category.SubCatDisplayed = true;
            document.getElementById(tbodyID).style.display = "";
            document.getElementById(clickIcon).innerHTML = "<img src='images/hide.png' />";
        } 
        else 
        {
            category.SubCatDisplayed = false;
            document.getElementById(tbodyID).style.display = "none";
            document.getElementById(clickIcon).innerHTML = "<img src='images/show.png' />";
        }
    }
}function TransTableModule(panelName, transData, catData, numToDisplay, fixedHeight)
{
    var categoryArray;

    if (catData) 
    {
        categoryArray = catData.getCategories();
    }
    
    //Retrieves the Data in the row form fields for the specified transID    
    this.getCurrentRowData = function(transID)
    {
        var trans = new Object();
        trans.TransID = transID;

        trans.Amount = roundAmount(getFieldValue(panelName + transID + "EditRowAmount"));
        trans.Description = getFieldValue(panelName + transID + "EditRowComments");
        trans.Date = getDateStringFromFormattedDateString(getFieldValue(panelName + transID + "EditRowDate"));

        var categoryList = document.getElementById(panelName + transID + "EditRowCatList");
        
        var selectedIDs = categoryList.options[categoryList.selectedIndex].value.split(":");

        trans.CategoryID = selectedIDs[0];
        if(selectedIDs.length > 1)
        {
            trans.SubCategoryID = selectedIDs[1];                  
        }
                                    
        trans.CategoryName = categoryList.options[categoryList.selectedIndex].text;
        
        return trans;
    };
    

    //Redraws the table module
    this.toHTML = function(startPage) {

        if (!transData || !categoryArray) {
            return;
        }

        var tempTransArray = transData.getTransArray().slice(0);
        tempTransArray = tempTransArray.reverse();

        var numItems = tempTransArray.length;

        var numCategories = categoryArray.length;

        var sb = new StringBuffer();
        var startItem = numItems - (numToDisplay * (startPage - 1));

        //Determine the Last Item to display
        var endItem = startItem - numToDisplay;

        //If there are less items then the numToDisplay, set
        //lastIndexOnPage to 0     
        if (endItem < 1) {
            endItem = 0;
        }

        //ALTER Table Headers
        sb.append("<table id='" + panelName + "_transTable' class='fixedTable' cellspacing='0' border='0' cellpadding='0' width='720px'>");
        sb.append("<tr class='blueTableHeaderRow'>");
        sb.append("<td width='10px' class='blueTableTopLeftCorner'></td>");
        sb.append("<td width='170px' align='left'><a href='javascript:" + panelName + ".sortTransTableByColumn(\"Category\"," + startPage + ")'>Category</a></td>");
        sb.append("<td width='110px' align='left'><a href='javascript:" + panelName + ".sortTransTableByColumn(\"Date\"," + startPage + ")'>Date</a></td>");
        sb.append("<td width='100px' align='left'><a href='javascript:" + panelName + ".sortTransTableByColumn(\"Amount\"," + startPage + ")'>Amount</a></td>");
        sb.append("<td width='205px' align='left'><a href='javascript:" + panelName + ".sortTransTableByColumn(\"Description\"," + startPage + ")'>Comment</a></td>");
        sb.append("<td width='115px'></td>");
        sb.append("<td width='10px' class='blueTableTopRightCorner'></td>");
        sb.append("</tr>");

        for (var i = startItem; i > endItem; i--) {
            var style = (i % 2 === 0) ? 'blueTableEvenRow' : 'blueTableOddRow';
            var transIndex = i - 1;
            var trans = tempTransArray[transIndex];

            sb.append("<tr align='left' id='" + panelName + "_transTable_" + transIndex + "' class='" + style + "'>");
            sb.append("<td class='blueTableFirstColumn'>&nbsp;</td>");

            if (trans.Selected) {
                sb.append("<td><select STYLE='width: 160px' id='");
                sb.append(panelName + trans.TransID + "EditRowCatList");
                sb.append("' class='defaultText' tabIndex='0'>");

                var selectedCategory;
                for (var j = 0; j < numCategories; j++) {
                    //Fill in Drop Down Option Values in HTML FORM
                    var category = categoryArray[j];

                    sb.append("<option value='");
                    sb.append(category.CategoryID + "'");

                    if ((category.CategoryID == trans.CategoryID) && !trans.SubCategoryID) {
                        sb.append(" selected ");
                        selectedCategory = category;
                    }

                    sb.append(">");
                    sb.append(catData.getCategoryName(category.CategoryID));
                    sb.append("</option>");

                    if (category.SubCategories) {
                        var numSubCategories = category.SubCategories.length;
                        for (subCatIndex = 0; subCatIndex < numSubCategories; subCatIndex++) {
                            var subCategory = category.SubCategories[subCatIndex];

                            sb.append("<option value='");
                            sb.append(category.CategoryID + ":" + subCategory.SubCategoryID);
                            sb.append("' ");

                            if ((category.CategoryID == trans.CategoryID) && (subCategory.SubCategoryID == trans.SubCategoryID)) {
                                sb.append(" selected ");
                            }

                            sb.append(">&nbsp;");
                            sb.append(category.Name + " - " + subCategory.Name);
                            sb.append("</option>");
                        }
                    }
                }

                sb.append("</select></td>");

                sb.append("<td><input type='text' size='9' id='" + panelName + trans.TransID + "EditRowDate' class='defaultText' tabindex='2' value='" + getFormattedDateString(trans.Date) + "' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' /></td>");
                sb.append("<td><input id='" + panelName + trans.TransID + "EditRowAmount' class='defaultText' size='10' value='" + getRoundedAmount(trans.Amount) + "' /></td>");
                sb.append("<td><input id='" + panelName + trans.TransID + "EditRowComments' class='defaultText' size='30' value='" + trans.Description + "' /></td>");
                sb.append("<td align='right'><a href='javascript:" + panelName + ".updateTrans(" + trans.TransID + "," + startPage + ");void(0);'>Update</a>&nbsp;<a href='javascript:" + panelName + ".toggleTransSelect(" + trans.TransID + "," + startPage + ");void(0);'>Cancel</a></td>");
            }
            else {
                var transCategoryName = catData.getCategoryName(trans.CategoryID);
                if (trans.SubCategoryID) {
                    transCategoryName = transCategoryName + " - " + catData.getSubCategoryName(trans.SubCategoryID);
                }

                sb.append("<td align='left'>" + transCategoryName + "</td>");
                sb.append("<td align='left'>" + getFormattedDateString(trans.Date) + "</td>");
                sb.append("<td align='left'>" + getRoundedAmount(trans.Amount) + "</td>");
                sb.append("<td align='left'>" + trans.Description + "</td>");

                if (trans.State == "" || trans.State === "Current") {
                    sb.append("<td align='right'><a href='javascript:" + panelName + ".deleteTrans(" + trans.TransID + "," + startPage + ");void(0);'>");
                    sb.append("<img src='images/delete.gif' alt='Delete' border='0' /></a>");
                    sb.append("<a href='javascript:" + panelName + ".toggleTransSelect(" + trans.TransID + "," + startPage + ");void(0);'>");
                    sb.append("<img src='images/table_edit.gif' alt='Edit' border='0' /></a></td>");
                }
                else if (trans.State === "Adding" || trans.State === "Updating" || trans.State === "Deleting") {
                    sb.append("<td align='right'>");
                    sb.append("<img src='images/loading.gif' alt='loading' border='0' />...");
                    sb.append(trans.State + "</td>");
                }
                else if (trans.State === "AddFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".retryAddTrans(" + trans.TransID + "," + startPage + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Add</a></td>");
                }
                else if (trans.State === "UpdateFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".retryUpdateTrans(" + trans.TransID + "," + startPage + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Update</a></td>");
                }
                else if (trans.State === "DeleteFailed") {
                    sb.append("<td align='right'>");
                    sb.append("<a href='javascript:" + panelName + ".deleteTrans(" + trans.TransID + "," + startPage + ");void(0);'>");
                    sb.append("<img src='images/error.gif' alt='loading' border='0' /> Retry Delete</a></td>");
                }
            }

            sb.append("<td class='blueTableLastColumn'>&nbsp;</td></tr>");
        }

        //If Specified Add Filler Rows to Ensure consistent Table size
        if (fixedHeight) {
            for (i = startItem - endItem; i < numToDisplay; i++) {
                sb.append("<tr class='blueTableEvenRow'><td  class='blueTableFirstColumn' colspan='4' style='height:16px'>&nbsp;</td><td  class='blueTableLastColumn' colspan='4'>&nbsp;</td></tr>");
            }
        }

        sb.append("<tr class='blueTableFooterRow'><td colspan='4' class='blueTableBotLeftCorner'></td><td colspan='4' align='right' class='blueTableBotRightCorner'>");

        var numPages = Math.ceil(numItems / numToDisplay);
        if (numPages > 1) {
            for (i = 1; i <= numPages; i++) {
                var pageNum;
                if (i == startPage) {
                    pageNum = "<b>" + i + "</b>";
                }
                else {
                    pageNum = i;
                }

                sb.append("<a href='javascript:" + panelName + ".drawRecentTransModule(" + i + ");void(0);'>" + pageNum + "</a>&nbsp;");
            }
        }

        sb.append("</td></tr></table>");

        return sb.toString();
    };    
}function BreakdownPieGraphPanel(panelName, transType)
{
    var graphData = "";
    
    //Displays all the modules in the panel
    this.drawPanel = function() 
    {
        document.getElementById("div_" + panelName).innerHTML = toHTML();
        this.drawPieChart();
    };
     
    //Returns the HTML string to dispaly this panel  
    function toHTML()
    {
        var sb = new StringBuffer();
        sb.append("<table cellspacing='2'>");
        sb.append("<tr><td class='panelHeader'>Expenses for: <select id='" + panelName + "_pieChartDefaultDateList' onchange='" + panelName + ".drawPieChart()'>");
        sb.append("<option selected value='All Time'>All Time</option>");
        sb.append("<option value='This Year'>This Year</option>");
        sb.append("<option value='Last Month'>Last Month</option>");
        sb.append("<option value='This Month'>This Month</option>");
        sb.append("<option value='Last Week'>Last Week</option>");
        sb.append("<option value='This Week'>This Week</option>");
        sb.append("<option value='Custom Date'>Custom Date</option>");                                    
        sb.append("</select></td><td>&nbsp;&nbsp;</td>");
        sb.append("<td id='" + panelName + "_pieOtherSelColumn' style='display: none'><table><tr>");
        sb.append("<td>Start Date</td>");
        sb.append("<td><input type='text' size='9' id='" + panelName + "_pieStartDate' class='defaultText' tabIndex='1' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' /></td>");
        sb.append("<td>End Date</td>");
        sb.append("<td><input type='text' size='9' id='" + panelName + "_pieEndDate' class='defaultText' tabIndex='2' onfocus='this.select();lcs(this)' onclick='event.cancelBubble=true;this.select();lcs(this)' /></td>");
        sb.append("<td><input type='button' id='" + panelName + "_pieSearchOtherButton' class='addButton' value='View Chart' onclick='" + panelName + ".drawOtherDatePieChart()'/></td>");
        sb.append("</tr></table></td></tr></table> <br />");

        sb.append("<div id='" + panelName + "_pieChartMsg'></div>");

        return sb.toString();
    };

    this.drawOtherDatePieChart = function()
    {
        var startDate = getDateFromFormattedDateString(getFieldValue(panelName + "_pieStartDate"));
        var endDate = getDateFromFormattedDateString(getFieldValue(panelName + "_pieEndDate"));

        //Display Loading Image
        document.getElementById(panelName + "_pieChartMsg").innerHTML = "Retrieving Data...<img src='images/loading.gif' />";

        jsonService.GetTransPieGraphForCustomDateRange(transType, startDate, endDate, function(response)
        {
            drawPieChart_CallBack(response);
        });

    };
    
    this.drawPieChart = function()
    {
        var defaultDateList = document.getElementById(panelName + "_pieChartDefaultDateList");
        if (defaultDateList)
        {
            var selectedDefaultDate = defaultDateList.options[defaultDateList.selectedIndex].value

            if (selectedDefaultDate == "Custom Date")
            {
                document.getElementById(panelName + "_pieChartMsg").innerHTML = "";
                document.getElementById(panelName + "_pieOtherSelColumn").style.display = "block";
            }
            else
            {
                document.getElementById(panelName + "_pieOtherSelColumn").style.display = "none";

                var userDate = new Date();

                //Display Loading Image
                document.getElementById(panelName + "_pieChartMsg").innerHTML = "Retrieving Data...<img src='images/loading.gif' />";

                jsonService.GetTransPieGraphForDefaultDateRange(selectedDefaultDate, transType, userDate, function(response)
                {
                    drawPieChart_CallBack(response);
                });
            }
        }
    };


    function drawPieChart_CallBack(response)
    {
    
        if (response.result == -1) 
        {
            document.getElementById(panelName + "_pieChartMsg").innerHTML = "<h2>Error ocurred while retrieving graph data.</h2>";
        }
        else if (response.result == 0) 
        {
            document.getElementById(panelName + "_pieChartMsg").innerHTML = "<h2>No Data found for Date Range</h2>";
        }
        else 
        {
            setGraphData(panelName, response.result);
            document.getElementById(panelName + "_pieChartMsg").innerHTML = "<div id='" + panelName + "_pieChart'></div>";
            swfobject.embedSWF("Flash/open-flash-chart.swf", panelName + "_pieChart", "650", "300", "9.0.0", "expressInstall.swf", { "get-data": "getGraphData", "id": panelName }, {"wmode":"transparent"});
        }
    };    
}function AddTransPanel(panelName, transType, recentTransData, transCategoryData)
{
    //Modules that are dsiplayed in this panel
    var addTransModule;
    var recentTransTable;
    var transSummaryTable;
    
    //Displays all the modules in the panel
    this.drawPanel = function() {
        if (!addTransModule) {

            //Create AddExpensePanel Modules
            addTransModule = new AddTransModule(panelName, transType, transCategoryData.getCategories());
            recentTransTable = new TransTableModule(panelName, recentTransData, transCategoryData, 5, true);
            transSummaryTable = new TransSummaryTableModule(panelName, transCategoryData, transType);
        }

        document.getElementById("div_" + panelName).innerHTML = toHTML();
    }
     
    //Returns the HTML string to dispaly this panel  
    function toHTML()
    {
        var sb = new StringBuffer();
        sb.append("<table cellpadding='0' cellspacing='0'><tr>");
        sb.append("<td valign='top' colspan='2' align='left'>");

        if (transType == "Expense")
        {
            sb.append("<span class='panelHeader'>Add Expenses</span><br />");
        }
        else
        {
            sb.append("<span class='panelHeader'>Add Income</span><br />");
        }

        //Draw Add Trans Module
        sb.append("<div id='" + panelName + "_AddTransModule'>");
        sb.append(addTransModule.toHTML());
        sb.append("</div>");

        sb.append("<br />&nbsp;&nbsp;<br />");

        if (transType == "Expense")
        {
            sb.append("<span class='panelHeader'>Recently Added Expenses</span>");
            sb.append("<i><font color='gray'>&nbsp;(Displays the last 25 added expenses.  Search Expenses to view more expenses.)</font></i>");
        }
        else
        {
            sb.append("<span class='panelHeader'>Recently Added Income</span>");
            sb.append("<i><font color='gray'>&nbsp;(Displays the last 25 added income records.  Search Income to view more records.)</font></i>");
        }

        //Get Recent Trans Module HTML
        sb.append("<div id='" + panelName + "_RecentTransTableModule'>");
        sb.append(recentTransTable.toHTML(1));
        sb.append("</div>");
        
        sb.append("<br />&nbsp;&nbsp;<br /></td></tr><tr>");
        sb.append("<td valign='top' colspan='2' align='left'>");

        if (transType == "Expense")
        {
            sb.append("<span class='panelHeader'>Expense Summary</span>");
            sb.append("<i><font color='gray'>&nbsp;(Displays total amount spent for each category. Any amounts over budget are highlighed in red.)</font></i>");
        }
        else
        {
            sb.append("<span class='panelHeader'>Income Summary</span>");
            sb.append("<i><font color='gray'>&nbsp;(Displays total amount spent for each category. Any amounts over budget are highlighed in red.)</font></i>");
        }

        //Append TransSummaryTable HTML
        sb.append("<div id='" + panelName + "_TransSummaryTableModule'>");        
        sb.append(transSummaryTable.toHTML());
        sb.append("</div>");

        sb.append("</td></tr></table>");

        return sb.toString();
    }

    //Redraws the AddTrans module in the panel
    function redrawAddTransModule()
    {
        document.getElementById(panelName + "_AddTransModule").innerHTML = addTransModule.toHTML();
    }

    //Redraws the RecentTrans module in the panel
    function redrawRecentTransTable(startPage)
    {
        var transTableString = recentTransTable.toHTML(startPage);
        document.getElementById(panelName + "_RecentTransTableModule").innerHTML = transTableString;
    }

    //Redraws the SummaryTrans module in the panel
    function redrawSummaryTransTable()
    {
        document.getElementById(panelName + "_TransSummaryTableModule").innerHTML = transSummaryTable.toHTML();
    }

    this.drawRecentTransModule = function(startPage)
    {
        redrawRecentTransTable(startPage);
    }

    this.addTrans = function()
    {
        var trans = addTransModule.getTrans();

        if (isValidTransForAdd(trans, transType))
        {
            //Add New Expense to recent expenses table and redraw
            trans.TransID = createGuid();
            trans.State = "Adding";
            recentTransData.addTrans(trans);

            var startPage = 1;
            redrawRecentTransTable(startPage);

            //Clear out Fields
            addTransModule.clearFields();

            //Create tempTrans object to pass to backend
            //Can't pass trans object directly because it contains
            //a generated guid for TransID 
            var tempTrans = new Object();
            tempTrans.CategoryID = trans.CategoryID;
            tempTrans.SubCategoryID = trans.SubCategoryID;
            tempTrans.Amount = trans.Amount;
            tempTrans.DisplayAmout = trans.DisplayAmount;
            tempTrans.Description = trans.Description;
            tempTrans.Date = trans.Date;

            //Call service to insert record
            jsonService.InsertTrans(tempTrans, function(response)
            {
                //set context variables
                response.context = new Object();
                response.context.startPage = startPage;
                response.context.addedTrans = trans;
                
                addTrans_CallBack(response);
            })
        }
    };

    this.retryAddTrans = function(transID, startPage)
    {
        var trans = recentTransData.getTransByTransID(transID);
        trans.State = "Adding";
        redrawRecentTransTable(startPage);

        //Create tempTrans object to pass to backend
        //Can't pass trans object directly because it contains
        //a generated guid for TransID 
        var tempTrans = new Object();
        tempTrans.CategoryID = trans.CategoryID;
        tempTrans.SubCategoryID = trans.SubCategoryID;
        tempTrans.Amount = trans.Amount;
        tempTrans.DisplayAmout = trans.DisplayAmount;
        tempTrans.Description = trans.Description;
        tempTrans.Date = trans.Date;

        jsonService.InsertTrans(tempTrans, function(response)
        {
            //set context variables
            response.context = new Object();            
            response.context.startPage = startPage;
            response.context.addedTrans = trans;

            addTrans_CallBack(response);
        })
    };

    function addTrans_CallBack(response)
    {
        var trans = response.context.addedTrans;

        var startPage = response.context.startPage;

        var resValue = response.result;

        if (resValue && resValue !== -1)
        {
            trans.TransID = resValue;
            trans.State = "Current";

            //Add new expense data to categories
            transCategoryData.addTrans(trans.CategoryID, trans.Amount, trans.Date, trans.SubCategoryID);
            redrawSummaryTransTable();
        }
        else
        {
            trans.State = "AddFailed";
            alert("Failed to add " + transType + " record. Unexpected error ocurred. Please retry");
        }

        redrawRecentTransTable(startPage);
    }

    function isValidTransForAdd(trans, transType)
    {
        if (!trans.Date)
        {
            alert("Cannot Add " + transType + ".  Invalid Date Specified.");
            return false;
        }

        if (!isValidAmount(trans.Amount))
        {
            alert("Cannot Add " + transType + ".  Invalid Amount Specified.");
            return false;
        }

        return true;
    }

    this.toggleTransSelect = function(transID, startPage)
    {
        var trans = recentTransData.getTransByTransID(transID);

        if (!trans.Selected)
        {
            trans.Selected = true;
        }
        else
        {
            trans.Selected = false;
        }

        redrawRecentTransTable(startPage);
    }

    this.sortTransTableByColumn = function(columnName, startPage)
    {
        //Sorts the TransData based on field name specified
        recentTransData.sortData(columnName);

        //Redraw the Recent Trans Table
        redrawRecentTransTable(startPage);
    }

    this.updateTrans = function(transID, startPage)
    {
        //Get Old Transaction to be deleted
        var updatingTrans = recentTransData.getTransByTransID(transID);
        updatingTrans.oldCategoryID = updatingTrans.CategoryID;
        updatingTrans.oldAmount = updatingTrans.Amount;
        updatingTrans.oldDate = updatingTrans.Date;
        updatingTrans.oldDescription = updatingTrans.Description;
        updatingTrans.oldSubCategoryID = updatingTrans.SubCategoryID;
        updatingTrans.oldCategoryName = updatingTrans.CategoryName;

        //Get New Transaction to be saved
        var newTrans = recentTransTable.getCurrentRowData(transID);
        updatingTrans.CategoryID = newTrans.CategoryID;
        updatingTrans.Amount = newTrans.Amount;
        updatingTrans.Date = newTrans.Date;
        updatingTrans.Description = newTrans.Description;
        updatingTrans.SubCategoryID = newTrans.SubCategoryID;
        updatingTrans.CategoryName = newTrans.CategoryName;

        if (isValidTransForUpdate(updatingTrans, transType))
        {
            internalUpdateTrans(startPage, updatingTrans);
        }
    };

    this.retryUpdateTrans = function(transID, startPage)
    {
        var updatingTrans = recentTransData.getTransByTransID(transID);

        internalUpdateTrans(startPage, updatingTrans);
    };

    function internalUpdateTrans(startPage, updatingTrans)
    {
        updatingTrans.Selected = false;
        updatingTrans.State = "Updating";

        redrawRecentTransTable(startPage);
        
        jsonService.UpdateTrans(updatingTrans, function(response)
        {
            response.context = new Object();
            response.context.updatingTrans = updatingTrans;
            response.context.startPage = startPage;

            updateTrans_CallBack(response);
        });
    }

    function updateTrans_CallBack(response)
    {
        var updatingTrans = response.context.updatingTrans;
        var startPage = response.context.startPage;

        var resValue = response.result;
        if (resValue && resValue !== -1)
        {
            //Update State
            updatingTrans.State = "Current";

            //Update CategoryData
            transCategoryData.deleteTrans(updatingTrans.oldCategoryID, updatingTrans.oldAmount, updatingTrans.oldDate, updatingTrans.oldSubCategoryID);
            transCategoryData.addTrans(updatingTrans.CategoryID, updatingTrans.Amount, updatingTrans.Date, updatingTrans.SubCategoryID);

            //Redraw SummaryTable
            redrawSummaryTransTable();
        }
        else
        {
            updatingTrans.State = "UpdateFailed";
            alert("Failed to update " + transType + " record. Unexpected error ocurred. Please retry");
        }

        //Redraw TransTableModule
        redrawRecentTransTable(startPage);
    }

    function isValidTransForUpdate(trans, transType)
    {
        if (!trans.Date)
        {
            alert("Cannot update " + transType + ".  Invalid Date Specified.");
            return false;
        }

        if (!isValidAmount(trans.Amount))
        {
            alert("Cannot update " + transType + ".  Invalid Amount Specified.");
            return false;
        }

        return true;
    }

    this.deleteTrans = function(transID, startPage)
    {
        var trans = recentTransData.getTransByTransID(transID);

        if (confirm("Are you sure you want to delete this " + transType + " record?\n--> " + trans.CategoryName + ": " + roundAmount(trans.Amount)))
        {
            //Redraw transTable to show trans being deleted
            trans.State = "Deleting";
            redrawRecentTransTable(startPage);

            jsonService.DeleteTrans(trans.TransID, function(response)
            {
                response.context = new Object();
                response.context.trans = trans;
                response.context.startPage = startPage;

                deleteTrans_CallBack(response);
            });
        }
    };

    function deleteTrans_CallBack(response)
    {
        var startPage = response.context.startPage;
        var trans = response.context.trans;

        var resValue = response.result;
        if (resValue && resValue !== -1)
        {
            //Delete from CategoryData        
            transCategoryData.deleteTrans(trans.CategoryID, trans.Amount, trans.Date, trans.SubCategoryID);

            //Delete from recent trans array
            recentTransData.deleteTransByTransID(trans.TransID);

            //Remove Transaction and redraw Recent Table
            redrawRecentTransTable(startPage);
            
            //Redraw SummaryTable
            redrawSummaryTransTable();
        }
        else
        {
            trans.State = "DeleteFailed";
            redrawRecentTransTable(startPage);

            alert("Failed to delete " + transType + " record. Unexpected error ocurred. Please retry");
        }
    };

    this.toggleSubCategories = function(tbodyid, ClickIcon, categoryID)
    {
        transSummaryTable.toggleSubCategories(tbodyid, ClickIcon, categoryID);
    }
     

}function EditCategoryPanel(panelName, categoryType, catTypeCatagoryData, recentTransData)
{
    var transCategoryTable;

    //Displays all the modules in the panel
    this.drawPanel = function()
    {
        if (!transCategoryTable)
        {
            //Create AddExpensePanel Modules
            transCategoryTable = new CategoryTableModule(panelName, catTypeCatagoryData, categoryType);        
        }

        document.getElementById("div_" + panelName).innerHTML = toHTML();
    }
    
    function toHTML()
    {
        var sb = new StringBuffer();
        if (categoryType === "Expense")
        {
            sb.append("<span class='panelHeader'>Expense Categories</span>");
            sb.append("&nbsp;<a href='#' onmouseout='hideTooltip();' onmouseover='showTooltip(this);' tipitle=\"Expense Categories allow you to track where you're spending your money. You can also specify a Yearly, Monthly or Weekly <i>Budget</i> for each category. Specifiying a <i>Budget</i> is opitonal, but it's useful a way to limit your spending and to forecast your potential savings.\"><img src='images/information.jpg' style='border: 0px' /></a>");
        }
        else
        {
            sb.append("<span class='panelHeader'>Income Categories</span>");
            sb.append("&nbsp;<a href='#' onmouseout='hideTooltip();' onmouseover='showTooltip(this);' tipitle=\"Income Categories allow you to track the sources of your income. You can also specify a Yearly, Monthly or Weekly <i>Amount</i> for each category to represent the amount you expect to receive for that period.  Specifiying an <i>Amount</i> is opitonal, but it is useful to forecast your potential balance.\"><img src='images/information.jpg' style='border: 0px' /></a>");        
        }
        
        sb.append("<div id='" + panelName + "_CategoryTableModule'>");
        sb.append(transCategoryTable.toHTML());
        sb.append("</div>");
        
        return sb.toString();
    }

    function redrawTransCategoryTable()
    {
        document.getElementById(panelName + "_CategoryTableModule").innerHTML = transCategoryTable.toHTML();
    }

    function isValidCategory(category, operation)
    {
        if(!category.Name || category.Name === "")
        {
            alert("Cannot " + operation + " Category.  Category Name was not specified");
            return false;
        }

        var catFieldDesc = "";
        if(category.CategoryType === "E") 
        { 
            catFieldDesc = "Budget"; 
        } 
        else 
        {
            catFieldDesc = "Amount";
        }
        
        if(category.yearBudget && !isValidAmount(category.yearBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Year" + catFieldDesc);
            return false;    
        }

        if(category.monthBudget && !isValidAmount(category.monthBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Month " + catFieldDesc);
            return false;    
        }

        if(category.weekBudget && !isValidAmount(category.weekBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Week  " + catFieldDesc);
            return false;    
        }
        
        return true;    
    }
    
    function isValidSubCategory(subCategory, operation)
    {
        if(!subCategory.Name || subCategory.Name === "")
        {
            alert("Cannot " + operation + " SubCategory.  SubCategory Name was not specified");
            return false;
        }
        
        return true;    
    }

    
    function getRandomColor()   
    {
        var array = new Array (   "f", "e", "d", "c", "b", "a", "9", "8", "7", "6", "5", "4", "3", "2", "1"   );  // array of possible hex values.
        var hexColor = "";  // this is the hex color that will be returned

        // and each time add a new character to the returned color.
        for(var i = 0; i < 6; i++)   
        {
            hexColor += array[Math.floor(Math.random() * array.length)];
        }

        return hexColor;
    };

    this.toggleSubCategories = function(tbodyID, clickIcon, categoryID)
    {
        transCategoryTable.toggleSubCategories(tbodyID, clickIcon, categoryID);
    }

    this.updateCategory = function(categoryID)
    {
        var modifiedCategory = transCategoryTable.getModifiedRow(categoryID);

        //Convert "" values to null before sending to server, otherwise it will cause a 
        //processing error
        if (modifiedCategory.YearBudget === "") { modifiedCategory.YearBudget = null; }
        if (modifiedCategory.MonthBudget === "") { modifiedCategory.MonthBudget = null; }
        if (modifiedCategory.WeekBudget === "") { modifiedCategory.WeekBudget = null; }

        if (isValidCategory(modifiedCategory, "update"))
        {
            //Redraw table to show that category is being updated
            var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);
            category.Selected = false;
            category.State = "Updating";
            redrawTransCategoryTable();

            jsonService.UpdateCategory(modifiedCategory, function(response)
            {
                response.context = new Object();
                response.context.modifiedCategory = modifiedCategory;
                updateCategory_CallBack(response);
            });
        }
    };
    
    function updateCategory_CallBack(response)
    {
        var modifiedCategory = response.context.modifiedCategory;
        var categoryID = modifiedCategory.CategoryID;
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            catTypeCatagoryData.updateCategory(categoryID, modifiedCategory);
            
            //Redraw Category Table to show that the update succeeded
            var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);                        
            category.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update failed
            var currentCategory = transCategoryTable.GetCategoryByCategoryID(categoryID);
            currentCategory.State = "UpdateFailed";
            redrawTransCategoryTable();
        }
    };
    
    this.toggleCategoryEdit = function(categoryID)
    {
        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);

        if(category.Selected)
        {
            category.Selected = false;            
        }
        else
        {
            category.Selected = true;    
        }

        redrawTransCategoryTable();
    }
    
    this.toggleSubCategoryEdit = function(subCategoryID)
    {
        var subCategory = catTypeCatagoryData.getSubCategory(subCategoryID);
        
        if(subCategory.Selected)
        {
            subCategory.Selected = false;            
        }
        else
        {
            subCategory.Selected = true;    
        }

        redrawTransCategoryTable();
    }

    this.addCategory = function() {
        var category = transCategoryTable.getAddingCategory();

        //Insert New Category onto database
        if (isValidCategory(category, "add")) {
            //Specify a color for the category
            category.Color = getRandomColor();
            category.CategoryID = createGuid();
            category.State = "Adding";

            if (!catTypeCatagoryData) {
                var categories = new Array();
                categories[0] = category;
                catTypeCatagoryData = new CategoryData(categories);
            }
            else {

                catTypeCatagoryData.addCategory(category);
            }
            
            //Redraw Category Table to display category being added
            redrawTransCategoryTable();

            //Create tempCategory object to pass to backend
            //Can't pass category object directly because it contains
            //a generated guid for CategoryID 
            var tempCategory = new Object();
            tempCategory.Name = category.Name;
            tempCategory.Color = category.Color;
            tempCategory.CategoryType = category.CategoryType;
            tempCategory.Description = category.Description;
            tempCategory.YearBudget = category.YearBudget;
            tempCategory.MonthBudget = category.MonthBudget;
            tempCategory.WeekBudget = category.WeekBudget;

            //Convert "" values to null to prevent any processing errors
            if (tempCategory.YearBudget == "") { tempCategory.YearBudget = null; }
            if (tempCategory.MonthBudget == "") { tempCategory.MonthBudget = null; }
            if (tempCategory.WeekBudget == "") { tempCategory.WeekBudget = null; }

            //Set CategoryID to null to avoid parsing error on server
            tempCategory.CategoryID = null;

            jsonService.InsertCategory(tempCategory, function(response) {
                response.context = new Object();
                response.context.guidCategoryID = category.CategoryID;
                addCategory_CallBack(response);
            })
        }
    };

    this.retryAddCategory = function(categoryID)
    {
        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);
        category.State = "Adding";
        
        //Redraw Category Table to display category being added
        redrawTransCategoryTable();

        //Create tempCategory object to pass to backend
        //Can't pass category object directly because it contains
        //a generated guid for CategoryID 
        var tempCategory = new Object();
        tempCategory.Name = category.Name;
        tempCategory.Color = category.Color;
        tempCategory.CategoryType = category.CategoryType;
        tempCategory.Description = category.Description;
        tempCategory.YearBudget = category.YearBudget;
        tempCategory.MonthBudget = category.MonthBudget;
        tempCategory.WeekBudget = category.WeekBudget;

        //Convert "" values to null to prevent any processing errors
        if (tempCategory.YearBudget == "") { tempCategory.YearBudget = null; }
        if (tempCategory.MonthBudget == "") { tempCategory.MonthBudget = null; }
        if (tempCategory.WeekBudget == "") { tempCategory.WeekBudget = null; }

        //Set CategoryID to null to avoid parsing error on server
        tempCategory.CategoryID = null;

        jsonService.InsertCategory(tempCategory, function(response)
        {
            response.context = new Object();
            response.context.guidCategoryID = category.CategoryID;
            addCategory_CallBack(response);
        })
    };
    

    
    function addCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {
            var category = catTypeCatagoryData.getCategoryByCategoryID(response.context.guidCategoryID);
            category.State = "Current";
            catTypeCatagoryData.changeCategoryID(response.context.guidCategoryID, response.result);

            //Redraw Category Table to show that the insert succeeded
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update succeeded
            var category = catTypeCatagoryData.getCategoryByCategoryID(response.context.guidCategoryID);

            category.State = "AddFailed";
            redrawTransCategoryTable();
        }        
    };

    this.deleteCategory = function(categoryID) {
        if (catTypeCatagoryData.getNumCategories() == 1) {
            alert("Cannot delete Category. At least on category is required to use the application");
            return;
        }

        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);

        var catTypeDesc;

        if (confirm("Are you sure you want to delete the " + category.Name + " category? \nDeleting this category will also delete ALL " + categoryType + " records for this category!")) {
            category.State = "Deleting";
            redrawTransCategoryTable();

            //Convert "" values to null before sending to server, otherwise it will cause a 
            //processing error
            if (category.YearBudget === "") { category.YearBudget = null; }
            if (category.MonthBudget === "") { category.MonthBudget = null; }
            if (category.WeekBudget === "") { category.WeekBudget = null; }

            jsonService.DeleteCategory(category.CategoryID, function(response) {
                response.context = new Object();
                response.context.deletingCategory = category;
                deleteCategory_CallBack(response);
            });
        }
    };
    
    function deleteCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {            
            var deletedCatID = response.context.deletingCategory.CategoryID;
            catTypeCatagoryData.deleteCategory(deletedCatID);

            redrawTransCategoryTable();
            
            if(recentTransData)
            {
                recentTransData.deleteAllTransInCategory(deletedCatID);
            }            
        }
        else
        {
            //Redraw Category Table to show that the update succeeded
            response.context.deletingCategory.Selected = false;            
            response.context.deletingCategory.State = "DeleteFailed";
            redrawTransCategoryTable();
        }      
    }
    
    this.updateSubCategory = function(subCategoryID)
    {
        var modifiedSubCategory = transCategoryTable.getModifiedSubCategory(subCategoryID);
                
        if(isValidSubCategory(modifiedSubCategory, "update"))
        {
            modifiedSubCategory.State = "Updating";
            redrawTransCategoryTable();
            
            jsonService.UpdateSubCategory(modifiedSubCategory, function(response) { 
                response.context = new Object();
                response.context.subCategoryID = modifiedSubCategory.SubCategoryID;            
                updateSubCategory_CallBack(response);
            });
        }                           
    };
    
    
    function updateSubCategory_CallBack(response)
    {
        var modifiedSubCategory = catTypeCatagoryData.getSubCategory(response.context.subCategoryID);
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Redraw Category Table to show that the update succeeded
            modifiedSubCategory.Selected = false;
            modifiedSubCategory.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update failed
            modifiedSubCategory.Selected = false;            
            modifiedSubCategory.State = "UpdateFailed";
            redrawTransCategoryTable();
        }
    };

    this.addSubCategory = function(categoryID)
    {
        var addingSubCategory = transCategoryTable.getAddingSubCategory(categoryID);
                        
        if(isValidSubCategory(addingSubCategory, "add"))
        {
            addingSubCategory.State = "Adding";
            addingSubCategory.Color = getRandomColor();

            //set temp SubCategoryID
            addingSubCategory.SubCategoryID = createGuid();            
            
            //add subCategory to catData
            catTypeCatagoryData.addSubCategory(categoryID, addingSubCategory);

            redrawTransCategoryTable();

            //Create a SubCategory object without the temp SubCategoryID to pass 
            //to the backend
            var newSubCategory = new Object();
            newSubCategory.SubCategoryID = null;
            newSubCategory.CategoryID = addingSubCategory.CategoryID;
            newSubCategory.Name = addingSubCategory.Name;
            newSubCategory.Color = addingSubCategory.Color;
            
            jsonService.InsertSubCategory(newSubCategory, function(response) { 
                response.context = new Object();
                response.context.tempSubCategoryID = addingSubCategory.SubCategoryID;            
                addSubCategory_CallBack(response);
            });
        }                           
    };    
    
    function addSubCategory_CallBack(response)
    {
        //Get SubCategory with the tempSubCategoryID
        var addedSubCategory = catTypeCatagoryData.getSubCategory(response.context.tempSubCategoryID);
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Update the SubCategory with the ID generated from the backend
            catTypeCatagoryData.changeSubCategoryID(response.context.tempSubCategoryID, resValue);
            
            //Redraw Category Table to show that the add succeeded
            addedSubCategory.Selected = false;
            addedSubCategory.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the add failed
            addedSubCategory.Selected = false;            
            addedSubCategory.State = "AddFailed";
            redrawTransCategoryTable();
        }
    };
      
      
    this.deleteSubCategory = function(subCategoryID) 
    {
        var subCategory = catTypeCatagoryData.getSubCategory(subCategoryID);
                
        if (confirm("Are you sure you want to delete the " + subCategory.Name +" sub-category? \nDeleting this category will also delete ALL " + categoryType + " records for this sub-category!")) 
        {   
            subCategory.State = "Deleting";
            redrawTransCategoryTable();
                                             
            jsonService.DeleteSubCategory(subCategoryID, function(response) { 
                response.context = new Object();
                response.context.deletingSubCategoryID = subCategoryID;            
                deleteSubCategory_CallBack(response);
            });
        }                                   
    };
    
    function deleteSubCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {   
            //Remove SubCategory from CategoryData       
            catTypeCatagoryData.deleteSubCategory(response.context.deletingSubCategoryID);

            //Remove recent transactions for the deleted subcategory
            if (recentTransData)
            {
                recentTransData.deleteAllTransInSubCategory(response.context.deletingSubCategoryID);
            }
            
            //Redraw CategoryTable to remove deleted sub-category
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw CategoryTable to show that the delete failed                       
            var subCategory = catTypeCatagoryData.getSubCategory(response.context.deletingSubCategoryID);
            subCategory.State = "DeleteFailed";
            redrawTransCategoryTable();
        }      
    }
    
};function SearchTransPanel(panelName, transType, transCatData, recentTransData)
{
    //data returned from the search parameters
    var searchTransData;
    
    //Modules in this panel
    var searchTransInputModule;
    var searchTransResultTable;
    
    //Displays all the modules in the panel
    this.drawPanel = function()
    {
        if (!searchTransInputModule)
        {
            searchTransInputModule = new SearchTransModule(panelName, transType);
        }

        document.getElementById("div_" + panelName).innerHTML = toHTML();
    }


    //Redraws the RecentTrans module in the panel
    this.drawRecentTransModule = function(startPage)
    {
        document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);
    }
    
    

    function toHTML()
    {
        var sb = new StringBuffer();
        sb.append("<table cellpadding='0' cellspacing='0'><tr><td>");
        
        if(transType == "Expense")
        {
            sb.append("<span class='panelHeader'>Search / Export Expenses</span>");
        }
        else
        {
            sb.append("<span class='panelHeader'>Search / Export Income</span>");        
        }
        
        sb.append("<i><font color='gray'>(Specify parameters to narrow what records to retrieve)</font></i>");

        sb.append(searchTransInputModule.toHTML(transCatData.getCategories()));
                
        sb.append("<br />");
                
        //Display Search Header
        sb.append("<div id='" + panelName + "_SearchResultsHeader'></div>");        
        
        //Display Search Results    
        sb.append("<div id='" + panelName + "_SearchResults'></div>");
        sb.append("</td></tr></table>");

        return sb.toString();
    }

    this.searchTrans = function() {
        var ts = searchTransInputModule.getTransSearch();
        jsonService.SearchTrans(ts.StartDate, ts.EndDate, ts.CategoryType, ts.CategoryId, ts.AmountOperator, ts.Amount,
            function(response) {
                searchTrans_CallBack(response);
            });

        //Display Search Header
        var searchHeaderString;
        if (transType == "Expense") 
        {
            searchHeaderString = "&nbsp;&nbsp;<table cellpadding='1' cellspacing='0'><tr><td valign='bottom'><span class='panelHeader'>Search Results</span>&nbsp;&nbsp;</td><td valign='bottom'><img src='images/page_excel.png' style='border-style: none'/></td><td><a href='generateReport.aspx?catType=Expense&startDate=" + ts.StartDate + "&endDate=" + ts.EndDate + "&catId=" + ts.CategoryId + "&amountOper=" + ts.AmountOperator + "&amount=" + ts.Amount + "'>Export Expense Records</a></td></tr></table>";
        }
        else 
        {
            searchHeaderString = "&nbsp;&nbsp;<table cellpadding='1' cellspacing='0'><tr><td valign='bottom'><span class='panelHeader'>Search Results</span>&nbsp;&nbsp;</td><td valign='bottom'><img src='images/page_excel.png' style='border-style: none'/></td><td><a href='generateReport.aspx?catType=Income&startDate=" + ts.StartDate + "&endDate=" + ts.EndDate + "&catId=" + ts.CategoryId + "&amountOper=" + ts.AmountOperator + "&amount=" + ts.Amount + "'>Export Income Records</a></td></tr></table>";
        }
        
        document.getElementById(panelName + "_SearchResultsHeader").innerHTML = searchHeaderString;

        //Display Loading Element        
        document.getElementById(panelName + "_SearchResults").innerHTML = "Searching...<img src='images/loading.gif' />";
    }

    function searchTrans_CallBack(response)
    {
        var resValue = response.result;

        if (resValue)
        {
            if (resValue == 0)
            {
                //Display No Data Found
                document.getElementById(panelName + "_SearchResults").innerHTML = "<h2>No Data found for Date Range</h2>"; ;            
            }
            else if (resValue == -1)
            {
                //Display No Data Found
                document.getElementById(panelName + "_SearchResults").innerHTML = "<h2>Error ocurred while searching for transactions.</h2>"; ;            
            }
            else
            {
                var searchResponseArray = JSON.parse(resValue);
                searchTransData = new TransData(searchResponseArray);

                searchTransResultTable = new TransTableModule(panelName, searchTransData, transCatData, 25, true);

                //Display Search Results
                document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(1);
            }
        }
    }

    this.toggleTransSelect = function(transID, startPage)
    {
        var trans = searchTransData.getTransByTransID(transID);

        if (!trans.Selected)
        {
            trans.Selected = true;
        }
        else
        {
            trans.Selected = false;
        }

        //Redraw the Search Trans Table
        document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);
    }

    this.sortTransTableByColumn = function(columnName, startPage)
    {
        //Sorts the TransData based on field name specified
        searchTransData.sortData(columnName);
        
        //Redraw the Search Trans Table
        document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);
    }

    this.updateTrans = function(transID, startPage)
    {
        //Get Old Transaction to be deleted
        var updatingTrans = searchTransData.getTransByTransID(transID);
        updatingTrans.oldCategoryID = updatingTrans.CategoryID;
        updatingTrans.oldAmount = updatingTrans.Amount;
        updatingTrans.oldDate = updatingTrans.Date;
        updatingTrans.oldDescription = updatingTrans.Description;
        updatingTrans.oldSubCategoryID = updatingTrans.SubCategoryID;
        updatingTrans.oldCategoryName = updatingTrans.CategoryName;

        //Get New Transaction to be saved
        var newTrans = searchTransResultTable.getCurrentRowData(transID);
        updatingTrans.CategoryID = newTrans.CategoryID;
        updatingTrans.Amount = newTrans.Amount;
        updatingTrans.Date = newTrans.Date;
        updatingTrans.Description = newTrans.Description;
        updatingTrans.SubCategoryID = newTrans.SubCategoryID;
        updatingTrans.CategoryName = newTrans.CategoryName;

        if (isValidTransForUpdate(updatingTrans, transType))
        {
            internalUpdateTrans(startPage, updatingTrans);
        }
    };
    
    this.retryUpdateTrans = function(transID, startPage)
    {
        var updatingTrans = searchTransData.getTransByTransID(transID);
        
        internalUpdateTrans(startPage, updatingTrans);
    };

    function internalUpdateTrans(startPage, updatingTrans)
    {
        updatingTrans.Selected = false;
        updatingTrans.State = "Updating";
        
        //Redraw Search TransTable
        document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);                        

        jsonService.UpdateTrans(updatingTrans, function(response)
        { 
            response.context = new Object();
            response.context.updatingTrans = updatingTrans;
            response.context.startPage = startPage;
            
            updateTrans_CallBack(response);
            });                            
    }
    
    function updateTrans_CallBack(response)
    {
        var updatingTrans = response.context.updatingTrans;
        var startPage = response.context.startPage;
        
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Update State
            updatingTrans.State = "Current";
            
            //Update CategoryData
            transCatData.deleteTrans(updatingTrans.oldCategoryID, updatingTrans.oldAmount, updatingTrans.oldDate, updatingTrans.oldSubCategoryID);
            transCatData.addTrans(updatingTrans.CategoryID, updatingTrans.Amount, updatingTrans.Date, updatingTrans.SubCategoryID);            
            
            //Also update recentTransData if the trans is part of it
            recentTransData.updateTransByTransID(updatingTrans.TransID, updatingTrans);
        }                 
        else
        {
            updatingTrans.State = "UpdateFailed";            
            alert("Failed to update " + transType + " record. Unexpected error ocurred. Please retry");         
        }

        //Redraw Search Results
        document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);                        
    }

    function isValidTransForUpdate(trans, transType)
    {
        if(!trans.Date)
        {
             alert("Cannot update " + transType + ".  Invalid Date Specified.");
             return false;       
        }
         
        if(!isValidAmount(trans.Amount))
        {
             alert("Cannot update " + transType + ".  Invalid Amount Specified.");
             return false;               
        }
        
        return true;
    }

    this.deleteTrans = function(transID, startPage)
    {
        var trans = searchTransData.getTransByTransID(transID);

        if (confirm("Are you sure you want to delete this " + transType + " record?\n--> " + trans.CategoryName + ": " + roundAmount(trans.Amount)))
        {
            //Redraw transTable to show trans being deleted
            trans.State = "Deleting";
            document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);                        

            jsonService.DeleteTrans(trans.TransID, function(response)
            {
                response.context = new Object();
                response.context.trans = trans;
                response.context.startPage = startPage;

                deleteTrans_CallBack(response);
            });
        }
    };
    
    function deleteTrans_CallBack(response)
    {
        var startPage = response.context.startPage;
        var trans = response.context.trans;
        
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Delete from CategoryData        
            transCatData.deleteTrans(trans.CategoryID, trans.Amount, trans.Date, trans.SubCategoryID);

            //Delete from recent trans array
            searchTransData.deleteTransByTransID(trans.TransID);

            //Also delete from recentTransData if the trans is part of it
            recentTransData.deleteTransByTransID(trans.TransID, trans);

            //Redraw Search Results
            document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);                        
        }                 
        else
        {
            trans.State = "DeleteFailed";
            document.getElementById(panelName + "_SearchResults").innerHTML = searchTransResultTable.toHTML(startPage);                        
            
            alert("Failed to delete " + transType + " record. Unexpected error ocurred. Please retry");         
        }
    }    
}/************************* ContentLoader Page Functions *************************/
function ContentLoader(htmlURL, containerId, jsURLs)
{       
    var httpRequest;

    var numJSFilesToLoad = 0;
    var numJSFilesLoaded = 0;
    var jsFileArray = null;    
        
    //Javascript files to load
    if(jsURLs)
    {
        jsFileArray = jsURLs.split(",");                
        numJSFilesToLoad += jsFileArray.length;        
    }
        
    var pageLoaded = false;    
    var onLoadFunction;

    this.isLoaded = function()
    {
        return pageLoaded;
    }
    
	this.loadPage = function(loadFunction)
	{	
	    onLoadFunction = loadFunction;
	    httpRequest = getXMLHttpRequest();
	    
	    //Load HTML Page
        if(httpRequest)
        {
            httpRequest.onreadystatechange = function()
            {
	            loadHTML_Callback();
            };
            
            httpRequest.open('GET', htmlURL, true);
            httpRequest.send(null);		                    
        }
        else
        {
            return false;
        }        
    }
            
    function loadHTML_Callback()
    {    
	    if (httpRequest.readyState == 4 && (httpRequest.status==200 || window.location.href.indexOf("http")==-1))
	    {
            document.getElementById(containerId).innerHTML = httpRequest.responseText;
            
            if(numJSFilesToLoad > 0)
            {
                loadJSFile(0);
            }
            else
            {                      
                callOnLoadFunction();
            }
	    }
    }
    
    function loadJSFile(fileIndex)
    {
        httpRequest = getXMLHttpRequest();
        
        httpRequest.onreadystatechange = function()
        {
            loadJS_Callback(fileIndex);
        };
                
        httpRequest.open('GET', jsFileArray[fileIndex], true);
        httpRequest.send(null);	                     
    }
    
    function loadJS_Callback(fileIndex)
    {
        
	    if(httpRequest.readyState == 4 && (httpRequest.status==200 || window.location.href.indexOf("http")==-1))
	    {
	        var code = httpRequest.responseText;
	        
            if(window.execScript)
            { 
                //IF IE
                window.execScript(code, 'javascript');
            }
            else if (navigator.userAgent.indexOf('Safari')!=-1) 
            {
                //IF Safari
                window.setTimeout(code,0);
            }
            else
            {
                window.eval(code);
            }
            
            numJSFilesLoaded += 1; 
            
            if(numJSFilesToLoad > numJSFilesLoaded)
            {
                loadJSFile(fileIndex+1);            
            }
            else
            {
                callOnLoadFunction();            
            }                        
        }
    }
    
    function callOnLoadFunction() {
        pageLoaded = true;
        setTimeout(onLoadFunction,100);       
    }    
    
    function getXMLHttpRequest()
    {
	    if (window.XMLHttpRequest) // if Mozilla, Safari etc
	    {
		    return new XMLHttpRequest();
	    }
	    else if (window.ActiveXObject)  // if IE
	    {
		    try 
		    {
			    return new ActiveXObject("Msxml2.XMLHTTP");
		    } 
		    catch (e)
		    {
			    try
			    {
				    return new ActiveXObject("Microsoft.XMLHTTP");
			    }
			    catch (e)
			    {
			    }
		    }
	    }
        
        return false;
    }    
}



/*
Author: Rens Methratta
Copyright ExpenseView.com
This code is property of ExpenseView.com and cannot be used without explicit permission
from Rens Methratta.
*/

//Panels that are displayed on the page
var addExpensePanel;
var expCategoryPanel;
var searchExpPanel;
var expPieChartPanel;

/*Function for Add Expense Panel 
  This panel dispalys the following elements:
    - Add Expense
    - Recent Expenses
    - Expense Summary
*/ 
function drawAddExpensePanel()
{
    if (!addExpensePanel)
    {
        addExpensePanel = new AddTransPanel("addExpensePanel", "Expense", recentExpData, expCategoryData);
    }

    addExpensePanel.drawPanel();
}

function drawExpCategoryPanel()
{
    if (!expCategoryPanel)
    {
        expCategoryPanel = new EditCategoryPanel("expCategoryPanel", "Expense", expCategoryData, recentExpData);
    }

    expCategoryPanel.drawPanel();                
}

function drawSearchExpensePanel()
{
    if (!searchExpPanel) 
    {
        searchExpPanel = new SearchTransPanel("searchExpPanel", "Expense", expCategoryData, recentExpData);
    }

    searchExpPanel.drawPanel();    
}

function drawExpensePieChartPanel()
{
    if (!expPieChartPanel)
    {
        expPieChartPanel = new BreakdownPieGraphPanel("expPieChartPanel", "E");
    }

    expPieChartPanel.drawPanel();
}


function drawExpTrendsPanel()
{
    alert("Drawing Table todo");
}/*
Author: Rens Methratta
Copyright ExpenseView.com
This code is property of ExpenseView.com and cannot be used without explicit permission
from Rens Methratta.
*/

//Panels that comprise the page
var addIncomePanel;
var incomeCategoryPanel;
var searchIncomePanel;
var incomePieChartPanel;

/*Function for Add Income Panel 
  This panel dispalys the following elements:
    - Add Income
    - Recent Income
    - Income Summary
*/ 
function drawAddIncomePanel()
{
    if (!addIncomePanel)
    {
        addIncomePanel = new AddTransPanel("addIncomePanel", "Income", recentIncomeData, incomeCategoryData);
    }

    addIncomePanel.drawPanel();
}

function drawIncomeCategoryPanel()
{
    if (!incomeCategoryPanel)
    {
        incomeCategoryPanel = new EditCategoryPanel("incomeCategoryPanel", "Income", incomeCategoryData, recentIncomeData);
    }

    incomeCategoryPanel.drawPanel();
}

function drawSearchIncomePanel() 
{
    if (!searchIncomePanel) 
    {
        searchIncomePanel = new SearchTransPanel("searchIncomePanel", "Income", incomeCategoryData, recentIncomeData);
    }

    searchIncomePanel.drawPanel();
}

function drawIncomePieChartPanel()
{
    if (!incomePieChartPanel)
    {
        incomePieChartPanel = new BreakdownPieGraphPanel("incomePieChartPanel", "I");
    }

    incomePieChartPanel.drawPanel();
}

function drawIncomeTrendsPanel()
{
    alert("Drawing Table todo");
}/*
Author: Rens Methratta
Copyright ExpenseView.com
This code is property of ExpenseView.com and cannot be used without explicit permission
from ExpenseView.com.
*/

//Modules which are displayed on this page
var balanceChangeTable;
var expectedBalanceChangeTable;

/******************************* Savings Summary ****************************/

function drawBalanceSummary(expCatData, incomeCatData)
{
    //Set Current Balance
    var balance = roundAmount(incomeCategoryData.getTotalAllTimeAmount() - expCategoryData.getTotalAllTimeAmount());
    if(!balance)
    {
        balance = 0;
    }
    
    var balanceColor = "green";
    if(balance < 0)
    {
        balanceColor = "red";
    }
    
    document.getElementById("currentBalanceDiv").innerHTML =  "<font color='" + balanceColor + "'>" + balance + "</font>";

        
    if(!balanceChangeTable)
    {
        balanceChangeTable = new BalanceChangeTable("balanceSumTable", expCategoryData, incomeCategoryData);
    }
    
    if(!expectedBalanceChangeTable)
    {
        expectedBalanceChangeTable = new ExpectedBalanceTableModule("expectedBalanceDiv", expCategoryData, incomeCategoryData);    
    }
    
    balanceChangeTable.drawModule();
    expectedBalanceChangeTable.drawModule();
}function getFieldValue(fieldName)
{
    var field = document.getElementById(fieldName);
    if(field){ return field.value; }
    else { return ""; }            
}

function setFieldValue(fieldName, fieldValue)
{
    var field = document.getElementById(fieldName);
    if(field){ field.value = fieldValue; }
}

function clearField(field, valueToClear) 
{
    if (field.value === valueToClear) {
        field.value = "";
    }
}

function setFieldText(field, valueToSet) {
    if (field.value === '') {
        field.value = valueToSet;
    }
}
function cleanXML(xmlValue)
{
    xmlValue = xmlValue.replace(/&/g, "*").replace(/>/g, "*").replace(/</g, "*").replace(/'/g, "*");
    return xmlValue;
}

function escapeQuote(stringValue)
{
    if(!stringValue || stringValue === "")
    {
        return stringValue;
    }
    else  
    {
        return stringValue.replace(/'/g, "&#39;");
    }
}

function getRoundedAmount(amount)
{
    if(!amount || amount === "")
    {
        return "0";
    }
    else
    {
        return roundAmount(amount);
    }
}

function roundAmount(amount) 
{ 
    var roundedValue = Math.round(amount*100)/100;      
    return padZeros(roundedValue);
}

function padZeros(amount)
{    
    if(!amount || amount === "")
    {
        return "";
    }
    
    var amountString = amount.toString();
    var decimalIndex = amountString.indexOf('.');
    
    if(decimalIndex === -1)
    {
        if (ExpViewGlobalData.userDisplayDecimals === 2) {
            return (amountString += ".00");
        }
        else if (ExpViewGlobalData.userDisplayDecimals === 3) {
            return (amountString += ".000");
        }
        else {
            return amountString;
        }
    }
    else
    {
        var numDecimalPlaces = (amountString.length - 1) - decimalIndex;

        if (numDecimalPlaces === 2) 
        {
            if (ExpViewGlobalData.userDisplayDecimals === 3) {
                return amountString + "0";
            }
            else {
                return amountString;
            }
        }
        else if (numDecimalPlaces === 1) 
        {
            if (ExpViewGlobalData.userDisplayDecimals === 2) {
                return (amountString += "0");
            }
            else if (ExpViewGlobalData.userDisplayDecimals === 3) {
                return (amountString += "00");
            }
            else 
            {
                return amountString;
            }
        }
        else if(numDecimalPlaces === 0)
        {
            if (ExpViewGlobalData.userDisplayDecimals === 2) {
                return (amountString += "00");
            }
            else if (ExpViewGlobalData.userDisplayDecimals === 3) {
                return (amountString += "000");
            }
            else {
                return amountString;
            }
        }
    }
}/******************* StringBuffer Object *********************/
function StringBuffer() 
{ 
    this.buffer = []; 
} 

StringBuffer.prototype.append = function append(string) 
{ 
    this.buffer.push(string); 
    return this; 
};

StringBuffer.prototype.toString = function toString() 
{ 
    return this.buffer.join(""); 
};

function showTooltip(anchor, text) 
{
    var toolTipDiv = document.getElementById("toolTip");	
    var left = (Left(anchor) + 30) + "px";
    var top = (Top(anchor)) + "px";
    
    toolTipDiv.style.position = "absolute";
	toolTipDiv.style.left = left;
	toolTipDiv.style.top = top;

    //Show toolTipDiv
    toolTipDiv.innerHTML = anchor.getAttribute('tipitle');
    toolTipDiv.style.display = "block";
}

function hideTooltip() 
{
    var toolTipDiv = document.getElementById("toolTip");
	toolTipDiv.innerHTML = "";
	toolTipDiv.style.display = "none";
}
function EditCategoryPanel(panelName, categoryType, catTypeCatagoryData, recentTransData)
{
    var transCategoryTable;

    //Displays all the modules in the panel
    this.drawPanel = function()
    {
        if (!transCategoryTable)
        {
            //Create AddExpensePanel Modules
            transCategoryTable = new CategoryTableModule(panelName, catTypeCatagoryData, categoryType);        
        }

        document.getElementById("div_" + panelName).innerHTML = toHTML();
    }
    
    function toHTML()
    {
        var sb = new StringBuffer();
        if (categoryType === "Expense")
        {
            sb.append("<span class='panelHeader'>Expense Categories</span>");
            sb.append("&nbsp;<a href='#' onmouseout='hideTooltip();' onmouseover='showTooltip(this);' tipitle=\"Expense Categories allow you to track where you're spending your money. You can also specify a Yearly, Monthly or Weekly <i>Budget</i> for each category. Specifiying a <i>Budget</i> is opitonal, but it's useful a way to limit your spending and to forecast your potential savings.\"><img src='images/information.jpg' style='border: 0px' /></a>");
        }
        else
        {
            sb.append("<span class='panelHeader'>Income Categories</span>");
            sb.append("&nbsp;<a href='#' onmouseout='hideTooltip();' onmouseover='showTooltip(this);' tipitle=\"Income Categories allow you to track the sources of your income. You can also specify a Yearly, Monthly or Weekly <i>Amount</i> for each category to represent the amount you expect to receive for that period.  Specifiying an <i>Amount</i> is opitonal, but it is useful to forecast your potential balance.\"><img src='images/information.jpg' style='border: 0px' /></a>");        
        }
        
        sb.append("<div id='" + panelName + "_CategoryTableModule'>");
        sb.append(transCategoryTable.toHTML());
        sb.append("</div>");
        
        return sb.toString();
    }

    function redrawTransCategoryTable()
    {
        document.getElementById(panelName + "_CategoryTableModule").innerHTML = transCategoryTable.toHTML();
    }

    function isValidCategory(category, operation)
    {
        if(!category.Name || category.Name === "")
        {
            alert("Cannot " + operation + " Category.  Category Name was not specified");
            return false;
        }

        var catFieldDesc = "";
        if(category.CategoryType === "E") 
        { 
            catFieldDesc = "Budget"; 
        } 
        else 
        {
            catFieldDesc = "Amount";
        }
        
        if(category.yearBudget && !isValidAmount(category.yearBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Year" + catFieldDesc);
            return false;    
        }

        if(category.monthBudget && !isValidAmount(category.monthBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Month " + catFieldDesc);
            return false;    
        }

        if(category.weekBudget && !isValidAmount(category.weekBudget))
        {
            alert("Cannot " + operation + " Category.  Invalid amount specified for Week  " + catFieldDesc);
            return false;    
        }
        
        return true;    
    }
    
    function isValidSubCategory(subCategory, operation)
    {
        if(!subCategory.Name || subCategory.Name === "")
        {
            alert("Cannot " + operation + " SubCategory.  SubCategory Name was not specified");
            return false;
        }
        
        return true;    
    }

    
    function getRandomColor()   
    {
        var array = new Array (   "f", "e", "d", "c", "b", "a", "9", "8", "7", "6", "5", "4", "3", "2", "1"   );  // array of possible hex values.
        var hexColor = "";  // this is the hex color that will be returned

        // and each time add a new character to the returned color.
        for(var i = 0; i < 6; i++)   
        {
            hexColor += array[Math.floor(Math.random() * array.length)];
        }

        return hexColor;
    };

    this.toggleSubCategories = function(tbodyID, clickIcon, categoryID)
    {
        transCategoryTable.toggleSubCategories(tbodyID, clickIcon, categoryID);
    }

    this.updateCategory = function(categoryID)
    {
        var modifiedCategory = transCategoryTable.getModifiedRow(categoryID);

        //Convert "" values to null before sending to server, otherwise it will cause a 
        //processing error
        if (modifiedCategory.YearBudget === "") { modifiedCategory.YearBudget = null; }
        if (modifiedCategory.MonthBudget === "") { modifiedCategory.MonthBudget = null; }
        if (modifiedCategory.WeekBudget === "") { modifiedCategory.WeekBudget = null; }

        if (isValidCategory(modifiedCategory, "update"))
        {
            //Redraw table to show that category is being updated
            var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);
            category.Selected = false;
            category.State = "Updating";
            redrawTransCategoryTable();

            jsonService.UpdateCategory(modifiedCategory, function(response)
            {
                response.context = new Object();
                response.context.modifiedCategory = modifiedCategory;
                updateCategory_CallBack(response);
            });
        }
    };
    
    function updateCategory_CallBack(response)
    {
        var modifiedCategory = response.context.modifiedCategory;
        var categoryID = modifiedCategory.CategoryID;
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            catTypeCatagoryData.updateCategory(categoryID, modifiedCategory);
            
            //Redraw Category Table to show that the update succeeded
            var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);                        
            category.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update failed
            var currentCategory = transCategoryTable.GetCategoryByCategoryID(categoryID);
            currentCategory.State = "UpdateFailed";
            redrawTransCategoryTable();
        }
    };
    
    this.toggleCategoryEdit = function(categoryID)
    {
        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);

        if(category.Selected)
        {
            category.Selected = false;            
        }
        else
        {
            category.Selected = true;    
        }

        redrawTransCategoryTable();
    }
    
    this.toggleSubCategoryEdit = function(subCategoryID)
    {
        var subCategory = catTypeCatagoryData.getSubCategory(subCategoryID);
        
        if(subCategory.Selected)
        {
            subCategory.Selected = false;            
        }
        else
        {
            subCategory.Selected = true;    
        }

        redrawTransCategoryTable();
    }

    this.addCategory = function() {
        var category = transCategoryTable.getAddingCategory();

        //Insert New Category onto database
        if (isValidCategory(category, "add")) {
            //Specify a color for the category
            category.Color = getRandomColor();
            category.CategoryID = createGuid();
            category.State = "Adding";

            if (!catTypeCatagoryData) {
                var categories = new Array();
                categories[0] = category;
                catTypeCatagoryData = new CategoryData(categories);
            }
            else {

                catTypeCatagoryData.addCategory(category);
            }
            
            //Redraw Category Table to display category being added
            redrawTransCategoryTable();

            //Create tempCategory object to pass to backend
            //Can't pass category object directly because it contains
            //a generated guid for CategoryID 
            var tempCategory = new Object();
            tempCategory.Name = category.Name;
            tempCategory.Color = category.Color;
            tempCategory.CategoryType = category.CategoryType;
            tempCategory.Description = category.Description;
            tempCategory.YearBudget = category.YearBudget;
            tempCategory.MonthBudget = category.MonthBudget;
            tempCategory.WeekBudget = category.WeekBudget;

            //Convert "" values to null to prevent any processing errors
            if (tempCategory.YearBudget == "") { tempCategory.YearBudget = null; }
            if (tempCategory.MonthBudget == "") { tempCategory.MonthBudget = null; }
            if (tempCategory.WeekBudget == "") { tempCategory.WeekBudget = null; }

            //Set CategoryID to null to avoid parsing error on server
            tempCategory.CategoryID = null;

            jsonService.InsertCategory(tempCategory, function(response) {
                response.context = new Object();
                response.context.guidCategoryID = category.CategoryID;
                addCategory_CallBack(response);
            })
        }
    };

    this.retryAddCategory = function(categoryID)
    {
        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);
        category.State = "Adding";
        
        //Redraw Category Table to display category being added
        redrawTransCategoryTable();

        //Create tempCategory object to pass to backend
        //Can't pass category object directly because it contains
        //a generated guid for CategoryID 
        var tempCategory = new Object();
        tempCategory.Name = category.Name;
        tempCategory.Color = category.Color;
        tempCategory.CategoryType = category.CategoryType;
        tempCategory.Description = category.Description;
        tempCategory.YearBudget = category.YearBudget;
        tempCategory.MonthBudget = category.MonthBudget;
        tempCategory.WeekBudget = category.WeekBudget;

        //Convert "" values to null to prevent any processing errors
        if (tempCategory.YearBudget == "") { tempCategory.YearBudget = null; }
        if (tempCategory.MonthBudget == "") { tempCategory.MonthBudget = null; }
        if (tempCategory.WeekBudget == "") { tempCategory.WeekBudget = null; }

        //Set CategoryID to null to avoid parsing error on server
        tempCategory.CategoryID = null;

        jsonService.InsertCategory(tempCategory, function(response)
        {
            response.context = new Object();
            response.context.guidCategoryID = category.CategoryID;
            addCategory_CallBack(response);
        })
    };
    

    
    function addCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {
            var category = catTypeCatagoryData.getCategoryByCategoryID(response.context.guidCategoryID);
            category.State = "Current";
            catTypeCatagoryData.changeCategoryID(response.context.guidCategoryID, response.result);

            //Redraw Category Table to show that the insert succeeded
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update succeeded
            var category = catTypeCatagoryData.getCategoryByCategoryID(response.context.guidCategoryID);

            category.State = "AddFailed";
            redrawTransCategoryTable();
        }        
    };

    this.deleteCategory = function(categoryID) {
        if (catTypeCatagoryData.getNumCategories() == 1) {
            alert("Cannot delete Category. At least on category is required to use the application");
            return;
        }

        var category = catTypeCatagoryData.getCategoryByCategoryID(categoryID);

        var catTypeDesc;

        if (confirm("Are you sure you want to delete the " + category.Name + " category? \nDeleting this category will also delete ALL " + categoryType + " records for this category!")) {
            category.State = "Deleting";
            redrawTransCategoryTable();

            //Convert "" values to null before sending to server, otherwise it will cause a 
            //processing error
            if (category.YearBudget === "") { category.YearBudget = null; }
            if (category.MonthBudget === "") { category.MonthBudget = null; }
            if (category.WeekBudget === "") { category.WeekBudget = null; }

            jsonService.DeleteCategory(category.CategoryID, function(response) {
                response.context = new Object();
                response.context.deletingCategory = category;
                deleteCategory_CallBack(response);
            });
        }
    };
    
    function deleteCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {            
            var deletedCatID = response.context.deletingCategory.CategoryID;
            catTypeCatagoryData.deleteCategory(deletedCatID);

            redrawTransCategoryTable();
            
            if(recentTransData)
            {
                recentTransData.deleteAllTransInCategory(deletedCatID);
            }            
        }
        else
        {
            //Redraw Category Table to show that the update succeeded
            response.context.deletingCategory.Selected = false;            
            response.context.deletingCategory.State = "DeleteFailed";
            redrawTransCategoryTable();
        }      
    }
    
    this.updateSubCategory = function(subCategoryID)
    {
        var modifiedSubCategory = transCategoryTable.getModifiedSubCategory(subCategoryID);
                
        if(isValidSubCategory(modifiedSubCategory, "update"))
        {
            modifiedSubCategory.State = "Updating";
            redrawTransCategoryTable();
            
            jsonService.UpdateSubCategory(modifiedSubCategory, function(response) { 
                response.context = new Object();
                response.context.subCategoryID = modifiedSubCategory.SubCategoryID;            
                updateSubCategory_CallBack(response);
            });
        }                           
    };
    
    
    function updateSubCategory_CallBack(response)
    {
        var modifiedSubCategory = catTypeCatagoryData.getSubCategory(response.context.subCategoryID);
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Redraw Category Table to show that the update succeeded
            modifiedSubCategory.Selected = false;
            modifiedSubCategory.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the update failed
            modifiedSubCategory.Selected = false;            
            modifiedSubCategory.State = "UpdateFailed";
            redrawTransCategoryTable();
        }
    };

    this.addSubCategory = function(categoryID)
    {
        var addingSubCategory = transCategoryTable.getAddingSubCategory(categoryID);
                        
        if(isValidSubCategory(addingSubCategory, "add"))
        {
            addingSubCategory.State = "Adding";
            addingSubCategory.Color = getRandomColor();

            //set temp SubCategoryID
            addingSubCategory.SubCategoryID = createGuid();            
            
            //add subCategory to catData
            catTypeCatagoryData.addSubCategory(categoryID, addingSubCategory);

            redrawTransCategoryTable();

            //Create a SubCategory object without the temp SubCategoryID to pass 
            //to the backend
            var newSubCategory = new Object();
            newSubCategory.SubCategoryID = null;
            newSubCategory.CategoryID = addingSubCategory.CategoryID;
            newSubCategory.Name = addingSubCategory.Name;
            newSubCategory.Color = addingSubCategory.Color;
            
            jsonService.InsertSubCategory(newSubCategory, function(response) { 
                response.context = new Object();
                response.context.tempSubCategoryID = addingSubCategory.SubCategoryID;            
                addSubCategory_CallBack(response);
            });
        }                           
    };    
    
    function addSubCategory_CallBack(response)
    {
        //Get SubCategory with the tempSubCategoryID
        var addedSubCategory = catTypeCatagoryData.getSubCategory(response.context.tempSubCategoryID);
                
        var resValue = response.result;
        if(resValue && resValue !== -1)
        {
            //Update the SubCategory with the ID generated from the backend
            catTypeCatagoryData.changeSubCategoryID(response.context.tempSubCategoryID, resValue);
            
            //Redraw Category Table to show that the add succeeded
            addedSubCategory.Selected = false;
            addedSubCategory.State = "Current";
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw Category Table to show that the add failed
            addedSubCategory.Selected = false;            
            addedSubCategory.State = "AddFailed";
            redrawTransCategoryTable();
        }
    };
      
      
    this.deleteSubCategory = function(subCategoryID) 
    {
        var subCategory = catTypeCatagoryData.getSubCategory(subCategoryID);
                
        if (confirm("Are you sure you want to delete the " + subCategory.Name +" sub-category? \nDeleting this category will also delete ALL " + categoryType + " records for this sub-category!")) 
        {   
            subCategory.State = "Deleting";
            redrawTransCategoryTable();
                                             
            jsonService.DeleteSubCategory(subCategoryID, function(response) { 
                response.context = new Object();
                response.context.deletingSubCategoryID = subCategoryID;            
                deleteSubCategory_CallBack(response);
            });
        }                                   
    };
    
    function deleteSubCategory_CallBack(response)
    {
        if(response.result && response.result != -1)
        {   
            //Remove SubCategory from CategoryData       
            catTypeCatagoryData.deleteSubCategory(response.context.deletingSubCategoryID);

            //Remove recent transactions for the deleted subcategory
            if (recentTransData)
            {
                recentTransData.deleteAllTransInSubCategory(response.context.deletingSubCategoryID);
            }
            
            //Redraw CategoryTable to remove deleted sub-category
            redrawTransCategoryTable();
        }
        else
        {
            //Redraw CategoryTable to show that the delete failed                       
            var subCategory = catTypeCatagoryData.getSubCategory(response.context.deletingSubCategoryID);
            subCategory.State = "DeleteFailed";
            redrawTransCategoryTable();
        }      
    }
    
};

function isValidAmount(amountValue)
{
    var amountRegExp = /^\d{1,}\.{0,1}\d{0,2}$/;    
    
    if(!amountRegExp.test(amountValue))
    {
        return false;
    }
    return true;    
}