/*
 * Flip! jQuery Plugin (http://lab.smashup.it/flip/)
 * @author Luca Manno (luca@smashup.it) [http://i.smashup.it]
 *              [Original idea by Nicola Rizzo (thanks!)]
 *
 * @version 0.9.9 [Nov. 2009]
 *
 * @changelog
 * v 0.9.9      ->      Fix transparency over non-colored background. Added dontChangeColor option.
 *                      Added $clone and $this parameters to on.. callback functions.
 *                      Force hexadecimal color values. Made safe for noConflict use.
 *                      Some refactoring. [Henrik Hjelte, Jul. 10, 2009]
 * 						Added revert options, fixes and improvements on color management.
 * 						Released in Nov 2009
 * v 0.5        ->      Added patch to make it work with Opera (thanks to Peter Siewert), Added callbacks [Feb. 1, 2008]
 * v 0.4.1      ->      Fixed a regression in Chrome and Safari caused by getTransparent [Oct. 1, 2008]
 * v 0.4        ->      Fixed some bugs with transparent color. Now Flip! works on non-white backgrounds | Update: jquery.color.js plugin or jqueryUI still needed :( [Sept. 29, 2008]
 * v 0.3        ->      Now is possibile to define the content after the animation.
 *                              (jQuery object or text/html is allowed) [Sept. 25, 2008]
 * v 0.2        ->      Fixed chainability and buggy innertext rendering (xNephilimx thanks!)
 * v 0.1        ->      Starting release [Sept. 11, 2008]
 *
 */
