var WCT = window.WCT || {};

WCT.namespace = function( sNameSpace ) {
    if (!sNameSpace || !sNameSpace.length) {
        return null;
    }
    var levels = sNameSpace.split(".");
    var currentNS = WCT;
    for (var i=(levels[0] == "WCT") ? 1 : 0; i<levels.length; ++i) {
        currentNS[levels[i]] = currentNS[levels[i]] || {};
        currentNS = currentNS[levels[i]];
    }
    return currentNS;
};
WCT.namespace("util");
WCT.namespace("widget");
WCT.namespace("example");
WCT.util.CustomEvent = function(type, oScope) {
    this.type = type;
    this.scope = oScope || window;
    if (WCT.util.Event) { 
        WCT.util.Event.regCE(this);
    }
};

if (!WCT.util.Event) {

    WCT.util.Event = function() {

        var loadComplete =  false;
        var listeners = [];
        var delayedListeners = [];
        var unloadListeners = [];
        var customEvents = [];
        var legacyEvents = [];
        var legacyHandlers = [];
        var retryCount = 0;
        var onAvailStack = [];
        var legacyMap = [];
        var counter = 0;

        return {

            POLL_RETRYS: 200,

            POLL_INTERVAL: 50,

            EL: 0,

            TYPE: 1,

            FN: 2,

            WFN: 3,

            SCOPE: 3,

            ADJ_SCOPE: 4,

            isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),

            isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && 
                    navigator.userAgent.match(/msie/gi)),

            addDelayedListener: function(el, sType, fn, oScope, bOverride) {
                delayedListeners[delayedListeners.length] =
                    [el, sType, fn, oScope, bOverride];

                if (loadComplete) {
                    retryCount = this.POLL_RETRYS;
                    this.startTimeout(0);

                }
            },

            startTimeout: function(interval) {
                var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;
                var self = this;
                var callback = function() { self._tryPreloadAttach(); };
                this.timeout = setTimeout(callback, i);
            },

            onAvailable: function(p_id, p_fn, p_obj, p_override) {
                onAvailStack.push( { id:       p_id, 
                                     fn:       p_fn, 
                                     obj:      p_obj, 
                                     override: p_override } );

                retryCount = this.POLL_RETRYS;
                this.startTimeout(0);

            },

            addListener: function(el, sType, fn, oScope, bOverride) {

                if (!fn || !fn.call) {
                    return false;
                }


                if ( this._isValidCollection(el)) {
                    var ok = true;
                    for (var i=0,len=el.length; i<len; ++i) {
                        ok = ( this.on(el[i], 
                                       sType, 
                                       fn, 
                                       oScope, 
                                       bOverride) && ok );
                    }
                    return ok;

                } else if (typeof el == "string") {
                    var oEl = this.getEl(el);

                    if (loadComplete && oEl) {
                        el = oEl;
                    } else {

                        this.addDelayedListener(el, 
                                                sType, 
                                                fn, 
                                                oScope, 
                                                bOverride);

                        return true;
                    }
                }

                if (!el) {
                    return false;
                }

                if ("unload" == sType && oScope !== this) {
                    unloadListeners[unloadListeners.length] =
                            [el, sType, fn, oScope, bOverride];
                    return true;
                }

                var scope = (bOverride) ? oScope : el;

                var wrappedFn = function(e) {
                        return fn.call(scope, WCT.util.Event.getEvent(e), 
                                oScope);
                    };

                var li = [el, sType, fn, wrappedFn, scope];
                var index = listeners.length;

                listeners[index] = li;

                if (this.useLegacyEvent(el, sType)) {
                    var legacyIndex = this.getLegacyIndex(el, sType);
                    if (legacyIndex == -1) {

                        legacyIndex = legacyEvents.length;
                        legacyMap[el.id + sType] = legacyIndex;

                        legacyEvents[legacyIndex] = 
                            [el, sType, el["on" + sType]];
                        legacyHandlers[legacyIndex] = [];

                        el["on" + sType] = 
                            function(e) {
                                WCT.util.Event.fireLegacyEvent(
                                    WCT.util.Event.getEvent(e), legacyIndex);
                            };
                    }

                    legacyHandlers[legacyIndex].push(index);

                } else if (el.addEventListener) {
                    el.addEventListener(sType, wrappedFn, false);

                } else if (el.attachEvent) {
                    el.attachEvent("on" + sType, wrappedFn);
                }

                return true;
                
            },
            fireLegacyEvent: function(e, legacyIndex) {
                var ok = true;

                var le = legacyHandlers[legacyIndex];
                for (var i=0,len=le.length; i<len; ++i) {
                    var index = le[i];
                    if (index) {
                        var li = listeners[index];
                        if ( li && li[this.WFN] ) {
                            var scope = li[this.ADJ_SCOPE];
                            var ret = li[this.WFN].call(scope, e);
                            ok = (ok && ret);
                        } else {

                            delete le[i];
                        }
                    }
                }

                return ok;
            },
            getLegacyIndex: function(el, sType) {

                var key = this.generateId(el) + sType;
                if (typeof legacyMap[key] == "undefined") { 
                    return -1;
                } else {
                    return legacyMap[key];
                }

            },
            useLegacyEvent: function(el, sType) {

                if (!el.addEventListener && !el.attachEvent) {
                    return true;
                } else if (this.isSafari) {
                    if ("click" == sType || "dblclick" == sType) {
                        return true;
                    }
                }

                return false;
            },

            removeListener: function(el, sType, fn, index) {

                if (!fn || !fn.call) {
                    return false;
                }

                if (typeof el == "string") {
                    el = this.getEl(el);

                } else if ( this._isValidCollection(el)) {
                    var ok = true;
                    for (var i=0,len=el.length; i<len; ++i) {
                        ok = ( this.removeListener(el[i], sType, fn) && ok );
                    }
                    return ok;
                }

                if ("unload" == sType) {

                    for (i=0, len=unloadListeners.length; i<len; i++) {
                        var li = unloadListeners[i];
                        if (li && 
                            li[0] == el && 
                            li[1] == sType && 
                            li[2] == fn) {
                                delete unloadListeners[i];
                                return true;
                        }
                    }

                    return false;
                }

                var cacheItem = null;
  
                if ("undefined" == typeof index) {
                    index = this._getCacheIndex(el, sType, fn);
                }

                if (index >= 0) {
                    cacheItem = listeners[index];
                }

                if (!el || !cacheItem) {
                    return false;
                }


                if (el.removeEventListener) {
                    el.removeEventListener(sType, cacheItem[this.WFN], false);
                } else if (el.detachEvent) {
                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
                }


                delete listeners[index][this.WFN];
                delete listeners[index][this.FN];
                delete listeners[index];

                return true;

            },

            getTarget: function(ev, resolveTextNode) {
                var t = ev.target || ev.srcElement;

                if (resolveTextNode && t && "#text" == t.nodeName) {
                    return t.parentNode;
                } else {
                    return t;
                }
            },

            getPageX: function(ev) {
                var x = ev.pageX;
                if (!x && 0 !== x) {
                    x = ev.clientX || 0;

                    if ( this.isIE ) {
                        x += this._getScrollLeft();
                    }
                }

                return x;
            },

            getPageY: function(ev) {
                var y = ev.pageY;
                if (!y && 0 !== y) {
                    y = ev.clientY || 0;

                    if ( this.isIE ) {
                        y += this._getScrollTop();
                    }
                }

                return y;
            },

            getXY: function(ev) {
                return [this.getPageX(ev), this.getPageY(ev)];
            },

            getRelatedTarget: function(ev) {
                var t = ev.relatedTarget;
                if (!t) {
                    if (ev.type == "mouseout") {
                        t = ev.toElement;
                    } else if (ev.type == "mouseover") {
                        t = ev.fromElement;
                    }
                }

                return t;
            },

            getTime: function(ev) {
                if (!ev.time) {
                    var t = new Date().getTime();
                    try {
                        ev.time = t;
                    } catch(e) { 

                        return t;
                    }
                }

                return ev.time;
            },

            stopEvent: function(ev) {
                this.stopPropagation(ev);
                this.preventDefault(ev);
            },

            stopPropagation: function(ev) {
                if (ev.stopPropagation) {
                    ev.stopPropagation();
                } else {
                    ev.cancelBubble = true;
                }
            },

            preventDefault: function(ev) {
                if (ev.preventDefault) {
                    ev.preventDefault();
                } else {
                    ev.returnValue = false;
                }
            },

            getEvent: function(e) {
                var ev = e || window.event;

                if (!ev) {
                    var c = this.getEvent.caller;
                    while (c) {
                        ev = c.arguments[0];
                        if (ev && Event == ev.constructor) {
                            break;
                        }
                        c = c.caller;
                    }
                }

                return ev;
            },

            getCharCode: function(ev) {
                return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);
            },

            _getCacheIndex: function(el, sType, fn) {
                for (var i=0,len=listeners.length; i<len; ++i) {
                    var li = listeners[i];
                    if ( li                 && 
                         li[this.FN] == fn  && 
                         li[this.EL] == el  && 
                         li[this.TYPE] == sType ) {
                        return i;
                    }
                }

                return -1;
            },

            generateId: function(el) {
                var id = el.id;

                if (!id) {
                    id = "yuievtautoid-" + (counter++);
                    el.id = id;
                }

                return id;
            },

            _isValidCollection: function(o) {

                return ( o                    &&
                         o.length             && 
                         typeof o != "string" && 
                         !o.tagName           && 
                         !o.alert             && 
                         typeof o[0] != "undefined" );

            },

            elCache: {},

            getEl: function(id) {
                return document.getElementById(id);
            },

            clearCache: function() { },

            regCE: function(ce) {
                customEvents.push(ce);
            },

            _load: function(e) {
                loadComplete = true;
            },

            _tryPreloadAttach: function() {

                if (this.locked) {
                    return false;
                }

                this.locked = true;

                var tryAgain = !loadComplete;
                if (!tryAgain) {
                    tryAgain = (retryCount > 0);
                }

                var stillDelayed = [];

                for (var i=0,len=delayedListeners.length; i<len; ++i) {
                    var d = delayedListeners[i];

                    if (d) {

                        var el = this.getEl(d[this.EL]);

                        if (el) {
                            this.on(el, d[this.TYPE], d[this.FN], 
                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
                            delete delayedListeners[i];
                        } else {
                            stillDelayed.push(d);
                        }
                    }
                }

                delayedListeners = stillDelayed;

                notAvail = [];
                for (i=0,len=onAvailStack.length; i<len ; ++i) {
                    var item = onAvailStack[i];
                    if (item) {
                        el = this.getEl(item.id);

                        if (el) {
                            var scope = (item.override) ? item.obj : el;
                            item.fn.call(scope, item.obj);
                            delete onAvailStack[i];
                        } else {
                            notAvail.push(item);
                        }
                    }
                }

                retryCount = (stillDelayed.length === 0 && 
                                    notAvail.length === 0) ? 0 : retryCount - 1;

                if (tryAgain) {
                    this.startTimeout();
                }

                this.locked = false;

            },

            _unload: function(e, me) {
                for (var i=0,len=unloadListeners.length; i<len; ++i) {
                    var l = unloadListeners[i];
                    if (l) {
                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
                    }
                }

                if (listeners && listeners.length > 0) {
                    for (i=0,len=listeners.length; i<len ; ++i) {
                        l = listeners[i];
                        if (l) {
                            this.removeListener(l[this.EL], l[this.TYPE], 
                                    l[this.FN], i);
                        }
                    }

                    this.clearCache();
                }

                for (i=0,len=customEvents.length; i<len; ++i) {
                    customEvents[i].unsubscribeAll();
                    delete customEvents[i];
                }

                for (i=0,len=legacyEvents.length; i<len; ++i) {

                    delete legacyEvents[i][0];

                    delete legacyEvents[i];
                }
            },

            _getScrollLeft: function() {
                return this._getScroll()[1];
            },


            _getScrollTop: function() {
                return this._getScroll()[0];
            },


            _getScroll: function() {
                var dd = document.documentElement; db = document.body;
                if (dd && dd.scrollTop) {
                    return [dd.scrollTop, dd.scrollLeft];
                } else if (db) {
                    return [db.scrollTop, db.scrollLeft];
                } else {
                    return [0, 0];
                }
            }
        };
    } ();

    WCT.util.Event.on = WCT.util.Event.addListener;

    if (document && document.body) {
        WCT.util.Event._load();
    } else {
        WCT.util.Event.on(window, "load", WCT.util.Event._load, 
                WCT.util.Event, true);
    }

    WCT.util.Event.on(window, "unload", WCT.util.Event._unload, 
                WCT.util.Event, true);

    WCT.util.Event._tryPreloadAttach();

}




