/**
 * @preserve Flux Slider v1.4.1
 * http://www.joelambert.co.uk/flux
 *
 * Copyright 2011, Joe Lambert.
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */

// Flux namespace
window.flux = {
    version: '1.4.1'
};

(function($){
    flux.slider = function(elem, opts) {
        // Setup the flux.browser singleton to perform feature detection
        flux.browser.init();

        if(!flux.browser.supportsTransitions)
        {
            if(window.console && window.console.error)
                console.error("Flux Slider requires a browser that supports CSS3 transitions");
        }

        var _this = this;

        this.element = $(elem);

        // Make a list of all available transitions
        this.transitions = [];
        for(var fx in flux.transitions)
            this.transitions.push(fx);

        this.options = $.extend({
            autoplay: true,
            transitions: this.transitions,
            delay: 4000,
            pagination: true,
            controls: false,
            captions: false,
            width: null,
            height: null,
            onTransitionEnd: null
        }, opts);

        // Set the height/width if given [EXPERIMENTAL!]
        this.height = this.options.height ? this.options.height    : null;
        this.width     = this.options.width  ? this.options.width     : null;

        // Filter out non compatible transitions
        var newTrans = [];
        $(this.options.transitions).each(function(index, tran){
            var t = new flux.transitions[tran](this),
                compatible = true;
            
            if(t.options.requires3d && !flux.browser.supports3d)
                compatible = false;
                
            if(t.options.compatibilityCheck)
                compatible = t.options.compatibilityCheck();

            if(compatible)
                newTrans.push(tran);
        });        

        this.options.transitions = newTrans;

        this.images = new Array();
        this.imageLoadedCount = 0;
        this.currentImageIndex = 0;
        this.nextImageIndex = 1;
        this.playing = false;


        this.container = $('<div class="fluxslider"></div>').appendTo(this.element);
        
        this.surface = $('<div class="surface" style="position: relative"></div>').appendTo(this.container);
        
        // Listen for click events as we may want to follow a link
        this.container.bind('click', function(event) {
            if($(event.target).hasClass('hasLink'))
                window.location = $(event.target).data('href');
        });

        this.imageContainer = $('<div class="images loading"></div>').css({
            'position': 'relative',
            'overflow': 'hidden',
            'min-height': '398px'
        }).appendTo(this.surface);
        
        // If the height/width is already set then resize the container
        if(this.width && this.height)
        {
            this.imageContainer.css({
                width: this.width+'px',
                height: this.height+'px'
            })
        }

        // Create the placeholders for the current and next image
        this.image1 = $('<div class="image1" style="height: 100%; width: 100%"></div>').appendTo(this.imageContainer);
        this.image2 = $('<div class="image2" style="height: 100%; width: 100%"></div>').appendTo(this.imageContainer);

        $(this.image1).add(this.image2).css({
            'position': 'absolute',
            'top': '0px',
            'left': '0px'
        });
        
        // Get a list of the images to use
        this.element.find('img, a img').each(function(index, found_img){
            var imgClone = found_img.cloneNode(false),
                link = $(found_img).parent();

            // If this img is directly inside a link then save the link for later use
            if(link.is('a'))
                $(imgClone).data('href', link.attr('href'));

            _this.images.push(imgClone);

            // Remove the images from the DOM
            $(found_img).remove();
        });
        
        // Load the images afterwards as IE seems to load images synchronously
        for(var i=0; i<this.images.length; i++) {
            var image = new Image();
            image.onload = function() {
                _this.imageLoadedCount++;

                _this.width  = _this.width     ? _this.width  : this.width;
                _this.height = _this.height ? _this.height : this.height;

                if(_this.imageLoadedCount >= _this.images.length)
                {
                    _this.finishedLoading();
                    _this.setupImages();
                }
            };

            // Load the image to ensure its cached by the browser
            image.src = this.images[i].src;
        }
        
        // Catch when a transition has finished
        this.element.bind('fluxTransitionEnd', function(event, data) {
            // If the slider is currently playing then set the timeout for the next transition
            if(_this.isPlaying())
                _this.start();
            
            // Are we using a callback instead of events for notifying about transition ends?
            if(_this.options.onTransitionEnd) {                    
                event.preventDefault();
                _this.options.onTransitionEnd(data);
            }
        });

        // Should we auto start the slider?
        if(this.options.autoplay)
            this.start();
            
        // Handle swipes
        this.element.bind('swipeLeft', function(event){
            _this.next(null, {direction: 'left'});
        }).bind('swipeRight', function(event){
            _this.prev(null, {direction: 'right'});
        });
        
        // Under FF7 autoplay breaks when the current tab loses focus
        setTimeout(function(){
            $(window).focus(function(){
                if(_this.isPlaying())
                    _this.next();
            });
        }, 100);
    };

    flux.slider.prototype = {
        constructor: flux.slider,
        playing: false,
        start: function() {
            var _this = this;
            this.playing = true;
            this.interval = setTimeout(function() {
                _this.transition();
            }, this.options.delay);
        },
        stop: function() {
            this.playing = false;
            clearTimeout(this.interval);
            this.interval = null;
        },
        isPlaying: function() {
            return this.playing;
            //return this.interval != null;
        },
        next: function(trans, opts) {
            opts = opts || {};
            opts.direction = 'left';
            this.showImage(this.currentImageIndex+1, trans, opts);
        },
        prev: function(trans, opts) {
            opts = opts || {};
            opts.direction = 'right';
            this.showImage(this.currentImageIndex-1, trans, opts);
        },
        showImage: function(index, trans, opts) {
            this.setNextIndex(index);
            
            // Temporarily stop the transition interval
            clearTimeout(this.interval);
            this.interval = null;
            
            this.setupImages();
            this.transition(trans, opts);
        },  
        finishedLoading: function() {
            var _this = this;

            this.container.css({
                width: this.width+'px',
                height: this.height+'px'
            });

            this.imageContainer.removeClass('loading');

            // Should we setup a pagination view?
            if(this.options.pagination)
            {
                // TODO: Attach to touch events if appropriate
                this.pagination = $('<ul class="pagination"></ul>').css({
                    margin: '0px',
                    padding: '0px',
                    'text-align': 'center'
                });

                this.pagination.bind('click', function(event){
                    event.preventDefault();
                    _this.showImage($(event.target).data('index'));
                });

                $(this.images).each(function(index, image){
                    var li = $('<li data-index="'+index+'">'+(index+1)+'</li>').css({
                        display: 'inline-block',
                        'margin-left': '0.5em',
                        'cursor': 'pointer'
                    }).appendTo(_this.pagination);

                    if(index == 0)
                        li.css('margin-left', 0).addClass('current');
                });

                this.container.append(this.pagination);
            }

            // Resize
            $(this.imageContainer).css({
                width: this.width+'px',
                height: this.height+'px'
            });

            $(this.image1).css({
                width: this.width+'px',
                height: this.height+'px'
            });

            $(this.image2).css({
                width: this.width+'px',
                height: this.height+'px'
            });

            this.container.css({
                width: this.width+'px',
                height: this.height+(this.options.pagination?this.pagination.height():0)+'px'
            });
            
            // Should we add prev/next controls?
            if(this.options.controls)
            {
                var css = {
                    padding: '4px 10px 10px',
                    'font-size': '60px',
                    'font-family': 'arial, sans-serif',
                    'line-height': '1em',
                    'font-weight': 'bold',
                    color: '#FFF',
                    'text-decoration': 'none',
                    background: 'rgba(0,0,0,0.5)',
                    position: 'absolute',
                    'z-index': 2
                };
                
                this.nextButton = $('<a href="#">»</a>').css(css).css3({
                    'border-radius': '4px'
                }).appendTo(this.surface).bind('click', function(event){
                    event.preventDefault();
                    _this.next();
                });
                
                this.prevButton = $('<a href="#">«</a>').css(css).css3({
                    'border-radius': '4px'
                }).appendTo(this.surface).bind('click', function(event){
                    event.preventDefault();
                    _this.prev();
                });
                
                var top = (this.height - this.nextButton.height())/2;
                this.nextButton.css({
                    top: top+'px',
                    right: '10px'
                });
                
                this.prevButton.css({
                    top: top+'px',
                    left: '10px'
                });
            }
            
            // Should we use captions?
            if(this.options.captions)
            {
                this.captionBar = $('<div class="caption"></div>').css({
                    background: 'rgba(0,0,0,0.6)',
                    color: '#FFF',
                    'font-size': '16px',
                    'font-family': 'helvetica, arial, sans-serif',
                    'text-decoration': 'none',
                    'font-weight': 'bold',
                    padding: '1.5em 1em',
                    opacity: 0,
                    position: 'absolute',
                    'z-index': 110,
                    width: '100%',
                    bottom: 0
                }).css3({
                    'transition-property': 'opacity',
                    'transition-duration': '800ms',
                    'box-sizing': 'border-box'
                }).prependTo(this.surface);
            }
            
            this.updateCaption();
        },
        setupImages: function() {
            var img1 = this.getImage(this.currentImageIndex),
                css1 = {
                    'background-image': 'url("'+img1.src+'")',
                    'z-index': 101,
                    'cursor': 'auto'
                };

            // Does this image have an associated link?
            if($(img1).data('href'))
            {
                css1.cursor = 'pointer'
                this.image1.addClass('hasLink');
                this.image1.data('href', $(img1).data('href'));
            }
            else
            {
                this.image1.removeClass('hasLink');
                this.image1.data('href', null);
            }

            this.image1.css(css1).children().remove();

            this.image2.css({
                'background-image': 'url("'+this.getImage(this.nextImageIndex).src+'")',
                'z-index': 100
            }).show();

            if(this.options.pagination && this.pagination)
            {
                this.pagination.find('li.current').removeClass('current');
                $(this.pagination.find('li')[this.currentImageIndex]).addClass('current');
            }
        },
        transition: function(transition, opts) {
            // Allow a transition to be picked from ALL available transitions (not just the reduced set)
            if(transition == undefined || !flux.transitions[transition])
            {
                // Pick a transition at random from the (possibly reduced set of) transitions
                var index = Math.floor(Math.random()*(this.options.transitions.length));
                transition = this.options.transitions[index];
            }
            
            var tran = null;

            try {
                tran = new flux.transitions[transition](this, $.extend(this.options[transition] ? this.options[transition] : {}, opts));
            }
            catch(e) {
                // If an invalid transition has been provided then use the fallback (default is to just switch the image)
                tran = new flux.transition(this, {fallback: true});
            }

            tran.run();
            
            this.currentImageIndex = this.nextImageIndex;
            this.setNextIndex(this.currentImageIndex+1);
            this.updateCaption();
        },
        updateCaption: function() {
            var str = $(this.getImage(this.currentImageIndex)).attr('title');
            if(this.options.captions && this.captionBar)
            {
                if(str !== "")
                    this.captionBar.html(str);
                    
                this.captionBar.css('opacity', str === "" ? 0 : 1);
            }
        },
        getImage: function(index) {
            index = index % this.images.length;

            return this.images[index];
        },
        setNextIndex: function(nextIndex)
        {
            if(nextIndex == undefined)
                nextIndex = this.currentImageIndex+1;

            this.nextImageIndex = nextIndex;

            if(this.nextImageIndex > this.images.length-1)
                this.nextImageIndex = 0;

            if(this.nextImageIndex < 0)
                this.nextImageIndex = this.images.length-1;
        },
        increment: function() {
            this.currentImageIndex++;
            if(this.currentImageIndex > this.images.length-1)
                this.currentImageIndex = 0;
        }
    }
})(window.jQuery || window.Zepto);

