(function ($) {
    // FlipBox v0.1 - 2009 Zachary Johnson www.zachstronaut.com
    // Another LightBox variant, this time with "3D" isometric rotating tiles.
    // Visual effect currently supported in Safari/Chrome/WebKit and Firefox 3.5+
    //
    // *This code is not currently licensed for any commercial use.*
    
    var thingsToLoad = 1; // window load is 1
    
    var tallyLoad = function () {
        thingsToLoad--;
        
        if (thingsToLoad <= 0) {
            afterLoad();
        }
    }

    var mouseenter = function (e) {
        $(this).parents('.flipbox').find('li a').not(this).css('opacity', '0.5');
    };

    var mouseleave = function (e) {
        $(this).parents('.flipbox').find('li a').not(this).css('opacity', '1.0');
    };

    var mySideChange = function (front) {
        if (front) {
            $(this).find('div').css('display', 'block');
        
        } else {
            $(this).find('div').css('display', 'none');
            $(this).find('a')
                .bind('mouseenter', mouseenter)
                .bind('mouseleave', mouseleave);
        }
    };

    // Private function for now... could be added to the jQuery prototype
    var flipAll = function ($what, complete) {
        /*
        // Rotate each for a randomly different duration for an organic/human feel
        $what.each(function () {
            $(this).rotate3Di('-=180', 1500 + Math.floor(Math.random() * 1500), {sideChange: mySideChange});
        });
        */
        
        if (typeof complete != 'function') {
            complete = function () {};
        }
        
        var rc = 0;
        $what.each(function () {
            rc++;
            var $self = $(this);
            
            var confObj = null;
            if (rc == $what.length) {
                confObj = {sideChange: mySideChange, complete: complete};
            } else {
                confObj = {sideChange: mySideChange};
            }
            
            setTimeout(function () {$self.rotate3Di('-=180', 1500, confObj);}, rc * 20);
        });
    };

    var afterLoad = function () {
        // For all .flipbox'es
        $('.flipbox').each(function () {
            // Help diffentiate from other uses of $(this)
            var $flipbox = $(this);
            
            var finishSetup = function () {
                // Set the cursor for all flip-side divs... now that things will be clickable
                $flipbox.find('li').css('cursor', 'pointer');

                $flipbox.find('li a').bind(
                    'click',
                    function (e) {
                        e.preventDefault();

                        $flipbox.find('li a').unbind('mouseenter', mouseenter).unbind('mouseleave', mouseleave);
                        $flipbox.find('li a').not(this).css('opacity', '1.0');

                        var image = $(this).attr('href');

                        $flipbox.find('li div').css('backgroundImage', 'url(' + image + ')');

                        flipAll($flipbox.find('li'));

                        location.hash = '#' + $(this).attr('id').replace(/id-/, '');
                    }
                );

                $flipbox.find('div').click(function () {
                    // Safari shows a loading page spinner forever if you set .hash to just '' or '#'
                    location.hash = '#flipbox';
                    flipAll($flipbox.find('li'));
                });
            };
            
            if (!location.hash.match(/^#img-.*$/) || !$(this).find(location.hash.replace(/#img/, '#id-img')).length) {
                flipAll($(this).find('li'), finishSetup);
            } else {
                finishSetup();
            }
        });
    };
    
    $(document).ready(function () {
        // For all .flipbox'es
        $('.flipbox').each(function () {
            // Help diffentiate from other uses of $(this)
            $flipbox = $(this);
            
            // Store this because it is used multiple times in this block
            var $flipbox_lis = $flipbox.find('li');

            // Add the divs for the flip-side
            $flipbox_lis.prepend('<div></div>');

            // Z-Index in reverse for a more convincing look.
            var z = $flipbox_lis.length + 1;
            $flipbox_lis.each(function () {
                $(this).css('zIndex', z--);
            });

            // Each anchor in ul.flipbox needs an id so we can change location and send people hash links to specific images.
            // This does blow away any id set by the user...
            // We should preload the fullsize images, too.
            $flipbox.find('li a').each(function () {
                var id = 'id-img-' + $(this).attr('href').split('/').pop().match(/^([^.]+)/)[1].replace(/[^-a-z0-9]+/gi, '-').replace(/(^-|-$)/g, '');
                $(this).attr('id', id);
                
                // Preload
                thingsToLoad++;
                var img = new Image();
                img.onload = tallyLoad;
                img.src = $(this).attr('href');
            });
            
            // Don't let people click through during preloading/loading animation
            $flipbox.find('li a').bind(
                'click',
                function (e) {
                    e.preventDefault();
                }
            );

            // Set background position offsets for each flip-side div
            var imgWidth = $flipbox.find('li a img:first').width();
            var imgHeight = $flipbox.find('li a img:first').height();
            var ulWidth = $flipbox.width();
            var perRow = ulWidth / imgWidth;
            $flipbox.find('li div').each(function (i) {
                var bgleft = -1 * (i * imgWidth) % ulWidth;
                var bgtop = -1 * Math.floor(i / perRow) * imgHeight;
                $(this).css('backgroundPosition', bgleft + 'px ' + bgtop + 'px');
            });

            // Use background image of ul.flipbox as the loading image and
            // set the background image for all flip-side divs to use it
            $flipbox.find('li div').css('backgroundImage', $flipbox.css('backgroundImage'));//'url(' + loadingImage + ')');

            // Remove the ul.flipbox loading background image since it is now applied to the flip-side divs
            $flipbox.css('backgroundImage', 'none');

            // Un-hide .flipbox list items
            $flipbox_lis.css('left', 0);
            
            // If the page we are loading has an #hashtag request then
            // set the background image for all flip-side divs to use it
            // after the loading animation has completed.
            var useImage = '';
            if (location.hash.match(/^#img-.*$/)) {
                var img = $flipbox.find(location.hash.replace(/#img/, '#id-img'));
                if (img.length) {
                    useImage = img.attr('href');
                }
            }
            
            // Loading Animation
            var rc = 0;
            $flipbox_lis.each(function () {
                rc++;
                var $self = $(this);
                setTimeout(
                    function () {
                        $self.rotate3Di(
                            '-=360',
                            3000,
                            {
                                sideChange: function (front) {
                                    if (front) {
                                        if (useImage) {
                                            $flipbox.find('li div').css('backgroundImage', 'url(' + useImage + ')');
                                        }
                                        $(this).find('div').css('display', 'block');

                                    } else {
                                        $(this).find('div').css('display', 'none');
                                    }
                                }
                            }
                        );
                    },
                    rc * 20
                );
            });
            // Wait for loading animation to finish before proceeding
            thingsToLoad++;
            setTimeout(tallyLoad, 3000 + rc * 20);
            
            $(window).load(tallyLoad);
        });
    });
})(jQuery);