WCT.util.Dom = function() {
   var ua = navigator.userAgent.toLowerCase();
   var isOpera = (ua.indexOf('opera') != -1);
   var isIE = (ua.indexOf('msie') != -1 && !isOpera);
   var id_counter = 0;
   
   return {

      get: function(el) {
         if (typeof el != 'string' && !(el instanceof Array) )
         {
            return el;
         }
         
         if (typeof el == 'string') 
         { 
            return document.getElementById(el);
         }
         else
         {
            var collection = [];
            for (var i = 0, len = el.length; i < len; ++i)
            {
               collection[collection.length] = this.get(el[i]);
            }
            
            return collection;
         }

         return null;
      },

      getStyle: function(el, property) {
         var f = function(el) {
            var value = null;
            var dv = document.defaultView;
            
            if (property == 'opacity' && el.filters) 
            {
               value = 1;
               try {
                  value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
               } catch(e) {
                  try {
                     value = el.filters.item('alpha').opacity / 100;
                  } catch(e) {}
               }
            }
            else if (el.style[property]) 
            {
               value = el.style[property];
            }
            else if (el.currentStyle && el.currentStyle[property]) {
               value = el.currentStyle[property];
            }
            else if ( dv && dv.getComputedStyle )
            { 
               
               var converted = '';
               for(var i = 0, len = property.length;i < len; ++i) {
                  if (property.charAt(i) == property.charAt(i).toUpperCase()) 
                  {
                     converted = converted + '-' + property.charAt(i).toLowerCase();
                  } else {
                     converted = converted + property.charAt(i);
                  }
               }
               
               if (dv.getComputedStyle(el, '') && dv.getComputedStyle(el, '').getPropertyValue(converted)) {
                  value = dv.getComputedStyle(el, '').getPropertyValue(converted);
               }
            }
      
            return value;
         };
         
         return this.batch(el, f, this, true);
      },

      setStyle: function(el, property, val) {
         var f = function(el) {
            switch(property) {
               case 'opacity' :
                  if (isIE && typeof el.style.filter == 'string') {
                     el.style.filter = 'alpha(opacity=' + val * 100 + ')';
                     
                     if (!el.currentStyle || !el.currentStyle.hasLayout) {
                        el.style.zoom = 1; 
                     }
                  } else {
                     el.style.opacity = val;
                     el.style['-moz-opacity'] = val;
                     el.style['-khtml-opacity'] = val;
                  }

                  break;
               default :
                  el.style[property] = val;
            }
            
         };
         
         this.batch(el, f, this, true);
      },

      getXY: function(el) {
         var f = function(el) {
   

            if (el.parentNode === null || this.getStyle(el, 'display') == 'none') {
               return false;
            }
            
            var parent = null;
            var pos = [];
            var box;
            
            if (el.getBoundingClientRect) { 
               box = el.getBoundingClientRect();
               var scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
               var scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
               
               return [box.left + scrollLeft, box.top + scrollTop];
            }
            else if (document.getBoxObjectFor) { 
               box = document.getBoxObjectFor(el);
               
               var borderLeft = parseInt(this.getStyle(el, 'borderLeftWidth'));
               var borderTop = parseInt(this.getStyle(el, 'borderTopWidth'));
               
               pos = [box.x - borderLeft, box.y - borderTop];
            }
            else { 
               pos = [el.offsetLeft, el.offsetTop];
               parent = el.offsetParent;
               if (parent != el) {
                  while (parent) {
                     pos[0] += parent.offsetLeft;
                     pos[1] += parent.offsetTop;
                     parent = parent.offsetParent;
                  }
               }
               if (
                  ua.indexOf('opera') != -1 
                  || ( ua.indexOf('safari') != -1 && this.getStyle(el, 'position') == 'absolute' ) 
               ) {
                  pos[0] -= document.body.offsetLeft;
                  pos[1] -= document.body.offsetTop;
               } 
            }
            
            if (el.parentNode) { parent = el.parentNode; }
            else { parent = null; }
      
            while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') 
            { 
               pos[0] -= parent.scrollLeft;
               pos[1] -= parent.scrollTop;
      
               if (parent.parentNode) { parent = parent.parentNode; } 
               else { parent = null; }
            }
      
            return pos;
         };
         
         return this.batch(el, f, this, true);
      },

      getX: function(el) {
         return this.getXY(el)[0];
      },

      getY: function(el) {
         return this.getXY(el)[1];
      },
      setXY: function(el, pos, noRetry) {
         var f = function(el) {
   
            var style_pos = this.getStyle(el, 'position');
            if (style_pos == 'static') { 
               this.setStyle(el, 'position', 'relative');
               style_pos = 'relative';
            }
            
            var pageXY = WCT.util.Dom.getXY(el);
            if (pageXY === false) { return false; } 
            
            var delta = [
               parseInt( WCT.util.Dom.getStyle(el, 'left'), 10 ),
               parseInt( WCT.util.Dom.getStyle(el, 'top'), 10 )
            ];
         
            if ( isNaN(delta[0]) ) 
            { 
               delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
            } 
            if ( isNaN(delta[1]) ) 
            { 
               delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
            } 
      
            if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
            if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
      
            var newXY = this.getXY(el);
      
            if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
               var retry = function() { WCT.util.Dom.setXY(el, pos, true); };
               setTimeout(retry, 0); 
            }
         };
         
         this.batch(el, f, this, true);
      },

      setX: function(el, x) {
         this.setXY(el, [x, null]);
      },

      setY: function(el, y) {
         this.setXY(el, [null, y]);
      },

      getRegion: function(el) {
         var f = function(el) {
            return new WCT.util.Region.getRegion(el);
         };
         
         return this.batch(el, f, this, true);
      },

      getClientWidth: function() {
         return this.getViewportWidth();
      },

      getClientHeight: function() {
         return this.getViewportHeight();
      },

      getElementsByClassName: function(className, tag, root) {
         var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
         
         var method = function(el) { return re.test(el['className']); };
         
         return this.getElementsBy(method, tag, root);
      },

      hasClass: function(el, className) {
         var f = function(el) {
            var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
            return re.test(el['className']);
         };
         
         return this.batch(el, f, this, true);
      },

      addClass: function(el, className) {
         var f = function(el) {
            if (this.hasClass(el, className)) { return; } 
            
            el['className'] = [el['className'], className].join(' ');
         };
         
         this.batch(el, f, this, true);
      },
   
      removeClass: function(el, className) {
         var f = function(el) {
            if (!this.hasClass(el, className)) { return; }
            
            var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
            var c = el['className'];
            
            el['className'] = c.replace( re, ' ');
         };
         
         this.batch(el, f, this, true);
      },

      replaceClass: function(el, oldClassName, newClassName) {
         var f = function(el) {
            this.removeClass(el, oldClassName);
            this.addClass(el, newClassName);
         };
         
         this.batch(el, f, this, true);
      },

      generateId: function(el, prefix) {
         prefix = prefix || 'yui-gen';
         
         var f = function(el) {
            el = el || {}; 
            
            if (!el.id) { el.id = prefix + id_counter++; } 
            
            return el.id;
         };
         
         return this.batch(el, f, this, true);
      },

      isAncestor: function(haystack, needle) {
         haystack = this.get(haystack);
         if (!haystack || !needle) { return false; }
         
         var f = function(needle) {
            if (haystack.contains && ua.indexOf('safari') < 0) 
            { 
               return haystack.contains(needle);
            }
            else if ( haystack.compareDocumentPosition ) 
            {
               return !!(haystack.compareDocumentPosition(needle) & 16);
            }
            else 
            { 
               var parent = needle.parentNode;
               
               while (parent) {
                  if (parent == haystack) {
                     return true;
                  }
                  else if (parent.tagName == 'HTML') {
                     return false;
                  }
                  
                  parent = parent.parentNode;
               }
               
               return false;
            }    
         };
         
         return this.batch(needle, f, this, true);     
      },

      inDocument: function(el) {
         var f = function(el) {
            return this.isAncestor(document.documentElement, el);
         };
         
         return this.batch(el, f, this, true);
      },

      getElementsBy: function(method, tag, root) {
         tag = tag || '*';
         root = this.get(root) || document;
         
         var nodes = [];
         var elements = root.getElementsByTagName(tag);
         
         if ( !elements.length && (tag == '*' && root.all) ) {
            elements = root.all;
         }
         
         for (var i = 0, len = elements.length; i < len; ++i) 
         {
            if ( method(elements[i]) ) { nodes[nodes.length] = elements[i]; }
         }

         return nodes;
      },

      batch: function(el, method, o, override) {
         el = this.get(el);
         var scope = (override) ? o : window;
         
         if (!el || el.tagName || !el.length) 
         { 
            return method.call(scope, el, o);
         } 
         
         var collection = [];
         
         for (var i = 0, len = el.length; i < len; ++i)
         {
            collection[collection.length] = method.call(scope, el[i], o);
         }
         
         return collection;
      },

      getDocumentHeight: function() {
         var scrollHeight=-1,windowHeight=-1,bodyHeight=-1;
         var marginTop = parseInt(this.getStyle(document.body, 'marginTop'), 10);
         var marginBottom = parseInt(this.getStyle(document.body, 'marginBottom'), 10);
         
         var mode = document.compatMode;
         
         if ( (mode || isIE) && !isOpera ) { 
            switch (mode) {
               case 'CSS1Compat': 
                  scrollHeight = ((window.innerHeight && window.scrollMaxY) ?  window.innerHeight+window.scrollMaxY : -1);
                  windowHeight = [document.documentElement.clientHeight,self.innerHeight||-1].sort(function(a, b){return(a-b);})[1];
                  bodyHeight = document.body.offsetHeight + marginTop + marginBottom;
                  break;
               
               default: 
                  scrollHeight = document.body.scrollHeight;
                  bodyHeight = document.body.clientHeight;
            }
         } else { 
            scrollHeight = document.documentElement.scrollHeight;
            windowHeight = self.innerHeight;
            bodyHeight = document.documentElement.clientHeight;
         }
      
         var h = [scrollHeight,windowHeight,bodyHeight].sort(function(a, b){return(a-b);});
         return h[2];
      },

      getDocumentWidth: function() {
         var docWidth=-1,bodyWidth=-1,winWidth=-1;
         var marginRight = parseInt(this.getStyle(document.body, 'marginRight'), 10);
         var marginLeft = parseInt(this.getStyle(document.body, 'marginLeft'), 10);
         
         var mode = document.compatMode;
         
         if (mode || isIE) { 
            switch (mode) {
               case 'CSS1Compat': 
                  docWidth = document.documentElement.clientWidth;
                  bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
                  winWidth = self.innerWidth || -1;
                  break;
                  
               default: 
                  bodyWidth = document.body.clientWidth;
                  winWidth = document.body.scrollWidth;
                  break;
            }
         } else { 
            docWidth = document.documentElement.clientWidth;
            bodyWidth = document.body.offsetWidth + marginLeft + marginRight;
            winWidth = self.innerWidth;
         }
      
         var w = [docWidth,bodyWidth,winWidth].sort(function(a, b){return(a-b);});
         return w[2];
      },

      getViewportHeight: function() {
         var height = -1;
         var mode = document.compatMode;
      
         if ( (mode || isIE) && !isOpera ) {
            switch (mode) { 
               case 'CSS1Compat': 
                  height = document.documentElement.clientHeight;
                  break;
      
               default: 
                  height = document.body.clientHeight;
            }
         } else { 
            height = self.innerHeight;
         }
      
         return height;
      },
      

      getViewportWidth: function() {
         var width = -1;
         var mode = document.compatMode;
         
         if (mode || isIE) { 
            switch (mode) {
            case 'CSS1Compat':  
               width = document.documentElement.clientWidth;
               break;
               
            default: 
               width = document.body.clientWidth;
            }
         } else { 
            width = self.innerWidth;
         }
         
         return width;
      }
   };
}();


