/*
 * jquery.splitter.js - two-pane splitter window plugin
 *
 * version 1.01 (01/05/2007) 
 * 
 * Dual licensed under the MIT and GPL licenses: 
 *   http://www.opensource.org/licenses/mit-license.php 
 *   http://www.gnu.org/licenses/gpl.html 
 */

/**
 * The splitter() plugin implements a two-pane resizable splitter window.
 * The selected elements in the jQuery object are converted to a splitter;
 * each element should have two child elements which are used for the panes
 * of the splitter. The plugin adds a third child element for the splitbar.
 * 
 * For more details see: http://methvin.com/jquery/splitter/
 *
 *
 * @example $('#MySplitter').splitter();
 * @desc Create a vertical splitter with default settings 
 *
 * @example $('#MySplitter').splitter({direction: 'h', accessKey: 'M'});
 * @desc Create a horizontal splitter resizable via Alt+Shift+M
 *
 * @name splitter
 * @type jQuery
 * @param String options Options for the splitter
 * @cat Plugins/Splitter
 * @return jQuery
 * @author Dave Methvin (dave.methvin@gmail.com)
 */
 jQuery.fn.splitter = function(opts){
    opts = jQuery.extend({
        type: 'v',              // v=vertical, h=horizontal split
        activeClass: 'active',  // class name for active splitter
        pxPerKey: 5,            // splitter px moved per keypress
        tabIndex: 0,            // tab order indicator
        accessKey: ''           // accelerator key for splitter
//      initA  initB            // initial A/B size (pick ONE)
//      minA maxA  minB maxB    // min/max pane sizes
    },{
        v: {                    // Vertical splitters:
            keyGrowA: 39,       //  left arrow key
            keyShrinkA: 37,     //  right arrow key
            cursor: "e-resize", //  double-arrow horizontal
            splitbarClass: "vsplitbar",
            eventPos: "pageX", set: "left", 
            adjust: "width",  offsetAdjust: "offsetWidth",  adjSide1: "Left", adjSide2: "Right",
            fixed:  "height", offsetFixed:  "offsetHeight", fixSide1: "Top",  fixSide2: "Bottom"
        },
        h: {                    // Horizontal splitters:
            keyGrowA: 40,       //  down arrow key
            keyShrinkA: 38,     //  up arrow key
            cursor: "n-resize", //  double-arrow vertical
            splitbarClass: "hsplitbar",
            eventPos: "pageY", set: "top", 
            adjust: "height", offsetAdjust: "offsetHeight", adjSide1: "Top",  adjSide2: "Bottom",
            fixed:  "width",  offsetFixed:  "offsetWidth",  fixSide1: "Left", fixSide2: "Right"
        }
    }[((opts||{}).type||'v').charAt(0).toLowerCase()], opts||{});

    return this.each(function() {
        function startSplit(e) {
            splitbar.addClass(opts.activeClass);
            if ( e.type == "mousedown" ) {
                paneA._posAdjust = paneA[0][opts.offsetAdjust] - e[opts.eventPos];
                jQuery(document)
                    .bind("mousemove", doSplitMouse)
                    .bind("mouseup", endSplit);
            }
            return true;    // required???
        }
        function doSplitKey(e) {
            var key = e.which || e.keyCode;
            var dir = key==opts.keyGrowA? 1 : key==opts.keyShrinkA? -1 : 0;
            if ( dir )
                moveSplitter(paneA[0][opts.offsetAdjust]+dir*opts.pxPerKey);
            return true;    // required???
        }
        function doSplitMouse(e) {
            moveSplitter(paneA._posAdjust+e[opts.eventPos]);
        }
        function endSplit(e) {
            splitbar.removeClass(opts.activeClass);
            jQuery(document)
                .unbind("mousemove", doSplitMouse)
                .unbind("mouseup", endSplit);
        }
        function moveSplitter(np) {
            // Constrain new position to fit pane size limits; 16=scrollbar fudge factor
            // TODO: enforce group width in IE6 since it lacks min/max css properties?
            np = Math.max(paneA._min+paneA._padAdjust, group._adjust - (paneB._max||9999), 16,
                Math.min(np, paneA._max||9999, group._adjust - splitbar._adjust - 
                    Math.max(paneB._min+paneB._padAdjust, 16)));

            // Resize/position the two panes and splitbar
            splitbar.css(opts.set, np+"px");
            paneA.css(opts.adjust, np-paneA._padAdjust+"px");
            paneB.css(opts.set, np+splitbar._adjust+"px")
                .css(opts.adjust, group._adjust-splitbar._adjust-paneB._padAdjust-np+"px");

            setCookie("splitterpos_"+opts.type, np-paneA._padAdjust+"px");
			

            // IE fires resize for us; all others pay cash
            if ( !jQuery.browser.msie ) {
                paneA.trigger("resize");
                paneB.trigger("resize");
            }
        }
        function cssCache(jq, n, pf, m1, m2) {
            // IE backCompat mode thinks width/height includes border and padding
            jq[n] = jQuery.boxModel? (parseInt(jq.css(pf+m1))||0) + (parseInt(jq.css(pf+m2))||0) : 0;
        }
        function optCache(jq, pane) {
            // Opera returns -1px for min/max dimensions when they're not there!
            jq._min = Math.max(0, opts["min"+pane] || parseInt(jq.css("min-"+opts.adjust)) || 0);
            jq._max = Math.max(0, opts["max"+pane] || parseInt(jq.css("max-"+opts.adjust)) || 0);
        }

        // Create jQuery object closures for splitter group and both panes
        var group = jQuery(this).css({position: "relative"});
        var divs = jQuery(">div", group).css({
            position: "absolute",           // positioned inside splitter container
            margin: "0",                    // remove any stylesheet margin or ...
            border: "0",                    // ... border added for non-script situations
            "-moz-user-focus": "ignore"     // disable focusability in Firefox
        });
        var paneA = jQuery(divs[0]);        // left  or top
        var paneB = jQuery(divs[1]);        // right or bottom

        // Focuser element, provides keyboard support
        var focuser = jQuery('<a href="javascript:void(0)"></a>')
            .bind("focus", startSplit).bind("keydown", doSplitKey).bind("blur", endSplit)
            .attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex});

        // Splitbar element, displays actual splitter bar
        // The select-related properties prevent unintended text highlighting
        var splitbar = jQuery('<div></div>')
            .insertAfter(paneA).append(focuser)
            .attr({"class": opts.splitbarClass, unselectable: "on"})
            .css({position: "absolute", "-khtml-user-select": "none",
                "-moz-user-select": "none", "user-select": "none"})
            .bind("mousedown", startSplit);
        if ( /^(auto|default)$/.test(splitbar.css("cursor") || "auto") )
            splitbar.css("cursor", opts.cursor);

        // Cache several dimensions for speed--assume these don't change
        splitbar._adjust = splitbar[0][opts.offsetAdjust];
        cssCache(group, "_borderAdjust", "border", opts.adjSide1+"Width", opts.adjSide2+"Width");
        cssCache(group, "_borderFixed",  "border", opts.fixSide1+"Width", opts.fixSide2+"Width");
        cssCache(paneA, "_padAdjust", "padding", opts.adjSide1, opts.adjSide2);
        cssCache(paneA, "_padFixed",  "padding", opts.fixSide1, opts.fixSide2);
        cssCache(paneB, "_padAdjust", "padding", opts.adjSide1, opts.adjSide2);
        cssCache(paneB, "_padFixed",  "padding", opts.fixSide1, opts.fixSide2);
        optCache(paneA, 'A');
        optCache(paneB, 'B');

        // Initial splitbar position as measured from left edge of splitter
        paneA._init = (opts.initA==true? parseInt(jQuery.curCSS(paneA[0],opts.adjust)) : opts.initA) || 0;
        paneB._init = (opts.initB==true? parseInt(jQuery.curCSS(paneB[0],opts.adjust)) : opts.initB) || 0;
        if ( paneB._init )
            paneB._init = group[0][opts.offsetAdjust] - group._borderAdjust - paneB._init - splitbar._adjust;

        // Set up resize event handler and trigger immediately to set initial position
        group.bind("resize", function(e,size){
            // Determine new width/height of splitter container
            group._fixed  = group[0][opts.offsetFixed]  - group._borderFixed;
            group._adjust = group[0][opts.offsetAdjust] - group._borderAdjust;
            // Bail if splitter isn't visible or content isn't there yet
            if ( group._fixed <= 0 || group._adjust <= 0 ) return;
            // Set the fixed dimension (e.g., height on a vertical splitter)
            paneA.css(opts.fixed, group._fixed-paneA._padFixed+"px");
            paneB.css(opts.fixed, group._fixed-paneB._padFixed+"px");
            splitbar.css(opts.fixed, group._fixed+"px");
            // Re-divvy the adjustable dimension; maintain size of the preferred pane
            moveSplitter(size || (!opts.initB? paneA[0][opts.offsetAdjust] :
                group._adjust-paneB[0][opts.offsetAdjust]-splitbar._adjust));
        }).trigger("resize" , [paneA._init || paneB._init || 
            Math.round((group[0][opts.offsetAdjust] - group._borderAdjust - splitbar._adjust)/2)]);
    });
};
