(function($) {
    var inject = '<div id="wimpy_overlay"></div><div id="wimpy_box"><div id="wimpy_stage"></div><div id="wimpy_exit">[x] schließen</div><div id="wimpy_fog"></div></div>';
    var stack = [];

    var hide = function() {
        $(this).css({display: 'none'});
    };

    var escape = function(e) {
        if (e.keyCode == 27)
            $.fn.wimpy.close();
    };

    var arrow_keys = function(e) {
        if ( e.keyCode == 38 || e.keyCode == 39 )
            $.fn.wimpy.next();
        if ( e.keyCode == 37 || e.keyCode == 40 )
            $.fn.wimpy.prev();
    };

    var outer_width = function(elem) {
        return  (parseInt(elem.css('width')) || 0) +
                (parseInt(elem.css('paddingLeft')) || 0) +
                (parseInt(elem.css('paddingRight')) || 0) +
                (parseInt(elem.css('borderLeftWidth')) || 0) +
                (parseInt(elem.css('borderRightWidth')) || 0);
    };

    var outer_height = function(elem) {
        return  (parseInt(elem.css('height')) || 0) +
                (parseInt(elem.css('paddingTop')) || 0) +
                (parseInt(elem.css('paddingBottom')) || 0) +
                (parseInt(elem.css('borderTopWidth')) || 0) +
                (parseInt(elem.css('borderBottomWidth')) || 0);
    };

    var get_dim = function(elem) {
        var dim = {
            width:  (elem.outerWidth() || outer_width(elem)) + (parseInt(elem.css('marginLeft')) || 0) + (parseInt(elem.css('marginRight')) || 0),
            height: (elem.outerHeight() || outer_height(elem)) + (parseInt(elem.css('marginTop')) || 0) + (parseInt(elem.css('marginBottom')) || 0)
        };
        return $.extend(dim, {
            top: $.fn.wimpy.opts.box_top(dim),
            left: $.fn.wimpy.opts.box_left(dim)
        });
    };

    var clear_stage = function() {
        if ( $.fn.wimpy.opts.clone || !$.fn.wimpy.opts.dump )
            $.fn.wimpy.stage.empty();
        else
            $('.wimpy_placeholder', $.fn.wimpy.opts.dump).replaceWith($.fn.wimpy.stage.children())
            .insertBefore($.fn.wimpy.elements[$.fn.wimpy.index]);
    };

    $.fn.wimpy = function(options) {
        var opts = $.extend({}, $.fn.wimpy.defaults, options);
        var overlay_css = {
            opacity: opts.overlay_opacity,
            backgroundColor: opts.overlay_bg_color,
            width: $(document).width(),
            height: $(document).height()
        };
        var box_css = {
            opacity: 1,
            width: opts.box_width,
            height: opts.box_height,
            cursor: opts.box_cursor,
            top: opts.box_top({width: opts.box_width, height: opts.box_height}),
            left: opts.box_left({width: opts.box_width, height: opts.box_height})
        };
        var fog_css = {
            width: '100%',
            height: '100%',
            backgroundColor: opts.box_bg_color
        }

        $.fn.wimpy.index = Math.max(Math.min(this.length, opts.index || 0), 0);
        this.each(function() {
            $.fn.wimpy.elements.push($(this));
        });

        if ( !opts.clone && opts.dump )
            $('<span class="wimpy_placeholder"></span>').insertBefore($.fn.wimpy.elements[$.fn.wimpy.index]);

        if ( opts.overlay_css != undefined )
            $.extend(overlay_css, opts.overlay_css);

        if ( opts.box_css != undefined )
            $.extend(box_css, opts.box_css);

        // IE 6 selection shine-thru fix
        $.fn.wimpy.iefix = $.browser.msie && parseInt($.browser.version) == 6 ?
            $('select:visible').css({visibility: 'hidden'}) : false;

        $.fn.wimpy.overlay.css(overlay_css);
        $.fn.wimpy.fog.css(fog_css);
        $.fn.wimpy.box.css(box_css)
        .mouseenter(function() {
            if ( opts.close_button )
                $.fn.wimpy.exit.animate({opacity: 'show'}, {duration: 150});
        }).mouseleave(function() {
            if ( opts.close_button )
                $.fn.wimpy.exit.animate({opacity: 'hide'}, {duration: 150});
        });;

        opts.overlay_anim.call($.fn.wimpy.overlay, opts);
        opts.box_anim.call($.fn.wimpy.box, opts);

        if ( opts.escape )
            $(document).bind('keydown.escape', escape);
        if ( opts.arrow_keys )
            $(document).bind('keydown.arrow_keys', arrow_keys);
        if ( opts.clickquit )
            $.fn.wimpy.overlay.css({cursor: 'pointer'})
            .bind('click', $.fn.wimpy.close);
        if ( opts.clicknext )
            $.fn.wimpy.box.bind('click.wimpy', function() {
                $.fn.wimpy.next();
            });

        $.fn.wimpy.opts = opts;
        $.fn.wimpy.show();

        return this;
    };

    $.fn.wimpy.next = function() {
        if ( $.fn.wimpy.elements.length < 2 ) return;

        if ( $.fn.wimpy.busy ) {
            stack.push($.fn.wimpy.next);
            return;
        }

        if ( ++$.fn.wimpy.index == $.fn.wimpy.elements.length )
            $.fn.wimpy.index = 0;

        $.fn.wimpy.show();
    };

    $.fn.wimpy.prev = function() {
        if ( $.fn.wimpy.elements.length < 2 ) return;

        if ( $.fn.wimpy.busy ) {
            stack.push($.fn.wimpy.prev);
            return;
        }

        if ( --$.fn.wimpy.index < 0 )
            $.fn.wimpy.index = $.fn.wimpy.elements.length - 1;

        $.fn.wimpy.show();
    };

    $.fn.wimpy.show = function() {
        if ( !$.fn.wimpy.elements.length ) return;

        $.fn.wimpy.busy = true;

        var elem = $.fn.wimpy.elements[$.fn.wimpy.index];
        var clone = ($.fn.wimpy.opts.clone ? elem.clone(true) : elem).css({display: 'block'});

        $.fn.wimpy.current = clone;

        if ( clone.bound('wimpy', 'pre') )
            clone.trigger('wimpy.pre');

        var dim = get_dim(elem);

        var delta_y = Math.min(1, Math.abs(dim.height - $.fn.wimpy.box.height()));
        var delta_x = Math.min(1, Math.abs(dim.width - $.fn.wimpy.box.width()));

        if ( delta_y || delta_x )
            $.fn.wimpy.fog.css({display: 'block', opacity: 1});

        clear_stage();
        $.fn.wimpy.box.animate({
            height: dim.height,
            top: dim.top
        }, {
            duration: 500 * delta_y,
            queue: $.fn.wimpy.opts.queue
        }).animate({
            width: dim.width,
            left: dim.left
        }, {
            duration: 500 * delta_x,
            queue: $.fn.wimpy.opts.queue,
            complete: function() {
                $.fn.wimpy.overlay.css({
                    width: $(document).width(),
                    height: $(document).height()
                });

                if ( stack.length ) {
                    $.fn.wimpy.busy = false;
                    return stack.shift()();
                }

                $.fn.wimpy.stage.append(clone);
                $.fn.wimpy.fog.animate({opacity: 'hide'}, {
                    duration: 500 * delta_y * delta_x,
                    queue: $.fn.wimpy.opts.queue,
                    complete: function() {
                        $.fn.wimpy.busy = false;
                        if ( stack.length ) stack.shift()();
                    }
                });

                if ( clone.bound('wimpy', 'post') )
                    clone.trigger('wimpy.post');
            }
        });
    };

    $.fn.wimpy.reposition = function() {
        if ( !$.fn.wimpy.elements.length ) return;

        var elem = $.fn.wimpy.elements[$.fn.wimpy.index];
        var dim = get_dim(elem);

        $.fn.wimpy.box.animate({
            top: dim.top
        }, {
            duration: 250,
            ease: 'easeInCubic',
            queue: $.fn.wimpy.opts.queue
        }).animate({
            left: dim.left
        }, {
            duration: 250,
            ease: 'easeInCubic',
            queue: $.fn.wimpy.opts.queue
        });
    };

    $.fn.wimpy.close = function() {
        if ( !$.fn.wimpy.elements.length ) return;

        if ( $.fxq($.fn.wimpy.opts.queue) != undefined )
            $.fxq($.fn.wimpy.opts.queue).clear();

        clear_stage();
        $('.wimpy_placeholder').remove();
        $.fn.wimpy.box.unbind('click.wimpy');
        $.fn.wimpy.box.animate({opacity: 'hide'}, {
            duration: 250,
            scope: $.fn.wimpy.defaults.scope
        });        
        $.fn.wimpy.overlay.animate({opacity: 'hide'}, {
            duration: 250,
            scope: $.fn.wimpy.defaults.scope
        });

        if ( $.fn.wimpy.iefix !== false )
            setTimeout(function() {
                $.fn.wimpy.iefix.css({visibility: 'visible'});
            }, 200);

        $(document).unbind('keydown', escape);
        $.fn.wimpy.overlay.unbind('click', $.fn.wimpy.close);

        $.fn.wimpy.exit.css({display: 'none'});

        $.fn.wimpy.elements = new Array();
        $.fn.wimpy.index = 0;
        $.fn.wimpy.opts = null;
    };

    $.fn.wimpy.elements = new Array();
    $.fn.wimpy.current = null;
    $.fn.wimpy.busy = false;
    $.fn.wimpy.index = 0;

    $.fn.wimpy.defaults = {
        overlay_opacity: .9,
        overlay_bg_color: '#000',
        overlay_duration: 500,
        overlay_anim: function(_opts) {
            return this.animate({opacity: 'show'}, {
                duration: _opts.overlay_duration,
                queue: _opts.queue
            });
        },

        box_width: 480,
        box_height: 300,
        box_bg_color: '#fff',
        box_duration: 500,
        box_cursor: 'pointer',
        box_anim: function(_opts) {
            return this.animate({opacity: 'show'}, {
                duration: _opts.box_duration,
                queue: _opts.queue
            });
        },
        box_top: function(dim) {
            return $(window).scrollTop() + parseInt($(window).height() / 15);
        },
        box_left: function(dim) {
            return $(window).scrollLeft() + parseInt(($(window).width() - dim.width) / 2);
        },

        queue: 'wimpy',
        scope: 'wimpy',
        dump: false,
        index: 0,
        clone: true,
        escape: true,
        arrow_keys: true,
        clickquit: true,
        clicknext: false,
        close_button: true
    };

    $.fn.bound = function(type, namespace) {
        var events = this.data('events') || false, n = 0;

        if ( typeof type != 'string' || !events || !events[type.replace(/^on/i, '')] ) return 0;

        if ( namespace == null )
            for ( x in events[type.replace(/^on/i, '')] ) ++n;
        else {
            if ( !$.isArray(namespace) )
                namespace = [namespace.toString()];

            $.each(events[type.replace(/^on/i, '')], function(i, elem) {
                if ( $.inArray(elem.type, namespace) != -1 ) ++n; 
            });
        }

        return n;
    };

    $(function() {
        $('body').append(inject);

        $.fn.wimpy.exit = $('#wimpy_exit').css({
            position: 'absolute',
            top: 4, right: 4,
            padding: 4,
            background: '#fff',
            display: 'none',
            'font-size': '.6875em',
            'z-index': 1003
        }).click(function() {
            $.fn.wimpy.close();
            return false;
        });
        $.fn.wimpy.box = $('#wimpy_box').css({
            position: 'absolute',
            top: 0, left: 0,
            display: 'none',
            opacity: 0,
            'z-index': 1000
        });
        $.fn.wimpy.stage = $('#wimpy_stage').css({
            position: 'absolute',
            top: 0, left: 0,
            'z-index': 1001            
        });
        $.fn.wimpy.fog = $('#wimpy_fog').css({
            position: 'absolute',
            top: 0, left: 0,
            'z-index': 1002
        });
        $.fn.wimpy.overlay = $('#wimpy_overlay').css({
            position: 'absolute',
            top: 0, left: 0,
            display: 'none',
            'z-index': 999
        });

        $(window).resize(function() {
            $.fn.wimpy.overlay.css({
                height: $(document).height(),
                width: $(document).width()
            });
            $.fn.wimpy.reposition();
        });        
    });
})(jQuery);
