(function ($) {

    $.fn.imageGallery = function (options) {
        var defaults = {
            width: 'auto',
            height: 'auto',
            itemSelector: '.galleryItem',
            imageSelector: '.image',
            nextPrevButtons: false,
            itemButtons: false,
            transition: 'opacity',
            transspeed: '1000',
            speed: '5000',
            autoplay: true,
            bspace:0
        }
        var o = $.extend(defaults, options);
        var itemIndex = -1;
        var waitingIndex = -1;
        var waitingTimeout;
        var reverse = false;

        return this.each(function () {
            var g = $(this);
            var gi = g.find(o.itemSelector);
            if (gi.length > 1) {
                gi.find(o.imageSelector).load(function () {
                    ti = $(this);
                    ti.attr('loaded', true);
                    if (waitingIndex == ti.attr('index')) {
                        g.find('.loading').remove();
                        waitingIndex = -1;
                        transitionIn(ti.attr('index'));
                    }
                }).each(function (index) {
                    var ti = $(this);
                    ti.attr('index', index);
                    ti.parents(o.itemSelector).attr('index', index);
                    if (ti.attr('complete') || ti.height() > 30) {
                        ti.attr('loaded', true);
                    }
                });
                var playing = o.autoplay;
                var playTimer;
                g.css({
                    'position': 'relative',
                    'overflow': 'hidden'
                });

                if (o.width != 'auto') {
                    g.width(o.width);
                } else {
                    g.width(gi.outerWidth());
                }
                if (o.height != 'auto') {
                    g.height(o.height);
                } else {
                    g.height(gi.outerHeight() + o.bspace);
                }

                gi.css({
                    'position': 'absolute',
                    'top': '0px',
                    'left': '0px'
                }).hide();

                g.append('<div class="transitionLayer"></div>');
                tl = g.children('.transitionLayer').css({
                    'position': 'absolute',
                    'display': 'none',
                    'top': '0px',
                    'left': '0px',
                    'width': '100%',
                    'height': '100%',
                    'z-index': 3
                });

                if (o.nextPrevButtons) {
                    g.append('<div class="leftButton"></div><div class="rightButton"></div>');
                    g.children('.leftButton').click(function () {
                        playing = false;
                        clearTimeout(playTimer);
                        reverse = true;
                        transitionIn(itemIndex - 2);
                    });
                    g.children('.rightButton').click(function () {
                        playing = false;
                        clearTimeout(playTimer);
                        transitionIn();
                    });
                }

                if (o.itemButtons) {
                    g.append('<div class="itemButtons"></div>');
                    ib = g.children('.itemButtons');
                    gi.each(function (i) {
                        thisgi = $(this);
                        if (thisgi.find('img:first').attr('data-thumb')) {
                            ib.append('<div class="itemButton thumbnailButton" data-index="' + i + '"><img src="' + thisgi.find('img:first').attr('data-thumb') + '" alt="" /></div>');
                        } else {
                            ib.append('<div class="itemButton" data-index="' + i + '"></div>');
                        }
                        var nb = ib.children('.itemButton[data-index=' + i + ']');
                        nb.click(function (e) {
                            playing = false;
                            clearTimeout(playTimer);
                            ti = $(this);
                            if (itemIndex > ti.attr('data-index')) {
                                reverse = true;
                            }
                            ti.siblings().removeClass('activeButton').end().addClass('activeButton');
                            transitionIn(parseInt(ti.attr('data-index')));
                            e.stopPropagation();
                        });
                    });
                }

                transitionIn(0);
            }

            function transitionIn(i) {
                var lastIndex = itemIndex;
                if (!isNaN(i)) {
                    itemIndex = parseInt(i);
                } else {
                    itemIndex++;
                }

                if (waitingTimeout) {
                    clearTimeout(waitingTimeout);
                }
                if (itemIndex < 0) {
                    itemIndex += gi.length;
                } else if (itemIndex > gi.length - 1) {
                    itemIndex -= gi.length;
                }

                var ni = gi.slice(itemIndex, itemIndex + 1);
                var li = gi.slice(lastIndex, lastIndex + 1);
                if ((ni.find('img').attr('loaded') || ni.find('img').attr('readyState') == "complete") && !ni.is(':animated') && !li.is(':animated') && !tl.children().is(':animated')) {
                    if (li.html() != ni.html()) {
                        ni.addClass('activeItem');
                        li.removeClass('activeItem');
                        ni.css('z-index', 5);
                        li.css('z-index', 1);

                        var transition = ni.attr('data-transition') || o.transition;
                        var dl = ni.attr('data-display-length') || o.speed;

                        if (playing) {
                            playTimer = setTimeout(function () {
                                transitionIn();
                            }, dl)
                        }
                        if (reverse) {
                            switch (transition) {
                                case 'right':
                                    transition = "left";
                                    break;
                                case 'left':
                                    transition = "right";
                                    break;
                                case 'top':
                                    transition = "bottom";
                                    break;
                                case 'bottom':
                                    transition = "top";
                                    break;
                            }
                            reverse = false;
                        }
                        switch (transition) {
                            case 'right':
                                if (li.css('display') == 'block') {
                                    ni.css('left', "-" + ni.width() + "px").show();
                                    ni.animate({ left: "0px" }, o.transspeed);
                                    li.animate({ left: ni.width() + "px" }, o.transspeed);
                                } else {
                                    ni.show();
                                }
                                break;
                            case 'left':
                                if (li.css('display') == 'block') {
                                    ni.css('left', ni.width() + "px").show();
                                    ni.animate({ left: "0px" }, o.transspeed);
                                    li.animate({ left: "-" + ni.width() + "px" }, o.transspeed);
                                } else {
                                    ni.show();
                                }
                                break;
                            case 'top':
                                if (li.css('display') == 'block') {
                                    ni.css('top', "-" + ni.height() + "px").show();
                                    ni.animate({ top: "0px" }, o.transspeed);
                                    li.animate({ top: ni.height() + "px" }, o.transspeed);
                                } else {
                                    ni.show();
                                }
                                break;
                            case 'bottom':
                                if (li.css('display') == 'block') {
                                    ni.css('top', ni.height() + "px").show();
                                    ni.animate({ top: "0px" }, o.transspeed);
                                    li.animate({ top: "-" + ni.height() + "px" }, o.transspeed);
                                } else {
                                    ni.show();
                                }
                                break;
                            case 'checkerboard':
                                var img = ni.find('img');
                                ni.show();
                                var sizeX = Math.ceil(ni.width() / 10);
                                var sizeY = Math.ceil(ni.height() / 8);
                                img.hide();
                                tl.html('');
                                for (x = 0; x < 10; x++) {
                                    for (y = 0; y < 8; y++) {
                                        $("<div />").css({
                                            width: sizeX,
                                            height: sizeY,
                                            left: x * sizeX,
                                            top: y * sizeY,
                                            backgroundPosition: "-" + x * sizeX + "px -" + y * sizeY + "px",
                                            position: 'absolute',
                                            display: 'none',
                                            'background-image': 'url(' + img.attr('src') + ')'
                                        }).appendTo(tl);
                                    }
                                }
                                tl.show().children().each(function (a, i) {
                                    $(this).delay(Math.random() * (o.transspeed * 0.75)).fadeIn(o.transspeed / 4, function () {
                                        var tb = $(this);
                                        if (tb.siblings().length == tb.siblings(':visible:not(:animated)').length) {
                                            tb.parent().siblings('.activeItem').find('img').show();
                                            tl.hide();
                                        }
                                    });
                                });
                                break;
                            case 'joinV':
                                var img = ni.find('img');
                                ni.show();
                                var sizeX = Math.ceil(ni.width() + (ni.width() / 2));
                                var sizeY = Math.ceil(ni.height());
                                img.hide();
                                tl.html('');
                                for (x = 0; x < 2; x++) {
                                    $("<div />").css({
                                        width: (ni.width() / 2),
                                        height: sizeY,
                                        left: x * sizeX - (ni.width() / 2),
                                        top: 0,
                                        backgroundPosition: "-" + (x * sizeX) + "px 0px",
                                        position: 'absolute',
                                        'background-image': 'url(' + img.attr('src') + ')'
                                    }).appendTo(tl);
                                }
                                tl.show().children(':eq(0)').animate({ left: 0 + "px" }, o.transspeed).siblings('div').animate({ left: ni.width() / 2 + "px" }, o.transspeed, function () {
                                    var tb = $(this);
                                    tb.parent().siblings('.activeItem').find('img').show();
                                    tl.hide();
                                });
                                break;
                            case 'joinH':
                                var img = ni.find('img');
                                ni.show();
                                var sizeX = Math.ceil(ni.width());
                                var sizeY = Math.ceil(ni.height() + (ni.height() / 2));
                                img.hide();
                                tl.html('');
                                for (y = 0; y < 2; y++) {
                                    $("<div />").css({
                                        width: sizeX,
                                        height: (ni.height() / 2),
                                        left: 0,
                                        top: y * sizeY - (ni.height() / 2),
                                        backgroundPosition: "-0px " + (y * sizeY) + "px",
                                        position: 'absolute',
                                        'background-image': 'url(' + img.attr('src') + ')'
                                    }).appendTo(tl);
                                }
                                tl.show().children(':eq(0)').animate({ top: 0 + "px" }, o.transspeed).siblings('div').animate({ top: ni.height() / 2 + "px" }, o.transspeed, function () {
                                    var tb = $(this);
                                    tb.parent().siblings('.activeItem').find('img').show();
                                    tl.hide();
                                });
                                break;
                            case 'splitV':
                                li.css('z-index', 5);
                                ni.css('z-index', 1);
                                var img = li.find('img');
                                li.show();
                                ni.show();
                                var sizeX = Math.ceil(li.width() / 2);
                                var sizeY = Math.ceil(li.height());
                                img.hide();
                                tl.html('');
                                for (x = 0; x < 2; x++) {
                                    $("<div />").css({
                                        width: sizeX,
                                        height: sizeY,
                                        left: x * sizeX,
                                        top: 0,
                                        backgroundPosition: "-" + (x * sizeX) + "px 0px",
                                        position: 'absolute',
                                        'background-image': 'url(' + img.attr('src') + ')'
                                    }).appendTo(tl);
                                }
                                tl.show().children(':eq(0)').animate({ left: -sizeX + "px" }, o.transspeed).siblings('div').animate({ left: li.width() + "px" }, o.transspeed, function () {
                                    var tb = $(this);
                                    tb.parent().siblings(o.itemSelector).css('z-index', 1).hide().find('img').show();
                                    tb.parent().siblings('.activeItem').css('z-index', 5).show();
                                    tl.hide();
                                });
                                break;
                            case 'splitH':
                                li.css('z-index', 5);
                                ni.css('z-index', 1);
                                var img = li.find('img');
                                li.show();
                                ni.show();
                                var sizeX = Math.ceil(li.width());
                                var sizeY = Math.ceil(li.height() / 2);
                                img.hide();
                                tl.html('');
                                for (y = 0; y < 2; y++) {
                                    $("<div />").css({
                                        width: sizeX,
                                        height: sizeY,
                                        left: 0,
                                        top: y * sizeY,
                                        backgroundPosition: "0px -" + (y * sizeY) + "px",
                                        position: 'absolute',
                                        'background-image': 'url(' + img.attr('src') + ')'
                                    }).appendTo(tl);
                                }
                                tl.show().children(':eq(0)').animate({ top: -sizeY + "px" }, o.transspeed).siblings('div').animate({ top: li.height() + "px" }, o.transspeed, function () {
                                    var tb = $(this);
                                    tb.parent().siblings(o.itemSelector).css('z-index', 1).hide().find('img').show();
                                    tb.parent().siblings('.activeItem').css('z-index', 5).show();
                                    tl.hide();
                                });
                                break;
                            case 'opacity':
                            default:
                                ni.css('left', '0px').hide().fadeIn(o.transspeed, function () {
                                    $(this).siblings(o.itemSelector).hide();
                                });
                                break;
                        }

                        if (o.height == 'auto') {
                            g.height(gi.filter(':visible').height() + o.bspace);
                        }
                        if (o.itemButtons) {
                            g.find('.itemButton').removeClass('activeButton');
                            g.find('.itemButton[data-index="' + ni.attr('index') + '"]').addClass('activeButton');
                        }
                    }
                } else {
                    if (!ni.is(':animated') && !li.is(':animated')) {
                        waitingIndex = itemIndex;
                        if (g.children('.loading').length > 0) {
                            g.children('.loading').remove();
                        }
                        g.prepend('<div class="loading"></div>').children('.loading').width(g.width()).height(g.height());
                        waitingTimeout = setTimeout(function () {
                            transitionIn(waitingIndex);
                        }, 100);
                    }
                    if (!isNaN(i)) {
                        itemIndex = lastIndex;
                    }
                }
            }
        });
    };
})($)