WCT.util.Region = function(t, r, b, l) {


    this.top = t;
    

    this[1] = t;


    this.right = r;


    this.bottom = b;


    this.left = l;
    

    this[0] = l;
};


WCT.util.Region.prototype.contains = function(region) {
    return ( region.left   >= this.left   && 
             region.right  <= this.right  && 
             region.top    >= this.top    && 
             region.bottom <= this.bottom    );


};


WCT.util.Region.prototype.getArea = function() {
    return ( (this.bottom - this.top) * (this.right - this.left) );
};


WCT.util.Region.prototype.intersect = function(region) {
    var t = Math.max( this.top,    region.top    );
    var r = Math.min( this.right,  region.right  );
    var b = Math.min( this.bottom, region.bottom );
    var l = Math.max( this.left,   region.left   );
    
    if (b >= t && r >= l) {
        return new WCT.util.Region(t, r, b, l);
    } else {
        return null;
    }
};


WCT.util.Region.prototype.union = function(region) {
    var t = Math.min( this.top,    region.top    );
    var r = Math.max( this.right,  region.right  );
    var b = Math.max( this.bottom, region.bottom );
    var l = Math.min( this.left,   region.left   );

    return new WCT.util.Region(t, r, b, l);
};


WCT.util.Region.prototype.toString = function() {
    return ( "Region {" +
             "t: "    + this.top    + 
             ", r: "    + this.right  + 
             ", b: "    + this.bottom + 
             ", l: "    + this.left   + 
             "}" );
};


