/*
 * jQuery UI @VERSION
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
;(function($) {

/** jQuery core modifications and additions **/
$.keyCode = {
        BACKSPACE: 8,
        CAPS_LOCK: 20,
        COMMA: 188,
        CONTROL: 17,
        DELETE: 46,
        DOWN: 40,
        END: 35,
        ENTER: 13,
        ESCAPE: 27,
        HOME: 36,
        INSERT: 45,
        LEFT: 37,
        NUMPAD_ADD: 107,
        NUMPAD_DECIMAL: 110,
        NUMPAD_DIVIDE: 111,
        NUMPAD_ENTER: 108,
        NUMPAD_MULTIPLY: 106,
        NUMPAD_SUBTRACT: 109,
        PAGE_DOWN: 34,
        PAGE_UP: 33,
        PERIOD: 190,
        RIGHT: 39,
        SHIFT: 16,
        SPACE: 32,
        TAB: 9,
        UP: 38
};

//Temporary mappings
var _remove = $.fn.remove;
var isFF2 = $.browser.mozilla && (parseFloat($.browser.version) < 1.9);


//Helper functions and ui object
$.ui = {
        
        version: "@VERSION",
        
        // $.ui.plugin is deprecated.  Use the proxy pattern instead.
        plugin: {
                add: function(module, option, set) {
                        var proto = $.ui[module].prototype;
                        for(var i in set) {
                                proto.plugins[i] = proto.plugins[i] || [];
                                proto.plugins[i].push([option, set[i]]);
                        }
                },
                call: function(instance, name, args) {
                        var set = instance.plugins[name];
                        if(!set) { return; }
                        
                        for (var i = 0; i < set.length; i++) {
                                if (instance.options[set[i][0]]) {
                                        set[i][1].apply(instance.element, args);
                                }
                        }
                }        
        },
        
        cssCache: {},
        css: function(name) {
                if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
                var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
                
                //if (!$.browser.safari)
                        //tmp.appendTo('body');
                
                //Opera and Safari set width and height to 0px instead of auto
                //Safari returns rgba(0,0,0,0) when bgcolor is not set
                $.ui.cssCache[name] = !!(
                        (!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
                        !(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
                );
                try { $('body').get(0).removeChild(tmp.get(0));        } catch(e){}
                return $.ui.cssCache[name];
        },

        hasScroll: function(e, a) {
                
                //If overflow is hidden, the element might have extra content, but the user wants to hide it
                if ($(e).css('overflow') == 'hidden') { return false; }
                
                var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
                        has = false;
                
                if (e[scroll] > 0) { return true; }
                
                // TODO: determine which cases actually cause this to happen
                // if the element doesn't have the scroll set, see if it's possible to
                // set the scroll
                e[scroll] = 1;
                has = (e[scroll] > 0);
                e[scroll] = 0;
                return has;
        }
};


//jQuery plugins
$.fn.extend({
        
        remove: function() {
                // Safari has a native remove event which actually removes DOM elements,
                // so we have to use triggerHandler instead of trigger (#3037).
                $("*", this).add(this).each(function() {
                        $(this).triggerHandler("remove");
                });
                return _remove.apply(this, arguments );
        },
        
        enableSelection: function() {
                return this
                        .attr('unselectable', 'off')
                        .css('MozUserSelect', '')
                        .unbind('selectstart.ui');
        },
        
        disableSelection: function() {
                return this
                        .attr('unselectable', 'on')
                        .css('MozUserSelect', 'none')
                        .bind('selectstart.ui', function() { return false; });
        },
        
        // WAI-ARIA Semantics
        ariaRole: function(role) {
                return (role !== undefined
                        
                        // setter
                        ? this.attr("role", isFF2 ? "wairole:" + role : role)
                        
                        // getter
                        : (this.attr("role") || "").replace(/^wairole:/, ""));
        },
        
        ariaState: function(state, value) {
                return (value !== undefined
                        
                        // setter
                        ? this.each(function(i, el) {
                                (isFF2
                                        ? el.setAttributeNS("http://www.w3.org/2005/07/aaa",
                                                "aaa:" + state, value)
                                        : $(el).attr("aria-" + state, value));
                        })
                        
                        // getter
                        : this.attr(isFF2 ? "aaa:" + state : "aria-" + state));
        }
        
});


//Additional selectors
$.extend($.expr[':'], {
        
        data: function(a, i, m) {
                return $.data(a, m[3]);
        },
        
        // TODO: add support for object, area
        tabbable: function(a, i, m) {

                var nodeName = a.nodeName.toLowerCase();
                var isVisible = function(element) {
                        function checkStyles(element) {
                                var style = element.style;
                                return (style.display != 'none' && style.visibility != 'hidden');
                        }
                        
                        var visible = checkStyles(element);
                        
                        (visible && $.each($.dir(element, 'parentNode'), function() {
                                return (visible = checkStyles(this));
                        }));
                        
                        return visible;
                };
                
                return (
                        // in tab order
                        a.tabIndex >= 0 &&
                        
                        ( // filter node types that participate in the tab order
                                
                                // anchor tag
                                ('a' == nodeName && a.href) ||
                                
                                // enabled form element
                                (/input|select|textarea|button/.test(nodeName) &&
                                        'hidden' != a.type && !a.disabled)
                        ) &&
                        
                        // visible on page
                        isVisible(a)
                );
                
        }
        
});


// $.widget is a factory to create jQuery plugins
// taking some boilerplate code out of the plugin code
// created by Scott Gonz?lez and Jörn Zaefferer
function getter(namespace, plugin, method, args) {
        function getMethods(type) {
                var methods = $[namespace][plugin][type] || [];
                return (typeof methods == 'string' ? methods.split(/,?\s+/) : methods);
        }
        
        var methods = getMethods('getter');
        if (args.length == 1 && typeof args[0] == 'string') {
                methods = methods.concat(getMethods('getterSetter'));
        }
        return ($.inArray(method, methods) != -1);
}

$.widget = function(name, prototype) {
        var namespace = name.split(".")[0];
        name = name.split(".")[1];
        
        // create plugin method
        $.fn[name] = function(options) {
                var isMethodCall = (typeof options == 'string'),
                        args = Array.prototype.slice.call(arguments, 1);
                
                // prevent calls to internal methods
                if (isMethodCall && options.substring(0, 1) == '_') {
                        return this;
                }
                
                // handle getter methods
                if (isMethodCall && getter(namespace, name, options, args)) {
                        var instance = $.data(this[0], name);
                        return (instance ? instance[options].apply(instance, args)
                                : undefined);
                }
                
                // handle initialization and non-getter methods
                return this.each(function() {
                        var instance = $.data(this, name);
                        
                        // constructor
                        (!instance && !isMethodCall &&
                                $.data(this, name, new $[namespace][name](this, options)));
                        
                        // method call
                        (instance && isMethodCall && $.isFunction(instance[options]) &&
                                instance[options].apply(instance, args));
                });
        };
        
        // create widget constructor
        $[namespace] = $[namespace] || {};
        $[namespace][name] = function(element, options) {
                var self = this;
                
                this.widgetName = name;
                this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
                this.widgetBaseClass = namespace + '-' + name;
                
                this.options = $.extend({},
                        $.widget.defaults,
                        $[namespace][name].defaults,
                        $.metadata && $.metadata.get(element)[name],
                        options);
                
                this.element = $(element)
                        .bind('setData.' + name, function(e, key, value) {
                                return self._setData(key, value);
                        })
                        .bind('getData.' + name, function(e, key) {
                                return self._getData(key);
                        })
                        .bind('remove', function() {
                                return self.destroy();
                        });
                
                this._init();
        };
        
        // add widget prototype
        $[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
        
        // TODO: merge getter and getterSetter properties from widget prototype
        // and plugin prototype
        $[namespace][name].getterSetter = 'option';
};

$.widget.prototype = {
        _init: function() {},
        destroy: function() {
                this.element.removeData(this.widgetName);
        },
        
        option: function(key, value) {
                var options = key,
                        self = this;
                
                if (typeof key == "string") {
                        if (value === undefined) {
                                return this._getData(key);
                        }
                        options = {};
                        options[key] = value;
                }
                
                $.each(options, function(key, value) {
                        self._setData(key, value);
                });
        },
        _getData: function(key) {
                return this.options[key];
        },
        _setData: function(key, value) {
                this.options[key] = value;
                
                if (key == 'disabled') {
                        this.element[value ? 'addClass' : 'removeClass'](
                                this.widgetBaseClass + '-disabled');
                }
        },
        
        enable: function() {
                this._setData('disabled', false);
        },
        disable: function() {
                this._setData('disabled', true);
        },
        
        _trigger: function(type, e, data) {
                var eventName = (type == this.widgetEventPrefix
                        ? type : this.widgetEventPrefix + type);
                e = e  || $.event.fix({ type: eventName, target: this.element[0] });
                return this.element.triggerHandler(eventName, [e, data], this.options[type]);
        }
};

$.widget.defaults = {
        disabled: false
};


/** Mouse Interaction Plugin **/

$.ui.mouse = {
        _mouseInit: function() {
                var self = this;
        
                this.element
                        .bind('mousedown.'+this.widgetName, function(e) {
                                return self._mouseDown(e);
                        })
                        .bind('click.'+this.widgetName, function(e) {
                                if(self._preventClickEvent) {
                                        self._preventClickEvent = false;
                                        return false;
                                }
                        });
                
                // Prevent text selection in IE
                if ($.browser.msie) {
                        this._mouseUnselectable = this.element.attr('unselectable');
                        this.element.attr('unselectable', 'on');
                }
                
                this.started = false;
        },
        
        // TODO: make sure destroying one instance of mouse doesn't mess with
        // other instances of mouse
        _mouseDestroy: function() {
                this.element.unbind('.'+this.widgetName);
                
                // Restore text selection in IE
                ($.browser.msie
                        && this.element.attr('unselectable', this._mouseUnselectable));
        },
        
        _mouseDown: function(e) {
                // we may have missed mouseup (out of window)
                (this._mouseStarted && this._mouseUp(e));
                
                this._mouseDownEvent = e;
                
                var self = this,
                        btnIsLeft = (e.which == 1),
                        elIsCancel = (typeof this.options.cancel == "string" ? $(e.target).parents().add(e.target).filter(this.options.cancel).length : false);
                if (!btnIsLeft || elIsCancel || !this._mouseCapture(e)) {
                        return true;
                }
                
                this.mouseDelayMet = !this.options.delay;
                if (!this.mouseDelayMet) {
                        this._mouseDelayTimer = setTimeout(function() {
                                self.mouseDelayMet = true;
                        }, this.options.delay);
                }
                
                if (this._mouseDistanceMet(e) && this._mouseDelayMet(e)) {
                        this._mouseStarted = (this._mouseStart(e) !== false);
                        if (!this._mouseStarted) {
                                e.preventDefault();
                                return true;
                        }
                }
                
                // these delegates are required to keep context
                this._mouseMoveDelegate = function(e) {
                        return self._mouseMove(e);
                };
                this._mouseUpDelegate = function(e) {
                        return self._mouseUp(e);
                };
                $(document)
                        .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
                        .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
                
                return false;
        },
        
        _mouseMove: function(e) {
                // IE mouseup check - mouseup happened when mouse was out of window
                if ($.browser.msie && !e.button) {
                        return this._mouseUp(e);
                }
                
                if (this._mouseStarted) {
                        this._mouseDrag(e);
                        return false;
                }
                
                if (this._mouseDistanceMet(e) && this._mouseDelayMet(e)) {
                        this._mouseStarted =
                                (this._mouseStart(this._mouseDownEvent, e) !== false);
                        (this._mouseStarted ? this._mouseDrag(e) : this._mouseUp(e));
                }
                
                return !this._mouseStarted;
        },
        
        _mouseUp: function(e) {
                $(document)
                        .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
                        .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
                
                if (this._mouseStarted) {
                        this._mouseStarted = false;
                        this._preventClickEvent = true;
                        this._mouseStop(e);
                }
                
                return false;
        },
        
        _mouseDistanceMet: function(e) {
                return (Math.max(
                                Math.abs(this._mouseDownEvent.pageX - e.pageX),
                                Math.abs(this._mouseDownEvent.pageY - e.pageY)
                        ) >= this.options.distance
                );
        },
        
        _mouseDelayMet: function(e) {
                return this.mouseDelayMet;
        },
        
        // These are placeholder methods, to be overriden by extending plugin
        _mouseStart: function(e) {},
        _mouseDrag: function(e) {},
        _mouseStop: function(e) {},
        _mouseCapture: function(e) { return true; }
};

$.ui.mouse.defaults = {
        cancel: null,
        distance: 1,
        delay: 0
};

})(jQuery);

