(function($){
    var ie = false; if ($.browser.msie) ie = parseInt($.browser.version);
    // HANDLER:

    $.extend($.fn, {
        flowPanes: function(options){
            return $(this).each(function(){
                var $this = $(this);
                if($this.data('flowPanes')){
                    var flowPanes = $this.data('flowPanes');
                    $.extend(true, {}, flowPanes.settings, options);
                    flowPanes.render();
                }
                else $this.data('flowPanes', new FlowPanes(this, options));
           });
        }
    });

    // CONSTRUCTOR:

    FlowPanes = function(elem, options){
        this.elem = $(elem);
        var this_ = this;
        var defaults = {
            fpList: [],
            fpNear: { 
                top: 0.31,//0.07,
                left: 0.67,//0.75,
                width: 0.3,//0.37,
                height: 0.65//0.87
            },
            fpFar: { 
                top: 0.39,
                left: 0.17,
                width: 0.17
            },
            fps: {
                farTopShift: -0.017,
                farLeftShift: -0.07,//-0.07,
                resize: 1.07
            },
            nullPoint: {},
            durations: { 
                fpMove: 250/*230/*370/*5700 for easing.js*/,
                fpStartShowDuration: 370,
                fpStartShowDelay: 570,
                fpClick: 370
            }
        };
        this.settings = $.extend(true, defaults, options);
        
        if(ie) {
            this.settings.fps.farTopShift = 0;
            this.settings.fpNear.height = (this.settings.fpNear.height / 1.25).toFixed(4);
        }
        this.settings.fpFar = $.extend(this.settings.fpFar, {
            height: (this.settings.fpFar.width / (this.settings.fpNear.width / this.settings.fpNear.height)).toFixed(4)
        });
        this.settings.nullPoint = $.extend(this.settings.nullPoint, {
            top: ((this.settings.fpFar.width * this.settings.fpNear.top - this.settings.fpFar.top * this.settings.fpNear.width) / (this.settings.fpFar.width - this.settings.fpNear.width)).toFixed(4),
            left: ((this.settings.fpFar.width * this.settings.fpNear.left - this.settings.fpFar.left * this.settings.fpNear.width) / (this.settings.fpFar.width - this.settings.fpNear.width)).toFixed(4)
        });

        var images = new Array();
        $(this.settings.fpList).each(function(index){
            images[index] = this.image;
            return this;
        });
        preload(images);

        if(ie) {
            this.setDOM().setSize().setReflexAndSkew().setCSS().setListener().show(0);
        }
        else {
            this.setDOM().setSize().setReflexAndSkew();
        }
    };

    // METHODS:

    $.extend(FlowPanes.prototype, {

        render: function(){
            return this;
        },

        setDOM: function(){
//$("#CONSOLE").append("<br/><b>setDOM:<b/><br/>");
            if(this.settings.fpList.length > 1) {
                var thisElem = this.elem;
                var thisSettings = this.settings;

                $(this.settings.fpList).each(function(index){
                    $("<div id='fp" + index + "' class='fp'>")
                        .css({ zIndex: (index + 10) * 10, display: "none" })
                        .appendTo(thisElem)
                        .append(function(){
                            return $("<img class='fpi reflex itiltright' alt=''/>").attr({
                                id: "fpi" + index,
                                src: thisSettings.fpList[index].image
                            });
                        });
                        return this;
                });
                return this;
            }
            return false;
        },

        setSize: function(){
//$("#CONSOLE").append("<br/><b>setSize:<b/><br/>");
            var thisElem = this.elem;
            var thisSettings = this.settings;
            var kSize = Math.pow(thisSettings.fpNear.width / thisSettings.fpFar.width, 1 / (thisSettings.fpList.length - 1)).toFixed(4);
//$("#CONSOLE").append("<br/>kSize: " + kSize);

            // RELATIVE sizes of EASY flow pane (index = 0):
            var top = thisSettings.fpFar.top, left = thisSettings.fpFar.left, width = thisSettings.fpFar.width, height = thisSettings.fpFar.height;

            // RELATIVE sizes of SELECTED flow pane (index = 0):
            var top_s = 1 * thisSettings.fpFar.top + 1 * thisSettings.fps.farTopShift, left_s = 1 * thisSettings.fpFar.left + 1 * thisSettings.fps.farLeftShift, width_s = (thisSettings.fpFar.width * thisSettings.fps.resize).toFixed(4), height_s = (thisSettings.fpFar.height * thisSettings.fps.resize).toFixed(4);

//$("#CONSOLE").append("<br/>thisElem.width(): " + thisElem.width() + "<br/>thisElem.height(): " + thisElem.height() + "<br/>");
            $(".fp", this.elem).each(function(index){
                if (index) {
                    top = (1 * thisSettings.nullPoint.top + (top - 1 * thisSettings.nullPoint.top) * kSize).toFixed(4);
                    left = (1 * thisSettings.nullPoint.left + (left - 1 * thisSettings.nullPoint.left) * kSize).toFixed(4);
                    width = (width * kSize).toFixed(4);
                    height = (height * kSize).toFixed(4);
                    top_s = (1 * thisSettings.nullPoint.top + (top_s - 1 * thisSettings.nullPoint.top) * kSize).toFixed(4);
                    left_s = (1 * thisSettings.nullPoint.left + (left_s - 1 * thisSettings.nullPoint.left) * kSize).toFixed(4);
                    width_s = (width_s * kSize).toFixed(4);
                    height_s = (height_s * kSize).toFixed(4);
                }

                if(index != thisSettings.fpList.length - 1) $(this).data({
                    "top": (top * thisElem.height()).toFixed(0) + "px",
                    "left": (left * thisElem.width()).toFixed(0) + "px",
                    "width": (width * thisElem.width()).toFixed(0) + "px",
                    "height": (height * thisElem.height()).toFixed(0) + "px",
                    "top_s": (top_s * thisElem.height()).toFixed(0) + "px",
                    "left_s": (left_s * thisElem.width()).toFixed(0) + "px",
                    "width_s": (width_s * thisElem.width()).toFixed(0) + "px",
                    "height_s": (height_s * thisElem.height()).toFixed(0) + "px"
                });
//$("#CONSOLE").append("<br/>index: " + index + "<br/>t/t_s: " + $(this).data("top") + "/" + $(this).data("top_s") + "<br/>l/l_s: " + $(this).data("left") + "/"+ $(this).data("left_s") + "<br/>w/w_s: " + $(this).data("width") + "/" + $(this).data("width_s") + "<br>h/h_s: " + $(this).data("height") + "/" + $(this).data("height_s") + "<br/>");
//$("#CONSOLE").append("<br/>index: " + index + "<br/>t/t_s: " + top + "/" + top_s + "<br/>l/l_s: " + left + "/"+ left_s + "<br/>w/w_s: " + width + "/" + width_s + "<br>h/h_s: " + height + "/" + height_s + "<br/>");
            });
            $(".fp:last", this.elem).data({
                "top": (top * thisElem.height()).toFixed(0) + "px",
                "left": (left * thisElem.width()).toFixed(0) + "px",
                "width": (width * thisElem.width()).toFixed(0) + "px",
                "height": (height * thisElem.height()).toFixed(0) + "px",
                "top_s": (top * thisElem.height()).toFixed(0) + "px",
                "left_s": (left * thisElem.width()).toFixed(0) + "px",
                "width_s": (width * thisElem.width()).toFixed(0) + "px",
                "height_s": (height * thisElem.height()).toFixed(0) + "px"
            });

            return this;
        },

        setReflexAndSkew: function(){
//$("#CONSOLE").append("<br/><b>setReflexAndSkew:<b/><br/>");
            if(window.addEventListener) window.addEventListener("load", addReflex, false);
            else window.attachEvent("onload", addIEReflex);
            return this;
        },

        setCSS: function(){
//$("#CONSOLE").append("<br/><b>setCSS:<b/><br/>");
            $(".fp", this.elem).each(function(index){
                $(this).css({
                    position: "absolute",
                    top: $(this).data("top"),
                    left: $(this).data("left"),
                    zIndex: index *10 + 1,
                    cursor: "pointer"
                });
            });
            $(".fpi", this.elem).each(function(index){
                $("#fpi" + index).stop().css({
                    position: "absolute",
                    top: "0px",
                    left: "0px",
                    width: $(this).parent().data("width"),
                    height: $(this).parent().data("height")
                });
                return this;
            });
            return this;
        },

        setListener: function(){
//$("#CONSOLE").append("<br/><b>setListener:<b/><br/>");
            var thisSettings = this.settings;
            $(".fp", this.elem).each(function(index){
                if(!ie) $(this).bind("mouseenter", function() {
                    $(this).stop().animate({
                        top: $(this).data("top_s"),
                        left: $(this).data("left_s")
                    }, thisSettings.durations.fpMove
                    //{ durations: thisSettings.durations.fpMove, easing: "easeOutQuad" }
                    );
                    $("#fpi" + index).stop().animate({
                        width: $(this).data("width_s"),
                        height: $(this).data("height_s")
                    }, thisSettings.durations.fpMove
                    //{ durations: thisSettings.durations.fpMove, easing: "easeOutQuad" }
                    );
                    return this;
                }).bind("mouseleave", function(){
                    mouseleave_(this);return this;
                });
                $(this).bind("click", function() {
                    var fp = this;
                    window.setTimeout(function(){
                        mouseleave_(fp);
                    }, thisSettings.durations.fpClick);
                    location.href = thisSettings.fpList[index].href;
                    return this;
                });
                function mouseleave_(fp){
                    $(fp).stop().animate({ 
                        top: $(fp).data("top"), left: $(fp).data("left")
                    }, thisSettings.durations.fpMove
                    //{ durations: thisSettings.durations.fpMove, easing: "easeOutQuad" }
                    );
                    $("#fpi" + index).stop().animate({
                        width: $(fp).data("width"), height: $(fp).data("height")
                    }, thisSettings.durations.fpMove
                    //{ durations: thisSettings.durations.fpMove, easing: "easeOutQuad" }
                    );
                    return fp;
                }
                return this;
            });
            return this;
        },

        show: function(duration){
//$("#CONSOLE").append("<br/><b>show:<b/><br/>");
            $(".fp", this.elem).fadeIn(duration);
            return this;
        },

        unbind: function(){
//$("#CONSOLE").append("<br/><b>unbind:<b/><br/>");
            $(".fp", this.elem).each(function(){
                $(this).unbind("mouseenter").unbind("mouseleave").unbind("click");
            });
            return this;
        },

        destroy: function(){
            $(this.elem).html("");
            return this;
        },

        resize: function(){
//$("#CONSOLE").append("<br/><b>resize:<b/><br/>");
            if(ie) {
                this.destroy().setDOM().setSize().setReflexAndSkew().setCSS().setListener().show(0);
            }
            else this.setSize().setCSS().setListener().show(this.settings.durations.fpStartShowDuration);

            return this;
        }

    });

})(jQuery);