WCT.util.Region.getRegion = function(el) {
    var p = WCT.util.Dom.getXY(el);

    var t = p[1];
    var r = p[0] + el.offsetWidth;
    var b = p[1] + el.offsetHeight;
    var l = p[0];

    return new WCT.util.Region(t, r, b, l);
};

WCT.widget.DateMath = new function() {


	this.DAY = "D";


	this.WEEK = "W";


	this.YEAR = "Y";


	this.MONTH = "M";


	this.ONE_DAY_MS = 1000*60*60*24;


	this.add = function(date, field, amount) {
		var d = new Date(date.getTime());
		switch (field)
		{
			case this.MONTH:
				var newMonth = date.getMonth() + amount;
				var years = 0;


				if (newMonth < 0) {
					while (newMonth < 0)
					{
						newMonth += 12;
						years -= 1;
					}
				} else if (newMonth > 11) {
					while (newMonth > 11)
					{
						newMonth -= 12;
						years += 1;
					}
				}
				
				d.setMonth(newMonth);
				d.setFullYear(date.getFullYear() + years);
				break;
			case this.DAY:
				d.setDate(date.getDate() + amount);
				break;
			case this.YEAR:
				d.setFullYear(date.getFullYear() + amount);
				break;
			case this.WEEK:
				d.setDate(date.getDate() + 7);
				break;
		}
		return d;
	};


	this.subtract = function(date, field, amount) {
		return this.add(date, field, (amount*-1));
	};


	this.before = function(date, compareTo) {
		var ms = compareTo.getTime();
		if (date.getTime() < ms) {
			return true;
		} else {
			return false;
		}
	};


	this.after = function(date, compareTo) {
		var ms = compareTo.getTime();
		if (date.getTime() > ms) {
			return true;
		} else {
			return false;
		}
	};


	this.getJan1 = function(calendarYear) {
		return new Date(calendarYear,0,1); 
	};


	this.getDayOffset = function(date, calendarYear) {
		var beginYear = this.getJan1(calendarYear); 
		

		var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
		return dayOffset;
	};


	this.getWeekNumber = function(date, calendarYear, weekStartsOn) {
		if (! weekStartsOn) {
			weekStartsOn = 0;
		}
		if (! calendarYear) {
			calendarYear = date.getFullYear();
		}
		var weekNum = -1;
		
		var jan1 = this.getJan1(calendarYear);
		var jan1DayOfWeek = jan1.getDay();
		
		var month = date.getMonth();
		var day = date.getDate();
		var year = date.getFullYear();
		
		var dayOffset = this.getDayOffset(date, calendarYear); 
			
		if (dayOffset < 0 && dayOffset >= (-1 * jan1DayOfWeek)) {
			weekNum = 1;
		} else {
			weekNum = 1;
			var testDate = this.getJan1(calendarYear);
			
			while (testDate.getTime() < date.getTime() && testDate.getFullYear() == calendarYear) {
				weekNum += 1;
				testDate = this.add(testDate, this.WEEK, 1);
			}
		}
		
		return weekNum;
	};

	this.isYearOverlapWeek = function(weekBeginDate) {
		var overlaps = false;
		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
		if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
			overlaps = true;
		}
		return overlaps;
	};

	this.isMonthOverlapWeek = function(weekBeginDate) {
		var overlaps = false;
		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
		if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
			overlaps = true;
		}
		return overlaps;
	};

	this.findMonthStart = function(date) {
		var start = new Date(date.getFullYear(), date.getMonth(), 1);
		return start;
	};

	this.findMonthEnd = function(date) {
		var start = this.findMonthStart(date);
		var nextMonth = this.add(start, this.MONTH, 1);
		var end = this.subtract(nextMonth, this.DAY, 1);
		return end;
	};

	this.clearTime = function(date) {
		date.setHours(0,0,0,0);
		return date;
	};
}

WCT.widget.Calendar_Core = function(id, containerId, monthyear, selected) {
	if (arguments.length > 0)
	{
		this.init(id, containerId, monthyear, selected);
	}
}


WCT.widget.Calendar_Core.IMG_ROOT = "";

WCT.widget.Calendar_Core.DATE = "D";

WCT.widget.Calendar_Core.MONTH_DAY = "MD";

WCT.widget.Calendar_Core.WEEKDAY = "WD";

WCT.widget.Calendar_Core.RANGE = "R";

WCT.widget.Calendar_Core.MONTH = "M";

WCT.widget.Calendar_Core.DISPLAY_DAYS = 42;

WCT.widget.Calendar_Core.STOP_RENDER = "S";

WCT.widget.Calendar_Core.prototype = {

	Config : null,
	parent : null,
	index : -1,
	cells : null,
	weekHeaderCells : null,
	weekFooterCells : null,
	cellDates : null,
	id : null,
	oDomContainer : null,
	today : null,
	renderStack : null,
	_renderStack : null,
	pageDate : null,
	_pageDate : null,
	minDate : null,
	maxDate : null,
	selectedDates : null,
	_selectedDates : null,
	shellRendered : false,
	table : null,
	headerCell : null
};




WCT.widget.Calendar_Core.prototype.init = function(id, containerId, monthyear, selected) {
	this.setupConfig();

	this.id = id;

	this.cellDates = new Array();
	
	this.cells = new Array();
	
	this.renderStack = new Array();
	this._renderStack = new Array();

	this.oDomContainer = document.getElementById(containerId);
	
	this.today = new Date();
	WCT.widget.DateMath.clearTime(this.today);

	var month;
	var year;

	if (monthyear)
	{
		var aMonthYear = monthyear.split(this.Locale.DATE_FIELD_DELIMITER);
		month = parseInt(aMonthYear[this.Locale.MY_MONTH_POSITION-1]);
		year = parseInt(aMonthYear[this.Locale.MY_YEAR_POSITION-1]);
	} else {
		month = this.today.getMonth()+1;
		year = this.today.getFullYear();
	}

	this.pageDate = new Date(year, month-1, 1);
	this._pageDate = new Date(this.pageDate.getTime());

	if (selected)
	{
		this.selectedDates = this._parseDates(selected);
		this._selectedDates = this.selectedDates.concat();
	} else {
		this.selectedDates = new Array();
		this._selectedDates = new Array();
	}

	this.wireDefaultEvents();
	this.wireCustomEvents();
};