(function ($) {

    function int_prop(fx) {
        fx.elem.style[fx.prop] = parseInt(fx.now, 10) + fx.unit;
    }

    var throwError = function (message) {
            throw ({
                name: "jquery.flip.js plugin error",
                message: message
            });
        };

    var isIE6orOlder = function () {
            // User agent sniffing is clearly out of fashion and $.browser will be be deprectad.
            // Now, I can't think of a way to feature detect that IE6 doesn't show transparent
            // borders in the correct way.
            // Until then, this function will do, and be partly political correct, allowing
            // 0.01 percent of the internet users to tweak with their UserAgent string.
            //
            // Not leadingWhiteSpace is to separate IE family from, well who knows?
            // Maybe some version of Opera?
            // The second guess behind this is that IE7+  will keep supporting maxHeight in the future.
            // First guess changed to dean edwards ie sniffing http://dean.edwards.name/weblog/2007/03/sniff/
            return ( /*@cc_on!@*/ false && (typeof document.body.style.maxHeight === "undefined"));
        };


    // Some named colors to work with
    // From Interface by Stefan Petre
    // http://interface.eyecon.ro/
    var colors = {
        aqua: [0, 255, 255],
        azure: [240, 255, 255],
        beige: [245, 245, 220],
        black: [0, 0, 0],
        blue: [0, 0, 255],
        brown: [165, 42, 42],
        cyan: [0, 255, 255],
        darkblue: [0, 0, 139],
        darkcyan: [0, 139, 139],
        darkgrey: [169, 169, 169],
        darkgreen: [0, 100, 0],
        darkkhaki: [189, 183, 107],
        darkmagenta: [139, 0, 139],
        darkolivegreen: [85, 107, 47],
        darkorange: [255, 140, 0],
        darkorchid: [153, 50, 204],
        darkred: [139, 0, 0],
        darksalmon: [233, 150, 122],
        darkviolet: [148, 0, 211],
        fuchsia: [255, 0, 255],
        gold: [255, 215, 0],
        green: [0, 128, 0],
        indigo: [75, 0, 130],
        khaki: [240, 230, 140],
        lightblue: [173, 216, 230],
        lightcyan: [224, 255, 255],
        lightgreen: [144, 238, 144],
        lightgrey: [211, 211, 211],
        lightpink: [255, 182, 193],
        lightyellow: [255, 255, 224],
        lime: [0, 255, 0],
        magenta: [255, 0, 255],
        maroon: [128, 0, 0],
        navy: [0, 0, 128],
        olive: [128, 128, 0],
        orange: [255, 165, 0],
        pink: [255, 192, 203],
        purple: [128, 0, 128],
        violet: [128, 0, 128],
        red: [255, 0, 0],
        silver: [192, 192, 192],
        white: [255, 255, 255],
        yellow: [255, 255, 0],
        transparent: [255, 255, 255]
    };

    var acceptHexColor = function (color) {
            if (color && color.indexOf("#") == -1 && color.indexOf("(") == -1) {
                return "rgb(" + colors[color].toString() + ")";
            } else {
                return color;
            }
        };

    $.extend($.fx.step, {
        borderTopWidth: int_prop,
        borderBottomWidth: int_prop,
        borderLeftWidth: int_prop,
        borderRightWidth: int_prop
    });

    $.fn.revertFlip = function () {
        return this.each(function () {
            var $this = $(this);
            $this.flip($this.data('flipRevertedSettings'));
        });
    };

    $.fn.flip = function (settings) {
        return this.each(function () {
            var $this = $(this),
                flipObj, $clone, dirOption, dirOptions, newContent, ie6 = isIE6orOlder();

            if ($this.data('flipLock')) {
                return false;
            }

            var revertedSettings = {
                direction: (function (direction) {
                    switch (direction) {
                    case "tb":
                        return "bt";
                    case "bt":
                        return "tb";
                    case "lr":
                        return "rl";
                    case "rl":
                        return "lr";
                    default:
                        return "bt";
                    }
                })(settings.direction),
                bgColor: acceptHexColor(settings.color) || "#FFF",
                color: acceptHexColor(settings.bgColor) || $this.css("background-color"),
                content: $this.html(),
                speed: settings.speed || 500,
                onBefore: settings.onBefore ||
                function () {},
                onEnd: settings.onEnd ||
                function () {},
                onAnimation: settings.onAnimation ||
                function () {}
            };

            $this.data('flipRevertedSettings', revertedSettings).data('flipLock', 1).data('flipSettings', revertedSettings);

            flipObj = {
                width: $this.width(),
                height: $this.height(),
                bgColor: acceptHexColor(settings.bgColor) || $this.css("background-color"),
                fontSize: $this.css("font-size") || "12px",
                direction: settings.direction || "tb",
                toColor: acceptHexColor(settings.color) || "#FFF",
                speed: settings.speed || 500,
                top: $this.offset().top,
                left: $this.offset().left,
                target: settings.content || null,
                transparent: "transparent",
                dontChangeColor: settings.dontChangeColor || false,
                onBefore: settings.onBefore ||
                function () {},
                onEnd: settings.onEnd ||
                function () {},
                onAnimation: settings.onAnimation ||
                function () {}
            };

            // This is the first part of a trick to support
            // transparent borders using chroma filter for IE6
            // The color below is arbitrary, lets just hope it is not used in the animation
            ie6 && (flipObj.transparent = "#123456");

            $clone = $this.css("visibility", "hidden").clone(true).data('flipLock', 1).appendTo("body").html("").css({
                visibility: "visible",
                position: "absolute",
                left: flipObj.left,
                top: flipObj.top,
                margin: 0,
                zIndex: 9999,
                "-webkit-box-shadow": "0px 0px 0px #FFF",
                "-moz-box-shadow": "0px 0px 0px #FFF"
            });

            var defaultStart = function () {
                    return {
                        backgroundColor: flipObj.transparent,
                        fontSize: 0,
                        lineHeight: 0,
                        borderTopWidth: 0,
                        borderLeftWidth: 0,
                        borderRightWidth: 0,
                        borderBottomWidth: 0,
                        borderTopColor: flipObj.transparent,
                        borderBottomColor: flipObj.transparent,
                        borderLeftColor: flipObj.transparent,
                        borderRightColor: flipObj.transparent,
                        background: "none",
                        borderStyle: 'solid',
                        height: 0,
                        width: 0
                    };
                };
            var defaultHorizontal = function () {
                    var waist = (flipObj.height / 100) * 25;
                    var start = defaultStart();
                    start.width = flipObj.width;
                    return {
                        "start": start,
                        "first": {
                            borderTopWidth: 0,
                            borderLeftWidth: waist,
                            borderRightWidth: waist,
                            borderBottomWidth: 0,
                            borderTopColor: '#FFF',
                            borderBottomColor: '#FFF',
                            top: (flipObj.top + (flipObj.height / 2)),
                            left: (flipObj.left - waist)
                        },
                        "second": {
                            borderBottomWidth: 0,
                            borderTopWidth: 0,
                            borderLeftWidth: 0,
                            borderRightWidth: 0,
                            borderTopColor: flipObj.transparent,
                            borderBottomColor: flipObj.transparent,
                            top: flipObj.top,
                            left: flipObj.left
                        }
                    };
                };
            var defaultVertical = function () {
                    var waist = (flipObj.height / 100) * 25;
                    var start = defaultStart();
                    start.height = flipObj.height;
                    return {
                        "start": start,
                        "first": {
                            borderTopWidth: waist,
                            borderLeftWidth: 0,
                            borderRightWidth: 0,
                            borderBottomWidth: waist,
                            borderLeftColor: '#FFF',
                            borderRightColor: '#FFF',
                            top: flipObj.top - waist,
                            left: flipObj.left + (flipObj.width / 2)
                        },
                        "second": {
                            borderTopWidth: 0,
                            borderLeftWidth: 0,
                            borderRightWidth: 0,
                            borderBottomWidth: 0,
                            borderLeftColor: flipObj.transparent,
                            borderRightColor: flipObj.transparent,
                            top: flipObj.top,
                            left: flipObj.left
                        }
                    };
                };

            dirOptions = {
                "tb": function () {
                    var d = defaultHorizontal();
                    d.start.borderTopWidth = flipObj.height;
                    d.start.borderTopColor = flipObj.bgColor;
                    d.second.borderBottomWidth = flipObj.height;
                    d.second.borderBottomColor = flipObj.toColor;
                    return d;
                },
                "bt": function () {
                    var d = defaultHorizontal();
                    d.start.borderBottomWidth = flipObj.height;
                    d.start.borderBottomColor = flipObj.bgColor;
                    d.second.borderTopWidth = flipObj.height;
                    d.second.borderTopColor = flipObj.toColor;
                    return d;
                },
                "lr": function () {
                    var d = defaultVertical();
                    d.start.borderLeftWidth = flipObj.width;
                    d.start.borderLeftColor = flipObj.bgColor;
                    d.second.borderRightWidth = flipObj.width;
                    d.second.borderRightColor = flipObj.toColor;
                    return d;
                },
                "rl": function () {
                    var d = defaultVertical();
                    d.start.borderRightWidth = flipObj.width;
                    d.start.borderRightColor = flipObj.bgColor;
                    d.second.borderLeftWidth = flipObj.width;
                    d.second.borderLeftColor = flipObj.toColor;
                    return d;
                }
            };

            dirOption = dirOptions[flipObj.direction]();

            // Second part of IE6 transparency trick.
            ie6 && (dirOption.start.filter = "chroma(color=" + flipObj.transparent + ")");

            newContent = function () {
                var target = flipObj.target;
                return target && target.jquery ? target.html() : target;
            };

            $clone.queue(function () {
                flipObj.onBefore($clone, $this);
                $clone.html('').css(dirOption.start);
                $clone.dequeue();
            });

            $clone.animate(dirOption.first, flipObj.speed);

            $clone.queue(function () {
                flipObj.onAnimation($clone, $this);
                $clone.dequeue();
            });
            $clone.animate(dirOption.second, flipObj.speed);

            $clone.queue(function () {
                if (!flipObj.dontChangeColor) {
                    $this.css({
                        backgroundColor: flipObj.toColor
                    });
                }
                $this.css({
                    visibility: "visible"
                });

                var nC = newContent();
                if (nC) {
                    $this.html(nC);
                }
                $clone.remove();
                flipObj.onEnd($clone, $this);
                $this.removeData('flipLock');
                $clone.dequeue();
            });
        });
    };
})(jQuery);