/**
 * Helper object to determine support for various CSS3 functions
 * @author Joe Lambert
 */

(function($) {
    flux.browser = {
        init: function() {
            // Have we already been initialised?
            if(flux.browser.supportsTransitions !== undefined)
                return;

            var div = document.createElement('div'),
                prefixes = ['-webkit', '-moz', '-o', '-ms'],
                domPrefixes = ['Webkit', 'Moz', 'O', 'Ms'];

            // Does the current browser support CSS Transitions?
            if(window.Modernizr && Modernizr.csstransitions !== undefined)
                flux.browser.supportsTransitions = Modernizr.csstransitions;
            else
            {
                flux.browser.supportsTransitions = this.supportsCSSProperty('Transition');
            }

            // Does the current browser support 3D CSS Transforms?
            if(window.Modernizr && Modernizr.csstransforms3d !== undefined)
                flux.browser.supports3d = Modernizr.csstransforms3d;
            else
            {
                // Custom detection when Modernizr isn't available
                // flux.browser.supports3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix();
                // 
                // // Chrome has a 3D matrix but doesn't support 3d transforms
                // if(flux.browser.supports3d && 'webkitPerspective' in div.style)
                // {
                    // Double check with a media query (similar to how Modernizr does this)
                    var div3D = $('<div id="csstransform3d"></div>');
                    var mq = $('<style media="(transform-3d), ('+prefixes.join('-transform-3d),(')+'-transform-3d)">div#csstransform3d { position: absolute; left: 9px }</style>');

                    $('body').append(div3D);
                    $('head').append(mq);

                    flux.browser.supports3d = div3D.get(0).offsetLeft == 9;

                    div3D.remove();
                    mq.remove();
                // }    
            }

        },
        supportsCSSProperty: function(prop) {
            var div = document.createElement('div'),
                prefixes = ['-webkit', '-moz', '-o', '-ms'],
                domPrefixes = ['Webkit', 'Moz', 'O', 'Ms'];
                
            var support = false;
            for(var i=0; i<domPrefixes.length; i++)
            {
                if(domPrefixes[i]+prop in div.style)
                    support = support || true;
            }
            
            return support;
        },
        translate: function(x, y, z) {
            x = (x != undefined) ? x : 0;
            y = (y != undefined) ? y : 0;
            z = (z != undefined) ? z : 0;

            return 'translate' + (flux.browser.supports3d ? '3d(' : '(') + x + 'px,' + y + (flux.browser.supports3d ? 'px,' + z + 'px)' : 'px)');
        },

        rotateX: function(deg) {
            return flux.browser.rotate('x', deg);
        },

        rotateY: function(deg) {
            return flux.browser.rotate('y', deg);
        },

        rotateZ: function(deg) {
            return flux.browser.rotate('z', deg);
        },

        rotate: function(axis, deg) {
            if(!axis in {'x':'', 'y':'', 'z':''})
                axis = 'z';

            deg = (deg != undefined) ? deg : 0;

            if(flux.browser.supports3d)
                return 'rotate3d('+(axis == 'x' ? '1' : '0')+', '+(axis == 'y' ? '1' : '0')+', '+(axis == 'z' ? '1' : '0')+', '+deg+'deg)';
            else
            {
                if(axis == 'z')
                    return 'rotate('+deg+'deg)';
                else
                    return '';
            }
        }
    };

    $(function(){
        // To continue to work with legacy code, ensure that flux.browser is initialised on document ready at the latest
        flux.browser.init();
    });
})(window.jQuery || window.Zepto);