WCT.widget.Calendar_Core.prototype.wireDefaultEvents = function() {
	

	this.doSelectCell = function(e, cal) {		
		var cell = this;
		var index = cell.index;
		var d = cal.cellDates[index];
		var date = new Date(d[0],d[1]-1,d[2]);
		
		if (! cal.isDateOOM(date) && ! WCT.util.Dom.hasClass(cell, cal.Style.CSS_CELL_RESTRICTED) && ! WCT.util.Dom.hasClass(cell, cal.Style.CSS_CELL_OOB)) {
			if (cal.Options.MULTI_SELECT) {
				var link = cell.getElementsByTagName("A")[0];
				link.blur();
				
				var cellDate = cal.cellDates[index];
				var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
				
				if (cellDateIndex > -1)
				{	
					cal.deselectCell(index);
				} else {
					cal.selectCell(index);
				}	
				
			} else {
				var link = cell.getElementsByTagName("A")[0];
				link.blur()
				cal.selectCell(index);
			}
		}
	}


	this.doCellMouseOver = function(e, cal) {
		var cell = this;
		var index = cell.index;
		var d = cal.cellDates[index];
		var date = new Date(d[0],d[1]-1,d[2]);

		if (! cal.isDateOOM(date) && ! WCT.util.Dom.hasClass(cell, cal.Style.CSS_CELL_RESTRICTED) && ! WCT.util.Dom.hasClass(cell, cal.Style.CSS_CELL_OOB)) {
			WCT.widget.Calendar_Core.prependCssClass(cell, cal.Style.CSS_CELL_HOVER);
		}
	}


	this.doCellMouseOut = function(e, cal) {
		WCT.widget.Calendar_Core.removeCssClass(this, cal.Style.CSS_CELL_HOVER);
	}
	

	this.doNextMonth = function(e, cal) {
		cal.nextMonth();
	}

	
	this.doPreviousMonth = function(e, cal) {
		cal.previousMonth();
	}
}


WCT.widget.Calendar_Core.prototype.wireCustomEvents = function() { }


WCT.widget.Calendar_Core.prototype.setupConfig = function() {

	this.Config = new Object();
	
	this.Config.Style = {

		CSS_ROW_HEADER: "calrowhead",
		CSS_ROW_FOOTER: "calrowfoot",
		CSS_CELL : "calcell",
		CSS_CELL_SELECTED : "selected",
		CSS_CELL_RESTRICTED : "restricted",
		CSS_CELL_TODAY : "today",
		CSS_CELL_OOM : "oom",
		CSS_CELL_OOB : "previous",
		CSS_HEADER : "calheader",
		CSS_HEADER_TEXT : "calhead",
		CSS_WEEKDAY_CELL : "calweekdaycell",
		CSS_WEEKDAY_ROW : "calweekdayrow",
		CSS_FOOTER : "calfoot",
		CSS_CALENDAR : "calendar",
		CSS_BORDER : "calbordered",
		CSS_CONTAINER : "calcontainer", 
		CSS_NAV_LEFT : "calnavleft",
		CSS_NAV_RIGHT : "calnavright",
		CSS_CELL_TOP : "calcelltop",
		CSS_CELL_LEFT : "calcellleft",
		CSS_CELL_RIGHT : "calcellright",
		CSS_CELL_BOTTOM : "calcellbottom",
		CSS_CELL_HOVER : "calcellhover",
		CSS_CELL_HIGHLIGHT1 : "highlight1",
		CSS_CELL_HIGHLIGHT2 : "highlight2",
		CSS_CELL_HIGHLIGHT3 : "highlight3",
		CSS_CELL_HIGHLIGHT4 : "highlight4"
	};

	this.Style = this.Config.Style;

	this.Config.Locale = {

		MONTHS_SHORT : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
		MONTHS_LONG : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
		WEEKDAYS_1CHAR : ["S", "M", "T", "W", "T", "F", "S"],
		WEEKDAYS_SHORT : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
		WEEKDAYS_MEDIUM : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
		WEEKDAYS_LONG : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
		DATE_DELIMITER : ",",
		DATE_FIELD_DELIMITER : "/",
		DATE_RANGE_DELIMITER : "-",
		MY_MONTH_POSITION : 1,
		MY_YEAR_POSITION : 2,
		MD_MONTH_POSITION : 1,
		MD_DAY_POSITION : 2,
		MDY_MONTH_POSITION : 1,
		MDY_DAY_POSITION : 2,
		MDY_YEAR_POSITION : 3
	};

	this.Locale = this.Config.Locale;

	this.Config.Options = {

		MULTI_SELECT : false,
		SHOW_WEEKDAYS : true,
		START_WEEKDAY : 0,
		SHOW_WEEK_HEADER : false,
		SHOW_WEEK_FOOTER : false,
		HIDE_BLANK_WEEKS : false,
		NAV_ARROW_LEFT : WCT.widget.Calendar_Core.IMG_ROOT + "/WCTpages/images/tsps.gif",
		NAV_ARROW_RIGHT : WCT.widget.Calendar_Core.IMG_ROOT + "/WCTpages/images/tsp.gif"
	};

	this.Options = this.Config.Options;

	this.customConfig();

	if (! this.Options.LOCALE_MONTHS) {
		this.Options.LOCALE_MONTHS=this.Locale.MONTHS_LONG;
	}
	if (! this.Options.LOCALE_WEEKDAYS) {
		this.Options.LOCALE_WEEKDAYS=this.Locale.WEEKDAYS_SHORT;
	}

	if (this.Options.START_WEEKDAY > 0)
	{
		for (var w=0;w<this.Options.START_WEEKDAY;++w) {
			this.Locale.WEEKDAYS_SHORT.push(this.Locale.WEEKDAYS_SHORT.shift());
			this.Locale.WEEKDAYS_MEDIUM.push(this.Locale.WEEKDAYS_MEDIUM.shift());
			this.Locale.WEEKDAYS_LONG.push(this.Locale.WEEKDAYS_LONG.shift());		
		}
	}
};

WCT.widget.Calendar_Core.prototype.customConfig = function() { };

WCT.widget.Calendar_Core.prototype.buildMonthLabel = function() {
	var text = this.Options.LOCALE_MONTHS[this.pageDate.getMonth()] + " " + this.pageDate.getFullYear();
	return text;
};

WCT.widget.Calendar_Core.prototype.buildDayLabel = function(workingDate) {
	var day = workingDate.getDate();
	return day;
};

WCT.widget.Calendar_Core.prototype.buildShell = function() {
	
	this.table = document.createElement("TABLE");
	this.table.cellSpacing = 0;	
	WCT.widget.Calendar_Core.setCssClasses(this.table, [this.Style.CSS_CALENDAR]);

	this.table.id = this.id;
	
	this.buildShellHeader();
	this.buildShellBody();
	this.buildShellFooter();
	
	WCT.util.Event.addListener(window, "unload", this._unload, this);
};

WCT.widget.Calendar_Core.prototype.buildShellHeader = function() {
	var head = document.createElement("THEAD");
	var headRow = document.createElement("TR");

	var headerCell = document.createElement("TH");
	
	var colSpan = 7;
	if (this.Config.Options.SHOW_WEEK_HEADER) {
		this.weekHeaderCells = new Array();
		colSpan += 1;
	}
	if (this.Config.Options.SHOW_WEEK_FOOTER) {
		this.weekFooterCells = new Array();
		colSpan += 1;
	}	
	
	headerCell.colSpan = colSpan;
	
	WCT.widget.Calendar_Core.setCssClasses(headerCell,[this.Style.CSS_HEADER_TEXT]);

	this.headerCell = headerCell;

	headRow.appendChild(headerCell);
	head.appendChild(headRow);

	if (this.Options.SHOW_WEEKDAYS)
	{
		var row = document.createElement("TR");
		var fillerCell;

		WCT.widget.Calendar_Core.setCssClasses(row,[this.Style.CSS_WEEKDAY_ROW]);
		
		if (this.Config.Options.SHOW_WEEK_HEADER) {
			fillerCell = document.createElement("TH");
			WCT.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
			row.appendChild(fillerCell);
		}
		
		for(var i=0;i<this.Options.LOCALE_WEEKDAYS.length;++i)
		{
			var cell = document.createElement("TH");
			WCT.widget.Calendar_Core.setCssClasses(cell,[this.Style.CSS_WEEKDAY_CELL]);
			cell.innerHTML=this.Options.LOCALE_WEEKDAYS[i];
			row.appendChild(cell);
		}

		if (this.Config.Options.SHOW_WEEK_FOOTER) {
			fillerCell = document.createElement("TH");
			WCT.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
			row.appendChild(fillerCell);
		}
				
		head.appendChild(row);
	}

	this.table.appendChild(head);
};

