/**
 * FlagNav is a jQuery plugin to build a flag style multi-level vertical navigation menu
 * 
 * Version: 1.0.0
 * @author    paopao http://paopao.name
 * @requires jQuery v1.2.3 or above
 * @requires jQuery Easing Plugin v1.3
 * http://www.paopao.name/programme/javascript/flag-style-multi-level-vertical-navigation-menu.html
 * 
 * Copyright (c) 2009 paopao (paopao.name)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * 
 * // basic usage receives bgposout and bgposover options in a object
 * $("#nav").flagNav({
 *   bgposout:"-261px 0px", // string = "a" background position onMouseOut
 *   bgposover:"-79px 0px"  // string = "a" background position onMouseOver
 * });
 * 
 * // advanced usage receives more options in a object
 * $("#nav").flagNav({
 *   bgposout:"-261px 0px", // string = "a" background position onMouseOut
 *   bgposover:"-79px 0px", // string = "a" background position onMouseOver || default = bgposout
 *   bgouttime: 500,    // number = "a" background animation time onMouseOver || default = flagouttime
 *   bgintime: 500,     // number = "a" background animation time onMouseOut || default = bgouttime
 *   rollback: false,   // boolean = with or without backword animation || default = false
 *   flagouttime: 500,  // number = flag out animation time onMouseOver || default = 500
 *   flagoutanim: "swing",  // string = flag out animation effect onMouseOver || default = "swing"
 *   flagdowntime: 400,     // number = flag down animation time onMouseOver || default = 400
 *   flagdownanim: "easeOutBounce", // string = flag down animation effect onMouseOver || default = "easeOutBounce"
 *   flaguptime: 400,       // number = flag up animation time onMouseOut || default = flagdowntime
 *   flagupanim: "easeInBounce",    // string = flag up animation effect onMouseOut || default = "easeInBounce"
 *   flagintime: 500,   // number = flag in animation time onMouseOut || default = flagouttime
 *   flaginanim: "swing",   // string = flag in animation effect onMouseOut || default = flagoutanim
 *   lineheight: $("li ul", $nav).css("line-height"),   // string = "li" height with unit || default = "ul" line-height
 *   width: $("li", $nav).width()   // string = "li" width with unit || default = "li" width
 * });
 * 
 * @param  o  An object with configuration options
 */
jQuery.fn.extend({
	flagNav : function(o) {
        var $nav = $(this);
		// default configuration options
		var cfg = {
            bgposout: $("a", $nav).css("background-position"),
            rollback: false,
            flagouttime: 500,
            flagoutanim: "swing",
            flagdowntime: 400,
            flagdownanim: "easeOutBounce",
            flagupanim: "easeInBounce",
            lineheight: $("li ul", $nav).css("line-height"),
            width: $("li", $nav).width()
		};
		// override configuration options with user supplied object
		cfg = $.extend(cfg, o ? o : {});
        // override self configuration options
        cfg.bgouttime = cfg.bgouttime ? cfg.bgouttime : cfg.flagouttime;
        cfg.bgintime = cfg.bgintime ? cfg.bgintime : cfg.bgouttime;
        cfg.flagintime = cfg.flagintime ? cfg.flagintime : cfg.flagouttime;
        cfg.flaginanim = cfg.flaginanim ? cfg.flaginanim : cfg.flagoutanim;
        cfg.flaguptime = cfg.flaguptime ? cfg.flaguptime : cfg.flagdowntime;
        cfg.bgposover = cfg.bgposover ? cfg.bgposover : cfg.bgposout;
        // get number part and unit part of cfg.lineheight
        var parts = cfg.lineheight.match(/^([\d+-.]+)(.*)$/);
        cfg.heightnum = parts[1];
        cfg.unit = parts[2];
        // save number of children "li" for every sub "ul"
        $("ul", $nav).each(function(){
            $(this).data("num", $(this).children("li").length);
        });
        // set default style for sub "ul"
        $("ul", $nav).css({overflow:"hidden", left:"0px", height:cfg.lineheight});
        // set z-index for every "ul"
        var zi = 0;
        $nav.css("z-index", zi);
        for(var i = $nav.children("li").children("ul"); i.length ; i = i.children("li").children("ul")) {
            zi--;
            i.css("z-index", zi);
        }
        // hover functions for flag animation of "li" with submenu
        $("li:has(ul)", $nav).hover(function(){
            var $subul = $(this).children("ul");
            // stop currently running animations
		    $subul.stop()
                // set initial style
                .css( {visibility:"visible", overflow:"hidden", height:cfg.lineheight} )
                // flag out animation
                .animate( {left:cfg.width}, cfg.flagouttime, cfg.flagoutanim )
                // flag down animation
                .animate( {height:cfg.heightnum * $subul.data("num") + cfg.unit}, cfg.flagdowntime, cfg.flagdownanim, function(){
                    // callback function to change overflow style
                    $subul.css( {overflow:"visible"} );
                    $("ul",$subul).css({overflow:"hidden", left:"0px"});
                } );
		},function(){
            var $subul = $(this).children("ul");
            if(!cfg.rollback) { // without backword animation
		        $subul.stop()
                    .css( {visibility:"hidden", height:cfg.lineheight, left:"0px", overflow:"hidden"} );
            } else { // backword animation
                // stop currently running animations and clear the queue
                $subul.stop(true,false)
                    // set initial style
                    .css( {overflow:"hidden"} )
                    // flag up animation
                    .animate( {height:cfg.lineheight}, cfg.flaguptime, cfg.flagupanim )
                    // flag in animation
                    .animate( {left:"0px"}, cfg.flagintime, cfg.flaginanim );
            }
		});
        // hover functions for background iamge animations of "a"
        $("a", $nav).css( {backgroundPosition: cfg.bgposout} )
	        .hover(function(){
                    // onMouseOver background iamge animation
    		        $(this).stop().animate(
	    		        {backgroundPosition:cfg.bgposover}, 
		    	        {duration:cfg.bgouttime});
		        }, function(){
                    // onMouseOut background iamge animation
	    	        $(this).stop().animate(
		    	        {backgroundPosition:cfg.bgposout}, 
			            {duration:cfg.bgintime});
		        });
        return $nav;
	}
});