(function($){
    /**
     * Helper function for cross-browser CSS3 support, prepends all possible prefixes to all properties passed in
     * @param {Object} props Ker/value pairs of CSS3 properties
     */
    $.fn.css3 = function(props) {
        var css = {};
        var prefixes = ['webkit', 'moz', 'ms', 'o'];

        for(var prop in props)
        {
            // Add the vendor specific versions
            for(var i=0; i<prefixes.length; i++)
                css['-'+prefixes[i]+'-'+prop] = props[prop];
            
            // Add the actual version    
            css[prop] = props[prop];
        }
        
        this.css(css);
        return this;
    };
    
    /**
     * Helper function to bind to the correct transition end event
     * @param {function} callback The function to call when the event fires
     */
    $.fn.transitionEnd = function(callback) {
        var _this = this;
        
        var events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd'];
        
        for(var i=0; i < events.length; i++)
        {
            this.bind(events[i], function(event){
                // Automatically stop listening for the event
                for(var j=0; j<events.length;j++)
                    $(this).unbind(events[j]);

                // Perform the callback function
                if(callback)
                    callback.call(this, event);
            });
        }
        
        return this;
    };

    flux.transition = function(fluxslider, opts) {
        this.options = $.extend({
            requires3d: false,
            after: function() {
                // Default callback for after the transition has completed
            }
        }, opts);

        this.slider = fluxslider;

        // We need to ensure transitions degrade gracefully if the transition is unsupported or not loaded
        if((this.options.requires3d && !flux.browser.supports3d) || !flux.browser.supportsTransitions || this.options.fallback === true)
        {
            var _this = this;
            
            this.options.after = undefined;

            this.options.setup = function() {
                //console.error("Fallback setup()");
                _this.fallbackSetup();
            };
            
            this.options.execute = function() {
                //console.error("Fallback execute()");
                _this.fallbackExecute();
            }
        }
    };

    flux.transition.prototype = {
        constructor: flux.transition,
        hasFinished: false, // This is a lock to ensure that the fluxTransitionEnd event is only fired once per tansition
        run: function() {
            var _this = this;

            // do something
            if(this.options.setup !== undefined)
                this.options.setup.call(this);
            
            // Remove the background image from the top image
            this.slider.image1.css({
                'background-image': 'none'
            });

            this.slider.imageContainer.css('overflow', this.options.requires3d ? 'visible' : 'hidden');

            // For some of the 3D effects using Zepto we need to delay the transitions for some reason
            setTimeout(function(){
                if(_this.options.execute !== undefined)
                    _this.options.execute.call(_this);
            }, 5);
        },
        finished: function() {
            if(this.hasFinished)
                return;
                
            this.hasFinished = true;
            
            if(this.options.after)
                this.options.after.call(this);

            this.slider.imageContainer.css('overflow', 'hidden');    

            this.slider.setupImages();

            // Trigger an event to signal the end of a transition
            this.slider.element.trigger('fluxTransitionEnd', {
                currentImage: this.slider.getImage(this.slider.currentImageIndex)
            });
        },
        fallbackSetup: function() {
            
        },
        fallbackExecute: function() {
            this.finished();
        }
    };

    flux.transitions = {};
    
    // Flux grid transition
    
    flux.transition_grid = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            columns: 6,
            rows: 6,
            forceSquare: false,
            setup: function() {
                var imgWidth = this.slider.image1.width(),
                    imgHeight = this.slider.image1.height();
                    
                var colWidth = Math.floor(imgWidth / this.options.columns),
                    rowHeight = Math.floor(imgHeight / this.options.rows);
                    
                if(this.options.forceSquare)
                {
                    rowHeight = colWidth;
                    this.options.rows = Math.floor(imgHeight / rowHeight);
                }

                // Work out how much space remains with the adjusted barWidth
                var colRemainder = imgWidth - (this.options.columns * colWidth),
                    colAddPerLoop = Math.ceil(colRemainder / this.options.columns),
                    
                    rowRemainder = imgHeight - (this.options.rows * rowHeight),
                    rowAddPerLoop = Math.ceil(rowRemainder / this.options.rows),
                    
                    delayBetweenBars = 150,
                    height = this.slider.image1.height(),
                    totalLeft = 0,
                    totalTop = 0,
                    fragment = document.createDocumentFragment();
                
                for(var i=0; i<this.options.columns; i++) {
                    var thisColWidth = colWidth,
                        totalTop = 0;

                    if(colRemainder > 0)
                    {
                        var add = colRemainder >= colAddPerLoop ? colAddPerLoop : colRemainder;
                        thisColWidth += add;
                        colRemainder -= add;
                    }
                    
                    for(var j=0; j<this.options.rows; j++)
                    {
                        var thisRowHeight = rowHeight,
                            thisRowRemainder = rowRemainder;

                        if(thisRowRemainder > 0)
                        {
                            var add = thisRowRemainder >= rowAddPerLoop ? rowAddPerLoop : thisRowRemainder;
                            thisRowHeight += add;
                            thisRowRemainder -= add;
                        }
                        
                        var tile = $('<div class="tile tile-'+i+'-'+j+'"></div>').css({
                            width: thisColWidth+'px',
                            height: thisRowHeight+'px',
                            position: 'absolute',
                            top: totalTop+'px',
                            left: totalLeft+'px'
                        });
                        
                        this.options.renderTile.call(this, tile, i, j, thisColWidth, thisRowHeight, totalLeft, totalTop);
                        
                        fragment.appendChild(tile.get(0));
                        
                        totalTop += thisRowHeight;
                    }
                    
                    totalLeft += thisColWidth;
                }

                // Append the fragement to the surface
                this.slider.image1.get(0).appendChild(fragment);
            },
            execute: function() {
                var _this = this,
                    height = this.slider.image1.height(),
                    bars = this.slider.image1.find('div.barcontainer');

                this.slider.image2.hide();

                // Get notified when the last transition has completed
                bars.last().transitionEnd(function(event){
                    _this.slider.image2.show();

                    _this.finished();
                });

                bars.css3({
                    'transform': flux.browser.rotateX(-90) + ' ' + flux.browser.translate(0, height/2, height/2)
                });
            },
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                
            }
        }, opts));    
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.bars = function(fluxslider, opts) {
        return new flux.transition_grid(fluxslider, $.extend({
            columns: 10,
            rows: 1,
            delayBetweenBars: 40,
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                $(elem).css({
                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': '-'+leftOffset+'px 0px'
                }).css3({
                    'transition-duration': '400ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'all',
                    'transition-delay': (colIndex*this.options.delayBetweenBars)+'ms'
                });
            },
            execute: function() {
                var _this = this;
    
                var height = this.slider.image1.height();
    
                var bars = this.slider.image1.find('div.tile');
    
                // Get notified when the last transition has completed
                $(bars[bars.length-1]).transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    bars.css({
                        'opacity': '0.5'
                    }).css3({
                        'transform': flux.browser.translate(0, height)
                    });
                }, 50);
                
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.bars3d = function(fluxslider, opts) {
        return new flux.transition_grid(fluxslider, $.extend({
            requires3d: true,
            columns: 7,
            rows: 1,
            delayBetweenBars: 150,
            perspective: 1000,
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                var bar = $('<div class="bar-'+colIndex+'"></div>').css({
                    width: colWidth+'px',
                    height: '100%',
                    position: 'absolute',
                    top: '0px',
                    left: '0px',
                    'z-index': 200,

                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': '-'+leftOffset+'px 0px',
                    'background-repeat': 'no-repeat'
                }).css3({
                    'backface-visibility': 'hidden'
                }),

                bar2 = $(bar.get(0).cloneNode(false)).css({
                    'background-image': this.slider.image2.css('background-image')
                }).css3({
                    'transform': flux.browser.rotateX(90) + ' ' + flux.browser.translate(0, -rowHeight/2, rowHeight/2)
                }),

                left = $('<div class="side bar-'+colIndex+'"></div>').css({
                    width: rowHeight+'px',
                    height: rowHeight+'px',
                    position: 'absolute',
                    top: '0px',
                    left: '0px',
                    background: '#222',
                    'z-index': 190
                }).css3({
                    'transform': flux.browser.rotateY(90) + ' ' + flux.browser.translate(rowHeight/2, 0, -rowHeight/2) + ' ' + flux.browser.rotateY(180),
                    'backface-visibility': 'hidden'
                }),

                right = $(left.get(0).cloneNode(false)).css3({
                    'transform': flux.browser.rotateY(90) + ' ' + flux.browser.translate(rowHeight/2, 0, colWidth-rowHeight/2)
                });

                $(elem).css({
                    width: colWidth+'px',
                    height: '100%',
                    position: 'absolute',
                    top: '0px',
                    left: leftOffset+'px',
                    'z-index': colIndex > this.options.columns/2 ? 1000-colIndex : 1000 // Fix for Chrome to ensure that the z-index layering is correct!
                }).css3({
                    'transition-duration': '800ms',
                    'transition-timing-function': 'linear',
                    'transition-property': 'all',
                    'transition-delay': (colIndex*this.options.delayBetweenBars)+'ms',
                    'transform-style': 'preserve-3d'
                }).append(bar).append(bar2).append(left).append(right);
            },
            execute: function() {
                this.slider.imageContainer.css3({
                    'perspective': this.options.perspective,
                    'perspective-origin': '50% 50%'
                });
                
                var _this = this,
                    height = this.slider.image1.height(),
                    bars = this.slider.image1.find('div.tile');

                this.slider.image2.hide();

                // Get notified when the last transition has completed
                bars.last().transitionEnd(function(event){
                    _this.slider.image2.show();

                    _this.finished();
                });
                
                setTimeout(function(){
                    bars.css3({
                        'transform': flux.browser.rotateX(-90) + ' ' + flux.browser.translate(0, height/2, height/2)
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {    
    flux.transitions.blinds = function(fluxslider, opts) {
        return new flux.transitions.bars(fluxslider, $.extend({
            execute: function() {
                var _this = this;

                var height = this.slider.image1.height();

                var bars = this.slider.image1.find('div.tile');

                // Get notified when the last transition has completed
                $(bars[bars.length-1]).transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    bars.css({
                        'opacity': '0.5'
                    }).css3({
                        'transform': 'scalex(0.0001)'
                    });
                }, 50);
            }
        }, opts));
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.blinds3d = function(fluxslider, opts) {
        return new flux.transitions.tiles3d(fluxslider, $.extend({
            forceSquare: false,
            rows: 1,
            columns: 6
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.zip = function(fluxslider, opts) {
        return new flux.transitions.bars(fluxslider, $.extend({
            execute: function() {
                var _this = this;

                var height = this.slider.image1.height();

                var bars = this.slider.image1.find('div.tile');

                // Get notified when the last transition has completed
                $(bars[bars.length-1]).transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    bars.each(function(index, bar){                        
                        $(bar).css({
                            'opacity': '0.3'
                        }).css3({
                            'transform': flux.browser.translate(0, (index%2 ? '-'+(2*height) : height))
                        });        
                    });
                }, 20);
            }
        }, opts));
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.blocks = function(fluxslider, opts) {
        return new flux.transition_grid(fluxslider, $.extend({
            cols: 12,
            forceSquare: true,
            delayBetweenBars: 100,
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                var delay = Math.floor(Math.random()*10*this.options.delayBetweenBars);
                
                $(elem).css({
                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': '-'+leftOffset+'px -'+topOffset+'px'
                }).css3({
                    'transition-duration': '350ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'all',
                    'transition-delay': delay+'ms'
                });
                
                // Keep track of the last elem to fire
                if(this.maxDelay === undefined)
                    this.maxDelay = 0;
                    
                if(delay > this.maxDelay)
                {
                    this.maxDelay = delay;
                    this.maxDelayTile = elem;
                }
            },
            execute: function() {
                var _this = this;
    
                var blocks = this.slider.image1.find('div.tile');
    
                // Get notified when the last transition has completed
                this.maxDelayTile.transitionEnd(function(){
                    _this.finished();
                });
    
                setTimeout(function(){
                    blocks.each(function(index, block){                
                        $(block).css({
                            'opacity': '0'
                        }).css3({
                            'transform': 'scale(0.8)'
                        });
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.blocks2 = function(fluxslider, opts) {
        return new flux.transition_grid(fluxslider, $.extend({
            cols: 12,
            forceSquare: true,
            delayBetweenDiagnols: 150,
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                var delay = Math.floor(Math.random()*10*this.options.delayBetweenBars);
                
                $(elem).css({
                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': '-'+leftOffset+'px -'+topOffset+'px'
                }).css3({
                    'transition-duration': '350ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'all',
                    'transition-delay': (colIndex+rowIndex)*this.options.delayBetweenDiagnols+'ms',
                    'backface-visibility': 'hidden' // trigger hardware acceleration
                });
            },
            execute: function() {
                var _this = this;
    
                var blocks = this.slider.image1.find('div.tile');
    
                // Get notified when the last transition has completed
                blocks.last().transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    blocks.each(function(index, block){                
                        $(block).css({
                            'opacity': '0'
                        }).css3({
                            'transform': 'scale(0.8)'
                        });
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.concentric = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            blockSize: 60,
            delay: 150,
            alternate: false,
            setup: function() {
                var w = this.slider.image1.width(),
                    h = this.slider.image1.height(),
                    largestLength = Math.sqrt(w*w + h*h), // Largest length is the diagonal

                    // How many blocks do we need?
                    blockCount = Math.ceil(((largestLength-this.options.blockSize)/2) / this.options.blockSize) + 1, // 1 extra to account for the round border
                    fragment = document.createDocumentFragment();

                for(var i=0; i<blockCount; i++)
                {
                    var thisBlockSize = (2*i*this.options.blockSize)+this.options.blockSize;

                    var block = $('<div></div>').attr('class', 'block block-'+i).css({
                        width: thisBlockSize+'px',
                        height: thisBlockSize+'px',
                        position: 'absolute',
                        top: ((h-thisBlockSize)/2)+'px',
                        left: ((w-thisBlockSize)/2)+'px',

                        'z-index': 100+(blockCount-i),

                        'background-image': this.slider.image1.css('background-image'),
                        'background-position': 'center center'
                    }).css3({
                        'border-radius': thisBlockSize+'px',
                        'transition-duration': '800ms',
                        'transition-timing-function': 'linear',
                        'transition-property': 'all',
                        'transition-delay': ((blockCount-i)*this.options.delay)+'ms'
                    });

                    fragment.appendChild(block.get(0));
                }

                //this.slider.image1.append($(fragment));
                this.slider.image1.get(0).appendChild(fragment);
            },
            execute: function() {
                var _this = this;

                var blocks = this.slider.image1.find('div.block');

                // Get notified when the last transition has completed
                $(blocks[0]).transitionEnd(function(){
                    _this.finished();
                });

                setTimeout(function(){
                    blocks.each(function(index, block){
                        $(block).css({
                            'opacity': '0'
                        }).css3({
                            'transform': flux.browser.rotateZ((!_this.options.alternate || index%2 ? '' : '-')+'90')
                        });
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.warp = function(fluxslider, opts) {
        return new flux.transitions.concentric(fluxslider, $.extend({
            delay: 30,
            alternate: true
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.cube = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            requires3d: true,
            barWidth: 100,
            direction: 'left',
            perspective: 1000,
            setup: function() {
                var width = this.slider.image1.width();
                var height = this.slider.image1.height();

                // Setup the container to allow 3D perspective

                this.slider.imageContainer.css3({
                    'perspective': this.options.perspective,
                    'perspective-origin': '50% 50%'
                });

                this.cubeContainer = $('<div class="cube"></div>').css({
                    width: width+'px',
                    height: height+'px',
                    position: 'relative'
                }).css3({
                    'transition-duration': '800ms',
                    'transition-timing-function': 'linear',
                    'transition-property': 'all',
                    'transform-style': 'preserve-3d'
                });

                var css = {
                    height: '100%',
                    width: '100%',
                    position: 'absolute',
                    top: '0px',
                    left: '0px'
                };

                var currentFace = $('<div class="face current"></div>').css($.extend(css, {
                    background: this.slider.image1.css('background-image')    
                }));

                this.cubeContainer.append(currentFace);

                var nextFace = $('<div class="face next"></div>').css($.extend(css, {
                    background: this.slider.image2.css('background-image')
                })).css3({
                    'transform' : this.options.transitionStrings.call(this, this.options.direction, 'nextFace')
                });

                this.cubeContainer.append(nextFace);

                this.slider.image1.append(this.cubeContainer);
            },
            execute: function() {
                var _this = this;

                var width = this.slider.image1.width();
                var height = this.slider.image1.height();

                this.slider.image2.hide();
                this.cubeContainer.transitionEnd(function(){
                    _this.slider.image2.show();

                    _this.finished();
                });
                
                setTimeout(function(){
                    _this.cubeContainer.css3({
                        'transform' : _this.options.transitionStrings.call(_this, _this.options.direction, 'container')
                    });
                }, 50);
            },
            transitionStrings: function(direction, elem) {
                var width = this.slider.image1.width();
                var height = this.slider.image1.height();

                // Define the various transforms that are required to perform various cube rotations
                var t = {
                    'up' : {
                        'nextFace': flux.browser.rotateX(-90) + ' ' + flux.browser.translate(0, height/2, height/2),
                        'container': flux.browser.rotateX(90) + ' ' + flux.browser.translate(0, -height/2, height/2)
                    },
                    'down' : {
                        'nextFace': flux.browser.rotateX(90) + ' ' + flux.browser.translate(0, -height/2, height/2),
                        'container': flux.browser.rotateX(-90) + ' ' + flux.browser.translate(0, height/2, height/2)
                    },
                    'left' : {
                        'nextFace': flux.browser.rotateY(90) + ' ' + flux.browser.translate(width/2, 0, width/2),
                        'container': flux.browser.rotateY(-90) + ' ' + flux.browser.translate(-width/2, 0, width/2)
                    },
                    'right' : {
                        'nextFace': flux.browser.rotateY(-90) + ' ' + flux.browser.translate(-width/2, 0, width/2),
                        'container': flux.browser.rotateY(90) + ' ' + flux.browser.translate(width/2, 0, width/2)
                    }
                };

                return (t[direction] && t[direction][elem]) ? t[direction][elem] : false;
            }
        }, opts));    
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.tiles3d = function(fluxslider, opts) {
        return new flux.transition_grid(fluxslider, $.extend({
            requires3d: true,
            forceSquare: true,
            columns: 5,
            perspective: 600,
            delayBetweenBarsX: 200,
            delayBetweenBarsY: 150,
            renderTile: function(elem, colIndex, rowIndex, colWidth, rowHeight, leftOffset, topOffset) {
                var tile = $('<div></div>').css({
                    width: colWidth+'px',
                    height: rowHeight+'px',
                    position: 'absolute',
                    top: '0px',
                    left: '0px',
                    'z-index': 200,

                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': '-'+leftOffset+'px -'+topOffset+'px',
                    'background-repeat': 'no-repeat'
                }).css3({
                    'backface-visibility': 'hidden'
                });

                var tile2 = $(tile.get(0).cloneNode(false)).css({
                    'background-image': this.slider.image2.css('background-image'),
                    'z-index': 190
                }).css3({
                    'transform': flux.browser.rotateY(180)
                });

                $(elem).css({
                    'z-index': (colIndex > this.options.columns/2 ? 500-colIndex : 500) + (rowIndex > this.options.rows/2 ? 500-rowIndex : 500) // Fix for Chrome to ensure that the z-index layering is correct!
                }).css3({
                    'transition-duration': '800ms',
                    'transition-timing-function': 'ease-out',
                    'transition-property': 'all',
                    'transition-delay': (colIndex*this.options.delayBetweenBarsX+rowIndex*this.options.delayBetweenBarsY)+'ms',
                    'transform-style': 'preserve-3d'
                }).append(tile).append(tile2);
            },
            execute: function() {
                this.slider.imageContainer.css3({
                    'perspective': this.options.perspective,
                    'perspective-origin': '50% 50%'
                });
                
                var _this = this;

                var tiles = this.slider.image1.find('div.tile');

                this.slider.image2.hide();

                // Get notified when the last transition has completed
                tiles.last().transitionEnd(function(event){
                    _this.slider.image2.show();

                    _this.finished();
                });
                
                setTimeout(function(){
                    tiles.css3({
                        'transform': flux.browser.rotateY(180)
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.turn = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            requires3d: true,
            perspective: 1300,
            direction: 'left',
            setup: function() {
                var tab = $('<div class="tab"></div>').css({
                        width: '50%',
                        height: '100%',
                        position: 'absolute',
                        top: '0px',
                        left: this.options.direction == 'left' ? '50%' : '0%',
                        'z-index':101
                    }).css3({
                        'transform-style': 'preserve-3d',
                        'transition-duration': '1000ms',
                        'transition-timing-function': 'ease-out',
                        'transition-property': 'all',
                        'transform-origin': this.options.direction == 'left' ? 'left center' : 'right center'
                    }),

                front = $('<div></div>').appendTo(tab).css({
                        'background-image': this.slider.image1.css('background-image'),
                        'background-position': (this.options.direction == 'left' ? '-'+(this.slider.image1.width()/2) : 0)+'px 0',
                        width: '100%',
                        height: '100%',
                        position: 'absolute',
                        top: '0',
                        left: '0'
                    }).css3({
                        'backface-visibility': 'hidden'
                    }),

                back = $('<div></div>').appendTo(tab).css({
                        'background-image': this.slider.image2.css('background-image'),
                        'background-position': (this.options.direction == 'left' ? 0 : '-'+(this.slider.image1.width()/2))+'px 0',
                        width: '100%',
                        height: '100%',
                        position: 'absolute',
                        top: '0',
                        left: '0'
                    }).css3({
                        transform: flux.browser.rotateY(180),
                        'backface-visibility': 'hidden'
                    }),

                current = $('<div></div>').css({
                    position: 'absolute',
                    top: '0',
                    left: this.options.direction == 'left' ? '0' : '50%',
                    width: '50%',
                    height: '100%',
                    'background-image': this.slider.image1.css('background-image'),
                    'background-position': (this.options.direction == 'left' ? 0 : '-'+(this.slider.image1.width()/2))+'px 0',
                    'z-index':100
                }),

                overlay = $('<div class="overlay"></div>').css({
                    position: 'absolute',
                    top: '0',
                    left: this.options.direction == 'left' ? '50%' : '0',
                    width: '50%',
                    height: '100%',
                    background: '#000',
                    opacity: 1
                }).css3({
                    'transition-duration': '800ms',
                    'transition-timing-function': 'linear',
                    'transition-property': 'opacity'
                }),

                container = $('<div></div>').css3({
                    width: '100%',
                    height: '100%'
                }).css3({
                    'perspective': this.options.perspective,
                    'perspective-origin': '50% 50%'
                }).append(tab).append(current).append(overlay);

                this.slider.image1.append(container);
            },
            execute: function() {
                var _this = this;

                this.slider.image1.find('div.tab').first().transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    _this.slider.image1.find('div.tab').css3({
                        transform: flux.browser.rotateY(_this.options.direction == 'left' ? -180 : 180)
                    });
                    _this.slider.image1.find('div.overlay').css({
                        opacity: 0
                    });
                }, 50);
            }
        }, opts));
    };
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.slide = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            direction: 'left',
            setup: function() {
                var width = this.slider.image1.width(),
                    height = this.slider.image1.height(),

                currentImage = $('<div class="current"></div>').css({
                    height: height+'px',
                    width: width+'px',
                    position: 'absolute',
                    top: '0px',
                    left: '0px',
                    background: this.slider[this.options.direction == 'left' ? 'image1' : 'image2'].css('background-image')    
                }).css3({
                    'backface-visibility': 'hidden'
                }),

                nextImage = $('<div class="next"></div>').css({
                    height: height+'px',
                    width: width+'px',
                    position: 'absolute',
                    top: '0px',
                    left: width+'px',
                    background: this.slider[this.options.direction == 'left' ? 'image2' : 'image1'].css('background-image')
                }).css3({
                    'backface-visibility': 'hidden'
                });

                this.slideContainer = $('<div class="slide"></div>').css({
                    width: (2*width)+'px',
                    height: height+'px',
                    position: 'relative',
                    left: this.options.direction == 'left' ? '0px' : -width+'px',
                    'z-index': 101
                }).css3({
                    'transition-duration': '600ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'all'
                });

                this.slideContainer.append(currentImage).append(nextImage);

                this.slider.image1.append(this.slideContainer);
            },
            execute: function() {
                var _this = this,
                    delta = this.slider.image1.width();

                if(this.options.direction == 'left')
                    delta = -delta;

                this.slideContainer.transitionEnd(function(){
                    _this.finished();
                });
                
                setTimeout(function(){
                    _this.slideContainer.css3({
                        'transform' : flux.browser.translate(delta)
                    });
                }, 50);
            }
        }, opts));    
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.swipe = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            setup: function() {
                var img = $('<div></div>').css({
                    width: '100%',
                    height: '100%',
                    'background-image': this.slider.image1.css('background-image')
                }).css3({
                    'transition-duration': '1600ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'all',
                    'mask-image': '-webkit-linear-gradient(left, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 48%, rgba(0,0,0,1) 52%, rgba(0,0,0,1) 100%)',
                    'mask-position': '70%',
                    'mask-size': '400%'
                });
                
                this.slider.image1.append(img);
            },
            execute: function() {
                //return;
                var _this = this,
                    img = this.slider.image1.find('div');

                // Get notified when the last transition has completed
                $(img).transitionEnd(function(){
                    _this.finished();
                });

                setTimeout(function(){
                    $(img).css3({
                        'mask-position': '30%'
                    });
                }, 50);
            },
            compatibilityCheck: function() {
                return flux.browser.supportsCSSProperty('MaskImage');
            }
        }, opts));
    }
})(window.jQuery || window.Zepto);

(function($) {
    flux.transitions.dissolve = function(fluxslider, opts) {
        return new flux.transition(fluxslider, $.extend({
            setup: function() {
                var img = $('<div class="image"></div>').css({
                    width: '100%',
                    height: '100%',
                    'background-image': this.slider.image1.css('background-image')    
                }).css3({
                    'transition-duration': '600ms',
                    'transition-timing-function': 'ease-in',
                    'transition-property': 'opacity'
                });
                
                this.slider.image1.append(img);
            },
            execute: function() {
                var _this = this,
                    img = this.slider.image1.find('div.image');

                // Get notified when the last transition has completed
                $(img).transitionEnd(function(){
                    _this.finished();
                });

                setTimeout(function(){
                    $(img).css({
                        'opacity': '0.0'
                    });
                }, 50);
            }
        }, opts));
    }
})(window.jQuery || window.Zepto);