WCT.widget.Calendar_Core.prototype.buildShellBody = function() {

	this.tbody = document.createElement("TBODY");

	for (var r=0;r<6;++r)
	{
		var row = document.createElement("TR");
		
		for (var c=0;c<this.headerCell.colSpan;++c)
		{
			var cell;
			if (this.Config.Options.SHOW_WEEK_HEADER && c===0) { 
				cell = document.createElement("TH");
				this.weekHeaderCells[this.weekHeaderCells.length] = cell;
			} else if (this.Config.Options.SHOW_WEEK_FOOTER && c==(this.headerCell.colSpan-1)){ 
				cell = document.createElement("TH");
				this.weekFooterCells[this.weekFooterCells.length] = cell;
			} else {
				cell = document.createElement("TD");
				this.cells[this.cells.length] = cell;
				WCT.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL]);
				WCT.util.Event.addListener(cell, "click", this.doSelectCell, this);

				WCT.util.Event.addListener(cell, "mouseover", this.doCellMouseOver, this);
				WCT.util.Event.addListener(cell, "mouseout", this.doCellMouseOut, this);
			}
			row.appendChild(cell);
		}
		this.tbody.appendChild(row);
	}
	
	this.table.appendChild(this.tbody);
};

WCT.widget.Calendar_Core.prototype.buildShellFooter = function() { };

WCT.widget.Calendar_Core.prototype.renderShell = function() {
	this.oDomContainer.appendChild(this.table);
	this.shellRendered = true;
};

WCT.widget.Calendar_Core.prototype.render = function() {
	if (! this.shellRendered)
	{
		this.buildShell();
		this.renderShell();
	}

	this.resetRenderers();

	this.cellDates.length = 0;

	var workingDate = WCT.widget.DateMath.findMonthStart(this.pageDate);

	this.renderHeader();
	this.renderBody(workingDate);
	this.renderFooter();

	this.onRender();
};

WCT.widget.Calendar_Core.prototype.renderHeader = function() {
	this.headerCell.innerHTML = "";
	
	var headerContainer = document.createElement("DIV");
	headerContainer.className = this.Style.CSS_HEADER;
	
	headerContainer.appendChild(document.createTextNode(this.buildMonthLabel()));
	
	this.headerCell.appendChild(headerContainer);
};

WCT.widget.Calendar_Core.prototype.renderBody = function(workingDate) {

	this.preMonthDays = workingDate.getDay();
	if (this.Options.START_WEEKDAY > 0) {
		this.preMonthDays -= this.Options.START_WEEKDAY;
	}
	if (this.preMonthDays < 0) {
		this.preMonthDays += 7;
	}
	
	this.monthDays = WCT.widget.DateMath.findMonthEnd(workingDate).getDate();
	this.postMonthDays = WCT.widget.Calendar_Core.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
	
	workingDate = WCT.widget.DateMath.subtract(workingDate, WCT.widget.DateMath.DAY, this.preMonthDays);
	
	var weekRowIndex = 0;
	
	for (var c=0;c<this.cells.length;++c)
	{
		var cellRenderers = new Array();
		
		var cell = this.cells[c];
		this.clearElement(cell);

		cell.index = c;
		cell.id = this.id + "_cell" + c;
		
		this.cellDates[this.cellDates.length]=[workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()];

		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
			var rowHeaderCell = null;
			var rowFooterCell = null;
			
			if (this.Options.SHOW_WEEK_HEADER) {
				rowHeaderCell = this.weekHeaderCells[weekRowIndex];
				this.clearElement(rowHeaderCell);
			}
			
			if (this.Options.SHOW_WEEK_FOOTER) {
				rowFooterCell = this.weekFooterCells[weekRowIndex];
				this.clearElement(rowFooterCell);
			}			
			
			if (this.Options.HIDE_BLANK_WEEKS && this.isDateOOM(workingDate) && ! WCT.widget.DateMath.isMonthOverlapWeek(workingDate)) {
				continue;
			} else {
				if (rowHeaderCell) {
					this.renderRowHeader(workingDate, rowHeaderCell);
				}
				if (rowFooterCell) {
					this.renderRowFooter(workingDate, rowFooterCell);
				}	
			}
		}

		

		var renderer = null;
		
		if (workingDate.getFullYear()	== this.today.getFullYear() &&
			workingDate.getMonth()		== this.today.getMonth() &&
			workingDate.getDate()		== this.today.getDate())
		{
			cellRenderers[cellRenderers.length]=this.renderCellStyleToday;
		}
		
		if (this.isDateOOM(workingDate))
		{
			cellRenderers[cellRenderers.length]=this.renderCellNotThisMonth;
		} else {
			for (var r=0;r<this.renderStack.length;++r)
			{
				var rArray = this.renderStack[r];
				var type = rArray[0];
				
				var month;
				var day;
				var year;

				switch (type) {
					case WCT.widget.Calendar_Core.DATE:
						month = rArray[1][1];
						day = rArray[1][2];
						year = rArray[1][0];

						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year)
						{
							renderer = rArray[2];
							this.renderStack.splice(r,1);
						}
						break;
					case WCT.widget.Calendar_Core.MONTH_DAY:
						month = rArray[1][0];
						day = rArray[1][1];
						
						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day)
						{
							renderer = rArray[2];
							this.renderStack.splice(r,1);
						}
						break;
					case WCT.widget.Calendar_Core.RANGE:
						var date1 = rArray[1][0];
						var date2 = rArray[1][1];

						var d1month = date1[1];
						var d1day = date1[2];
						var d1year = date1[0];
						
						var d1 = new Date(d1year, d1month-1, d1day);

						var d2month = date2[1];
						var d2day = date2[2];
						var d2year = date2[0];

						var d2 = new Date(d2year, d2month-1, d2day);

						if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime())
						{
							renderer = rArray[2];

							if (workingDate.getTime()==d2.getTime()) { 
								this.renderStack.splice(r,1);
							}
						}
						break;
					case WCT.widget.Calendar_Core.WEEKDAY:
						
						var weekday = rArray[1][0];
						if (workingDate.getDay()+1 == weekday)
						{
							renderer = rArray[2];
						}
						break;
					case WCT.widget.Calendar_Core.MONTH:
						
						month = rArray[1][0];
						if (workingDate.getMonth()+1 == month)
						{
							renderer = rArray[2];
						}
						break;
				}
				
				if (renderer) {
					cellRenderers[cellRenderers.length]=renderer;
				}
			}

		}

		if (this._indexOfSelectedFieldArray([workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]) > -1)
		{
			cellRenderers[cellRenderers.length]=this.renderCellStyleSelected; 
		}

		if (this.minDate)
		{
			this.minDate = WCT.widget.DateMath.clearTime(this.minDate);
		}
		if (this.maxDate)
		{
			this.maxDate = WCT.widget.DateMath.clearTime(this.maxDate);
		}

		if (
			(this.minDate && (workingDate.getTime() < this.minDate.getTime())) ||
			(this.maxDate && (workingDate.getTime() > this.maxDate.getTime()))
		) {
			cellRenderers[cellRenderers.length]=this.renderOutOfBoundsDate;
		} else {
			cellRenderers[cellRenderers.length]=this.renderCellDefault;	
		}
		
		for (var x=0;x<cellRenderers.length;++x)
		{
			var ren = cellRenderers[x];
			if (ren.call(this,workingDate,cell) == WCT.widget.Calendar_Core.STOP_RENDER) {
				break;
			}
		}
		
		workingDate = WCT.widget.DateMath.add(workingDate, WCT.widget.DateMath.DAY, 1);
		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
			weekRowIndex += 1;
		}

		WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL);
		if (c >= 0 && c <= 6) {
			WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_TOP);
		}
		if ((c % 7) == 0) {
			WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_LEFT);
		}
		if (((c+1) % 7) == 0) {
			WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_RIGHT);
		}
		
		var postDays = this.postMonthDays; 
		if (postDays >= 7 && this.Options.HIDE_BLANK_WEEKS) {
			var blankWeeks = Math.floor(postDays/7);
			for (var p=0;p<blankWeeks;++p) {
				postDays -= 7;
			}
		}
		
		if (c >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
			WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_BOTTOM);
		}
	}
		
};

WCT.widget.Calendar_Core.prototype.renderFooter = function() { };

WCT.widget.Calendar_Core.prototype._unload = function(e, cal) {
	for (var c in cal.cells) {
		c = null;
	}
	
	cal.cells = null;
	
	cal.tbody = null;
	cal.oDomContainer = null;
	cal.table = null;
	cal.headerCell = null;
	
	cal = null;
};

WCT.widget.Calendar_Core.prototype.renderOutOfBoundsDate = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOB);
	cell.innerHTML = workingDate.getDate();
	return WCT.widget.Calendar_Core.STOP_RENDER;
}

