/*
 * boxAreaSelect 
 * 
 * Copyright (c) 2009 German Gonzo (letmego.com)
 * 
 * based on imgAreaSelect jQuery plugin version 0.9
 *
 */

(function($) {

var abs = Math.abs,
    max = Math.max,
    min = Math.min,
    round = Math.round;

function div() {
    return $('<div/>');
}

$.boxAreaSelect = function ($container, options) {
    var
        $container = $($container),
        $border = div().add(div()).add(div()).add(div()),
        $outer = div().add(div()).add(div()).add(div()),
        $handles = $([]),
        left, top,
        areaOfs,
        parOfs,
        zIndex = 0,
        position = 'absolute',        
        selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 };

    function viewX(x) {
        return x + areaOfs.left;
    }

    function viewY(y) {
        return y + areaOfs.top;
    }

    function getSelection(noScale) {
    	return selection;
    }

    function setSelection(x1, y1, x2, y2, noScale) {
    	selection = {
            x1: x1,
            y1: y1,
            x2: x2,
            y2: y2
        };
        selection.width = (x2 = viewX(selection.x2)) - (x1 = viewX(selection.x1));
        selection.height = (y2 = viewX(selection.y2)) - (y1 = viewX(selection.y1));
    }

    function adjust() {
        areaOfs = { left: round($container.offset().left), top: round($container.offset().top) };
        if ($().jquery == '1.3.2' && $.browser.safari && position == 'fixed') {
            areaOfs.top += max(document.documentElement.scrollTop, $('body').scrollTop());
            areaOfs.left += max(document.documentElement.scrollLeft, $('body').scrollLeft());
        }
        parOfs = $.inArray($container.css('position'), ['absolute', 'relative']) + 1 ?
            { left: round($container.offset().left) - $container.scrollLeft(),
                top: round($container.offset().top) - $container.scrollTop() } :
            position == 'fixed' ?
                { left: $(document).scrollLeft(), top: $(document).scrollTop() } :
                { left: 0, top: 0 };
        left = viewX(0);
        top = viewY(0);
    }

    function update(resetKeyPress) {
    	left = 0;
        top = 0;
        var borderWidth = $($border[1]).css("height");
    	
        x1 = selection.x1 > 0 ?selection.x1:0;
        x2 = selection.x2  < $container.width() ? selection.x2 :$container.width();
        y1 = selection.y1 > 0 ?selection.y1:0;
        y2 = selection.y2 < $container.height() ? selection.y2 :$container.height();
        w = x2-x1;
        h = y2-y1;
        
        $($outer[0]).css({ left: left, top: top,
            width: x1, height: $container.height()});
        
        $($outer[1]).css({ left: left + x1, top: top,
            width: w, height: y1});
        
        $($outer[2]).css({ left: left + x2, top: top,
            width: $container.width() - x2, height: $container.height()});
        
        $($outer[3]).css({ left: left + x1, top: top + y2,
            width: w, height: $container.height() - y2});
	
        hw = $handles.outerWidth();
        hh = $handles.outerHeight();        
        
        $($handles).show();
        if(options.hideHandlersOnBorder){
	        if (x1 == 0 || x2 == $container.width() || y1 == 0 || y2 == $container.height()) {
	        	 $($handles).hide();
	        }
        }
        
        switch ($handles.length) {
        case 8:
        	borderWidth = parseInt(borderWidth.replace("px", ""));
        	$($handles[4]).css({ left: parseInt((x1+x2)/2),top: y1});
        	$($handles[5]).css({ left: parseInt((x1+x2)/2),top: y2-hh+borderWidth});
            $($handles[6]).css({ left: x1,top: parseInt((y1+y2)/2)});
            $($handles[7]).css({ left: x2-hw,top: parseInt((y1+y2)/2)});
            $($handles).slice(4,6).draggable('option', 'axis', 'y');
            $($handles).slice(6,8).draggable('option', 'axis', 'x');
       case 4:
    	   $($handles[0]).css({ left: x1,top: y1});
           $($handles[1]).css({ left: x2-hw,top: y1});
           $($handles[2]).css({ left: x1,top: y2-hh+borderWidth});
           $($handles[3]).css({ left: x2-hw,top: y2-hh+borderWidth});
        }
        $($border).slice(0,2).css({left:x1,top:y1,width:w});
        $($border[1]).css({top:y2-1});
        $($border).slice(2,4).css({left:x1,top:y1+parseInt(borderWidth),height:h-1-parseInt(borderWidth)});
        $($border[3]).css({left:x2-parseInt(borderWidth),top:y1+parseInt(borderWidth)});
        
    }

    function setOptions(newOptions) {
        options
    	options = $.extend(options, newOptions);

        if (!isNaN(options.zIndex))
            zIndex = options.zIndex;        
        if (newOptions.handles != null) {
        	$handles.remove();
            $handles = $([]);

            i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0;
            
            while (i--)
                $handles = $handles.add(div());

            $handles.addClass('boxareaselect' + '-handle').css({
                position: 'absolute',
                fontSize: 0,
                zIndex: zIndex + 1 || 1
            });

            if (!parseInt($handles.css('width')))
                $handles.width(7).height(7);
            //cursors
            $($handles[0]).css({cursor:'nw-resize'});
            $($handles[1]).css({cursor:'ne-resize'});
            $($handles[2]).css({cursor:'sw-resize'});
            $($handles[3]).css({cursor:'se-resize'});
            if ($handles.length==8) {
            	$($handles[4]).css({cursor:'n-resize'});
                $($handles[5]).css({cursor:'s-resize'});
                $($handles[6]).css({cursor:'w-resize'});
                $($handles[7]).css({cursor:'e-resize'});
            }

        }
        adjust();
        
        //$($container).append($outer);
        //$($outer).css({position:'absolute'});
        //$($outer).addClass("boxareaselect-outer");
        
        $($container).append($border);
        $($border).css({position:'absolute'});
        for (i = 0; i++ < 4;)
            $($border[i-1]).addClass('boxareaselect' + '-border' + i);
        
        $($container).append($handles);
        $($handles).draggable({
    		drag:handleDrag,
    		stop: handleStop,
    		containment: 'parent'
        });
        
        if ($.browser.msie) {
            //if (o = $outer.css('filter').match(/opacity=([0-9]+)/))
            //    $outer.css('opacity', o[1]/100);
            if (o = $border.css('filter').match(/opacity=([0-9]+)/))
                $border.css('opacity', o[1]/100);
        }
       
    }
    
    function handleDrag(event,ui) {
    	s = selection;
        hw = $(this).outerWidth();
        hh = $(this).outerHeight();
    	x = ui.position.left;
    	y = ui.position.top;
 
    	if (ui.helper.draggable('option', 'axis')!='y') {
    		if (abs(selection.x1-x) < abs(selection.x2-x)) {
        		s.x1 = x;
        	} else {
        		s.x2 = x+hh;
        	}
    	}
    	if (ui.helper.draggable('option', 'axis')!='x') {
	    	if (abs(selection.y1-y) < abs(selection.y2-y)) {
	    		s.y1 = y;
	    	} else {
	    		s.y2 = y+hh;
	    	}
    	}
    	setSelection(s.x1,s.y1,s.x2,s.y2);
    	update();
    }
    
    function handleStop(event,ui) {
    	options.onSelectEnd($container,selection);
    } 
    
    this.getOptions = function () { return options; };

    this.setOptions = setOptions;

    this.getSelection = getSelection;

    this.setSelection = setSelection;

    this.update = function doUpdate(resetKeyPress) {
    	adjust();
    	update(resetKeyPress);
    };
    
    //sets default options
    setOptions(options = $.extend({
        classPrefix: 'boxareaselect',
        onInit: function () {},
        onSelectStart: function () {},
        onSelectChange: function () {},
        onSelectEnd: function () {}
    }, options));

};

$.fn.boxAreaSelect = function (options) {
    options = options || {};
    var selector = null;
    this.each(function () {
        if ($(this).data('boxAreaSelect'))
        	selector = $(this).data('boxAreaSelect');
        else {
            $(this).data('boxAreaSelect', new $.boxAreaSelect(this, options));
            selector = $(this).data('boxAreaSelect');
        }
        selector.setOptions(options);
    });
    return selector;
};
})(jQuery);
