(function($) {
    // fix background flickering under IE6
    try {
        if (document.execCommand)
            document.execCommand('BackgroundImageCache', false, true);
    } catch (e) { }

    // Patching jQuery to correctly support mouseenter/mouseleave. Remove once fixed.

    function liveConvert( type, selector ) {
	    return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "&")].join(".");
    }

    function isBogus(element) {
        try {
            var parent = element.parentNode;
            return false;
        } catch (error) {
            return true;
        }
    }

    var routedLiveEvents = {
        mouseenter: 'mouseover',
        mouseleave: 'mouseout'
    };

    $.fn.extend({

        live: function(type, data, fn) {
            var bubble;

            if ($.isFunction(data)) {
                bubble = fn;
                fn = data;
                data = undefined;
            }

            var proxy = $.proxy(fn);

            if (routedLiveEvents[type]) {
                type = routedLiveEvents[type];
                proxy = $.proxy(fn, function(e) {
                    if (!isBogus(e.relatedTarget)) {
                        if (this !== e.relatedTarget && !$.contains(this, e.relatedTarget))
                            fn.apply(this, arguments);

                        if (bubble)
                            $(this.parentNode).trigger(e);
                    }
                });
            }

            $(this.context).bind(liveConvert(type, this.selector), {
                data: data, selector: this.selector, live: type
            }, proxy);

            return this;
        },

        die: function(type, fn) {
            if (routedLiveEvents[type])
                type = routedLiveEvents[type];
            
            jQuery(this.context).unbind(liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type} : null);
            return this;
        }
    });

    // End of patch

    // All Telerik-specific code and component objects will live in this namespace

    $.telerik = {

        delegate: function(context, handler) {
            return function(e) {
                handler.apply(context, [e, this]);
            };
        },

        hover: function() {
            $(this).addClass('t-state-hover');
        },

        leave: function() {
            $(this).removeClass('t-state-hover');
        },

        buttonHover: function() {
            $(this).addClass('t-button-hover');
        },

        buttonLeave: function() {
            $(this).removeClass('t-button-hover');
        },

        preventDefault: function(e) {
            e.preventDefault();
        },

        stringBuilder: function() {
            this.buffer = [];
        },

        ajaxError: function(element, eventName, xhr, status) {
            var prevented = this.trigger(element, eventName,
                {
                    XMLHttpRequest: xhr,
                    textStatus: status
                });

            if (!prevented) {
                if (status == 'error' && xhr.status != '0')
                    alert('Error! The requested URL returned ' + xhr.status + ' - ' + xhr.statusText);
                if (status == 'timeout')
                    alert('Error! Server timeout.');
            }
        },

        trigger: function(element, eventName, options) {
            var e = new $.Event(eventName);
            $.extend(e, options);
            $(element).trigger(e);
            return e.isDefaultPrevented();
        },

        defaultActionEvent: function(type, e, options) {
            return $.extend({
                type: type,
                preventDefault: function() {
                    e.preventDefault();
                }
            }, options);
        },

        fx: {}
    };

    $.telerik.stringBuilder.prototype = {

        cat: function(what) {
            this.buffer.push(what);
            return this;
        },

        string: function() {
            return this.buffer.join('');
        }
    }

    // Effects ($.telerik.fx)

    var prepareAnimations = function(effects, target, end) {
        if (target.length == 0 && end) {
            end();
            return null;
        }

        var animationsToPlay = effects.length;

        return function() {
            if (--animationsToPlay == 0 && end)
                end();
        };
    };

    $.extend($.telerik.fx, {
        _wrap: function(element) {
            if (!element.parent().hasClass('t-animation-container')) {
                element.wrap(
					$('<div/>')
						.addClass('t-animation-container')
						.css({
						    width: element.outerWidth(),
						    height: element.outerHeight()
						}));
            }

            return element.parent();
        },

        play: function(effects, target, options, end) {
            var afterAnimation = prepareAnimations(effects, target, end);

            if (afterAnimation === null) return;

            target.stop(false, true);

            for (var i = 0, len = effects.length; i < len; i++) {

                var effect = new $.telerik.fx[effects[i].name](target);

                if (!target.data('effect-' + i)) {
                    effect.play($.extend(effects[i], options), afterAnimation);

                    target.data('effect-' + i, effect);
                }
            }
        },

        rewind: function(effects, target, options, end) {
            var afterAnimation = prepareAnimations(effects, target, end);

            if (afterAnimation === null) return;

            for (var i = effects.length - 1; i >= 0; i--) {

                var effect = target.data('effect-' + i) || new $.telerik.fx[effects[i].name](target);

                effect.rewind($.extend(effects[i], options), afterAnimation);

                target.data('effect-' + i, null);
            }
        }
    });

    // simple show/hide toggle

    $.telerik.fx.toggle = function(element) {
        this.element = element.stop(false, true);
    };

    $.extend($.telerik.fx.toggle.prototype, {
        play: function(options, end) {
            this.element.show();
            if (end) end();
        },
        rewind: function(options, end) {
            this.element.hide();
            if (end) end();
        }
    });

    $.telerik.fx.toggle.defaults = function() {
        return { name: 'toggle' };
    };

    // slide animation

    $.telerik.fx.slide = function(element) {
        this.element = element;

        this.animationContainer = $.telerik.fx._wrap(element);
    };

    $.extend($.telerik.fx.slide.prototype, {
        play: function(options, end) {

            var animationContainer = this.animationContainer;

            this.element.css('display', 'block').stop();

            animationContainer
				.css({
				    display: 'block',
				    overflow: 'hidden'
				});

            var width = this.element.outerWidth();
            var height = this.element.outerHeight();
            var animatedProperty = options.direction == 'bottom' ? 'marginTop' : 'marginLeft';
            var animatedStartValue = options.direction == 'bottom' ? -height : -width;

            animationContainer
				.css({
				    width: width,
				    height: height
				});

            var animationEnd = {};
            animationEnd[animatedProperty] = 0;

            this.element
                .css('width', this.element.width())
                .each(function() { this.style.cssText = this.style.cssText; })
                .css(animatedProperty, animatedStartValue)
				.animate(animationEnd, {
				    queue: false,
				    duration: options.openDuration,
				    easing: 'linear',
				    complete: function() {
				        animationContainer.css('overflow', '');

				        if (end) end();
				    }
				});
        },

        rewind: function(options, end) {
            var animationContainer = this.animationContainer;

            this.element.stop();

            animationContainer.css({
                overflow: 'hidden'
            });

            var animatedProperty;

            switch (options.direction) {
                case 'bottom': animatedProperty = { marginTop: -this.element.outerHeight() }; break;
                case 'right': animatedProperty = { marginLeft: -this.element.outerWidth() }; break;
            }

            this.element
				.animate(animatedProperty, {
				    queue: false,
				    duration: options.closeDuration,
				    easing: 'linear',
				    complete: function() {
				        animationContainer
							.css({
							    display: 'none',
							    overflow: ''
							});

				        if (end) end();
				    }
				});
        }
    });

    $.telerik.fx.slide.defaults = function() {
        return { name: 'slide', openDuration: 'fast', closeDuration: 'fast' };
    };

    // property animation

    $.telerik.fx.property = function(element) {
        this.element = element;
    };

    $.extend($.telerik.fx.property.prototype, {
        _animate: function(properties, duration, reverse, end) {
            var startValues = { overflow: 'hidden' },
				endValues = {},
				$element = this.element;

            $.each(properties, function(i, prop) {
                var value;

                switch (prop) {
                    case 'height':
                    case 'width': value = $element[prop](); break;

                    case 'opacity': value = 1; break;

                    default: value = $element.css(prop); break;
                }

                startValues[prop] = reverse ? value : 0;
                endValues[prop] = reverse ? 0 : value;
            });

            $element
				.css(startValues)
				.show()
				.animate(endValues, {
				    queue: false,
				    duration: duration,
				    easing: 'linear',
				    complete: function() {
				        if (reverse)
				            $element.hide();

				        $.each(endValues, function(property) {
				            endValues[property] = '';
				        });

				        $element.css($.extend({ overflow: '' }, endValues));

				        if (end) end();
				    }
				});
        },

        play: function(options, complete) {
            this._animate(options.properties, options.openDuration, false, complete);
        },

        rewind: function(options, complete) {
            this._animate(options.properties, options.closeDuration, true, complete);
        }
    });

    $.telerik.fx.property.defaults = function() {
        return { name: 'property', properties: arguments, openDuration: 'fast', closeDuration: 'fast' };
    };
})(jQuery);