WCT.widget.Calendar_Core.prototype.renderRowHeader = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_ROW_HEADER);
	
	var useYear = this.pageDate.getFullYear();
	
	if (! WCT.widget.DateMath.isYearOverlapWeek(workingDate)) {
		useYear = workingDate.getFullYear();
	}
	
	var weekNum = WCT.widget.DateMath.getWeekNumber(workingDate, useYear, this.Options.START_WEEKDAY);
	cell.innerHTML = weekNum;
	
	if (this.isDateOOM(workingDate) && ! WCT.widget.DateMath.isMonthOverlapWeek(workingDate)) {
		WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);	
	}
};

WCT.widget.Calendar_Core.prototype.renderRowFooter = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_ROW_FOOTER);
	
	if (this.isDateOOM(workingDate) && ! WCT.widget.DateMath.isMonthOverlapWeek(workingDate)) {
		WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);	
	}
};

WCT.widget.Calendar_Core.prototype.renderCellDefault = function(workingDate, cell) {
	cell.innerHTML = "";
	var link = document.createElement("a");

	link.href="javascript:void(null);";
	link.name=this.id+"__"+workingDate.getFullYear()+"_"+(workingDate.getMonth()+1)+"_"+workingDate.getDate();

	link.appendChild(document.createTextNode(this.buildDayLabel(workingDate)));
	cell.appendChild(link);
};

WCT.widget.Calendar_Core.prototype.renderCellStyleHighlight1 = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
};
WCT.widget.Calendar_Core.prototype.renderCellStyleHighlight2 = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
};
WCT.widget.Calendar_Core.prototype.renderCellStyleHighlight3 = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
};
WCT.widget.Calendar_Core.prototype.renderCellStyleHighlight4 = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
};

WCT.widget.Calendar_Core.prototype.renderCellStyleToday = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_TODAY);
};

WCT.widget.Calendar_Core.prototype.renderCellStyleSelected = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_SELECTED);
};

WCT.widget.Calendar_Core.prototype.renderCellNotThisMonth = function(workingDate, cell) {
	WCT.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);
	cell.innerHTML=workingDate.getDate();
	return WCT.widget.Calendar_Core.STOP_RENDER;
};

WCT.widget.Calendar_Core.prototype.renderBodyCellRestricted = function(workingDate, cell) {
	WCT.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL,this.Style.CSS_CELL_RESTRICTED]);
	cell.innerHTML=workingDate.getDate();
	return WCT.widget.Calendar_Core.STOP_RENDER;
};

WCT.widget.Calendar_Core.prototype.addMonths = function(count) {
	this.pageDate = WCT.widget.DateMath.add(this.pageDate, WCT.widget.DateMath.MONTH, count);
	this.resetRenderers();
	this.onChangePage();
};

WCT.widget.Calendar_Core.prototype.subtractMonths = function(count) {
	this.pageDate = WCT.widget.DateMath.subtract(this.pageDate, WCT.widget.DateMath.MONTH, count);
	this.resetRenderers();
	this.onChangePage();
};

WCT.widget.Calendar_Core.prototype.addYears = function(count) {
	this.pageDate = WCT.widget.DateMath.add(this.pageDate, WCT.widget.DateMath.YEAR, count);
	this.resetRenderers();
	this.onChangePage();
};

WCT.widget.Calendar_Core.prototype.subtractYears = function(count) {
	this.pageDate = WCT.widget.DateMath.subtract(this.pageDate, WCT.widget.DateMath.YEAR, count);
	this.resetRenderers();
	this.onChangePage();
};

WCT.widget.Calendar_Core.prototype.nextMonth = function() {
	this.addMonths(1);
};

WCT.widget.Calendar_Core.prototype.previousMonth = function() {
	this.subtractMonths(1);
};

WCT.widget.Calendar_Core.prototype.nextYear = function() {
	this.addYears(1);
};

WCT.widget.Calendar_Core.prototype.previousYear = function() {
	this.subtractYears(1);
};

WCT.widget.Calendar_Core.prototype.reset = function() {
	this.selectedDates.length = 0;
	this.selectedDates = this._selectedDates.concat();

	this.pageDate = new Date(this._pageDate.getTime());
	this.onReset();
};

WCT.widget.Calendar_Core.prototype.clear = function() {
	this.selectedDates.length = 0;
	this.pageDate = new Date(this.today.getTime());
	this.onClear();
};

WCT.widget.Calendar_Core.prototype.select = function(date) {
	this.onBeforeSelect();

	var aToBeSelected = this._toFieldArray(date);

	for (var a=0;a<aToBeSelected.length;++a)
	{
		var toSelect = aToBeSelected[a]; 
		if (this._indexOfSelectedFieldArray(toSelect) == -1) 
		{	
			this.selectedDates[this.selectedDates.length]=toSelect;
		}
	}
	
	if (this.parent) {
		this.parent.sync(this);
	}

	this.onSelect();

	return this.getSelectedDates();
};

WCT.widget.Calendar_Core.prototype.selectCell = function(cellIndex) {
	this.onBeforeSelect();

	this.cells = this.tbody.getElementsByTagName("TD");

	var cell = this.cells[cellIndex];
	var cellDate = this.cellDates[cellIndex];

	var dCellDate = this._toDate(cellDate);

	var selectDate = cellDate.concat();

	this.selectedDates.push(selectDate);
	
	if (this.parent) {
		this.parent.sync(this);
	}

	this.renderCellStyleSelected(dCellDate,cell);

	this.onSelect();
	this.doCellMouseOut.call(cell, null, this);

	return this.getSelectedDates();
};

WCT.widget.Calendar_Core.prototype.deselect = function(date) {
	this.onBeforeDeselect();

	var aToBeSelected = this._toFieldArray(date);

	for (var a=0;a<aToBeSelected.length;++a)
	{
		var toSelect = aToBeSelected[a];
		var index = this._indexOfSelectedFieldArray(toSelect);
	
		if (index != -1)
		{	
			this.selectedDates.splice(index,1);
		}
	}

	if (this.parent) {
		this.parent.sync(this);
	} 

	this.onDeselect();
	return this.getSelectedDates();
};

WCT.widget.Calendar_Core.prototype.deselectCell = function(i) {
	this.onBeforeDeselect();
	this.cells = this.tbody.getElementsByTagName("TD");

	var cell = this.cells[i];
	var cellDate = this.cellDates[i];
	var cellDateIndex = this._indexOfSelectedFieldArray(cellDate);

	var dCellDate = this._toDate(cellDate);

	var selectDate = cellDate.concat();

	if (cellDateIndex > -1)
	{
		if (this.pageDate.getMonth() == dCellDate.getMonth() &&
			this.pageDate.getFullYear() == dCellDate.getFullYear())
		{
			WCT.widget.Calendar_Core.removeCssClass(cell, this.Style.CSS_CELL_SELECTED);
		}

		this.selectedDates.splice(cellDateIndex, 1);
	}


	if (this.parent) {
		this.parent.sync(this);
	}

	this.onDeselect();
	return this.getSelectedDates();
};

WCT.widget.Calendar_Core.prototype.deselectAll = function() {
	this.onBeforeDeselect();
	var count = this.selectedDates.length;
	this.selectedDates.length = 0;

	if (this.parent) {
		this.parent.sync(this);
	}
	
	if (count > 0) {
		this.onDeselect();
	}

	return this.getSelectedDates();
};

WCT.widget.Calendar_Core.prototype._toFieldArray = function(date) {
	var returnDate = new Array();

	if (date instanceof Date)
	{
		returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
	} 
	else if (typeof date == 'string')
	{
		returnDate = this._parseDates(date);
	}
	else if (date instanceof Array)
	{
		for (var i=0;i<date.length;++i)
		{
			var d = date[i];
			returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
		}
	}
	
	return returnDate;
};

WCT.widget.Calendar_Core.prototype._toDate = function(dateFieldArray) {
	if (dateFieldArray instanceof Date)
	{
		return dateFieldArray;
	} else 	
	{
		return new Date(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
	}
};

WCT.widget.Calendar_Core.prototype._fieldArraysAreEqual = function(array1, array2) {
	var match = false;

	if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2])
	{
		match=true;	
	}

	return match;
};

WCT.widget.Calendar_Core.prototype._indexOfSelectedFieldArray = function(find) {
	var selected = -1;

	for (var s=0;s<this.selectedDates.length;++s)
	{
		var sArray = this.selectedDates[s];
		if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2])
		{
			selected = s;
			break;
		}
	}

	return selected;
};

WCT.widget.Calendar_Core.prototype.isDateOOM = function(date) {
	var isOOM = false;
	if (date.getMonth() != this.pageDate.getMonth()) {
		isOOM = true;
	}
	return isOOM;
};

WCT.widget.Calendar_Core.prototype.onBeforeSelect = function() {
	if (! this.Options.MULTI_SELECT) {
		this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
		this.deselectAll();
	}
};

WCT.widget.Calendar_Core.prototype.onSelect = function() { };

WCT.widget.Calendar_Core.prototype.onBeforeDeselect = function() { };

WCT.widget.Calendar_Core.prototype.onDeselect = function() { };

WCT.widget.Calendar_Core.prototype.onChangePage = function() {
		var me = this;

		this.renderHeader();
		if (this.renderProcId) {
			clearTimeout(this.renderProcId);
		}
		this.renderProcId = setTimeout(function() {
											me.render();
											me.renderProcId = null;
										}, 1);
};

WCT.widget.Calendar_Core.prototype.onRender = function() { };

WCT.widget.Calendar_Core.prototype.onReset = function() { this.render(); };

WCT.widget.Calendar_Core.prototype.onClear = function() { this.render(); };

WCT.widget.Calendar_Core.prototype.validate = function() { return true; };

WCT.widget.Calendar_Core.prototype._parseDate = function(sDate) {
	var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER);
	var rArray;

	if (aDate.length == 2)
	{
		rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
		rArray.type = WCT.widget.Calendar_Core.MONTH_DAY;
	} else {
		rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
		rArray.type = WCT.widget.Calendar_Core.DATE;
	}
	return rArray;
};

WCT.widget.Calendar_Core.prototype._parseDates = function(sDates) {
	var aReturn = new Array();

	var aDates = sDates.split(this.Locale.DATE_DELIMITER);
	
	for (var d=0;d<aDates.length;++d)
	{
		var sDate = aDates[d];

		if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {

			var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER);

			var dateStart = this._parseDate(aRange[0]);
			var dateEnd = this._parseDate(aRange[1]);

			var fullRange = this._parseRange(dateStart, dateEnd);
			aReturn = aReturn.concat(fullRange);
		} else {

			var aDate = this._parseDate(sDate);
			aReturn.push(aDate);
		}
	}
	return aReturn;
};

WCT.widget.Calendar_Core.prototype._parseRange = function(startDate, endDate) {
	var dStart   = new Date(startDate[0],startDate[1]-1,startDate[2]);
	var dCurrent = WCT.widget.DateMath.add(new Date(startDate[0],startDate[1]-1,startDate[2]),WCT.widget.DateMath.DAY,1);
	var dEnd     = new Date(endDate[0],  endDate[1]-1,  endDate[2]);

	var results = new Array();
	results.push(startDate);
	while (dCurrent.getTime() <= dEnd.getTime())
	{
		results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
		dCurrent = WCT.widget.DateMath.add(dCurrent,WCT.widget.DateMath.DAY,1);
	}
	return results;
};

WCT.widget.Calendar_Core.prototype.resetRenderers = function() {
	this.renderStack = this._renderStack.concat();
};

WCT.widget.Calendar_Core.prototype.clearElement = function(cell) {
	cell.innerHTML = "&nbsp;";
	cell.className="";
};

WCT.widget.Calendar_Core.prototype.addRenderer = function(sDates, fnRender) {
	var aDates = this._parseDates(sDates);
	for (var i=0;i<aDates.length;++i)
	{
		var aDate = aDates[i];
	
		if (aDate.length == 2) 
		{
			if (aDate[0] instanceof Array) 
			{
				this._addRenderer(WCT.widget.Calendar_Core.RANGE,aDate,fnRender);
			} else { 
				this._addRenderer(WCT.widget.Calendar_Core.MONTH_DAY,aDate,fnRender);
			}
		} else if (aDate.length == 3)
		{
			this._addRenderer(WCT.widget.Calendar_Core.DATE,aDate,fnRender);
		}
	}
};

WCT.widget.Calendar_Core.prototype._addRenderer = function(type, aDates, fnRender) {
	var add = [type,aDates,fnRender];
	this.renderStack.unshift(add);	
	
	this._renderStack = this.renderStack.concat();
};


WCT.widget.Calendar_Core.prototype.addMonthRenderer = function(month, fnRender) {
	this._addRenderer(WCT.widget.Calendar_Core.MONTH,[month],fnRender);
};

WCT.widget.Calendar_Core.prototype.addWeekdayRenderer = function(weekday, fnRender) {
	this._addRenderer(WCT.widget.Calendar_Core.WEEKDAY,[weekday],fnRender);
};

WCT.widget.Calendar_Core.addCssClass = function(element, style) {
	if (element.className.length === 0)
	{
		element.className += style;
	} else {
		element.className += " " + style;
	}
};

WCT.widget.Calendar_Core.prependCssClass = function(element, style) {
	element.className = style + " " + element.className;
}

WCT.widget.Calendar_Core.removeCssClass = function(element, style) {
	var aStyles = element.className.split(" ");
	for (var s=0;s<aStyles.length;++s)
	{
		if (aStyles[s] == style)
		{
			aStyles.splice(s,1);
			break;
		}
	}
	WCT.widget.Calendar_Core.setCssClasses(element, aStyles);
};

WCT.widget.Calendar_Core.setCssClasses = function(element, aStyles) {
	element.className = "";
	var className = aStyles.join(" ");
	element.className = className;
};


WCT.widget.Calendar_Core.prototype.clearAllBodyCellStyles = function(style) {
	for (var c=0;c<this.cells.length;++c)
	{
		WCT.widget.Calendar_Core.removeCssClass(this.cells[c],style);
	}
};


WCT.widget.Calendar_Core.prototype.setMonth = function(month) {
	this.pageDate.setMonth(month);
};

WCT.widget.Calendar_Core.prototype.setYear = function(year) {
	this.pageDate.setFullYear(year);
};

WCT.widget.Calendar_Core.prototype.getSelectedDates = function() {
	var returnDates = new Array();

	for (var d=0;d<this.selectedDates.length;++d)
	{
		var dateArray = this.selectedDates[d];

		var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
		returnDates.push(date);
	}

	returnDates.sort();
	return returnDates;
};

WCT.widget.Calendar_Core._getBrowser = function()
{

  var ua = navigator.userAgent.toLowerCase();
  
  if (ua.indexOf('opera')!=-1)
	 return 'opera';
  else if (ua.indexOf('msie')!=-1)
	 return 'ie';
  else if (ua.indexOf('safari')!=-1) 
	 return 'safari';
  else if (ua.indexOf('gecko') != -1)
	 return 'gecko';
 else
  return false;
}


WCT.widget.Cal_Core = WCT.widget.Calendar_Core;

WCT.widget.Calendar = function(id, containerId, monthyear, selected) {
	if (arguments.length > 0)
	{
		this.init(id, containerId, monthyear, selected);
	}
}

WCT.widget.Calendar.prototype = new WCT.widget.Calendar_Core();

WCT.widget.Calendar.prototype.buildShell = function() {
	this.border = document.createElement("DIV");
	this.border.className =  this.Style.CSS_BORDER;
	
	this.table = document.createElement("TABLE");
	this.table.cellSpacing = 0;	
	
	WCT.widget.Calendar_Core.setCssClasses(this.table, [this.Style.CSS_CALENDAR]);

	this.border.id = this.id;
	
	this.buildShellHeader();
	this.buildShellBody();
	this.buildShellFooter();
};

WCT.widget.Calendar.prototype.renderShell = function() {
	this.border.appendChild(this.table);
	this.oDomContainer.appendChild(this.border);
	this.shellRendered = true;
};


WCT.widget.Cal = WCT.widget.Calendar;














/*Software License Agreement (BSD License)
Copyright (c) 2006, Yahoo! Inc.
All rights reserved.
Redistribution and use of this software in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other
  materials provided with the distribution.
* Neither the name of Yahoo! Inc. nor the names of its
  contributors may be used to endorse or promote products
  derived from this software without specific prior
  written permission of Yahoo! Inc.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/







