Ext.namespace('Ext.ux.grid');

Ext.ux.grid.DragSelector = function(cfg){
    
	cfg = cfg || {};
    var rs, rsOrig, objectsSelected = [];
	var grid, view, regions, proxy, tracker, selModel, scroller;
    var bodyRegion, mainRegion, dragRegion = new Ext.lib.Region(0,0,0,0);
    var dragSafe = cfg.dragSafe === true;
	var ctrlState, shiftState, isDragging = false;
	var scrollTopStart, scrollTop = 0;
	
    this.init = function(cmp){
		grid = cmp;
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
		view = grid.getView();
		selModel = grid.getSelectionModel();
		grid.on('render', onRender);
		grid.on('bodyscroll', syncScroll);
    };
	
	function syncScroll(e) {
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
		// sync regions
		syncRowRegions();
		
		// get new scroll position
		var top = scroller.getScroll().top;
		scrollTop = top - scrollTopStart;
		if (isDragging) {
			onDrag(e, true);
		}
	}

    function fillAllRegions(){
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
        mainRegion = scroller.getRegion();
        bodyRegion = scroller.getRegion();
		objectsSelected = [];
		var itemSelector = 'div.x-grid3-row';
		var mainElement = view.el.dom;
		Ext.each(Ext.query(itemSelector, mainElement), function(el) {
			objectsSelected[objectsSelected.length] = selModel.isSelected(objectsSelected.length);
		});
		fillRowRegions();
        syncScroll();
    }
	
	function fillRowRegions() {
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
		rs = [];
		rsOrig = [];
		var itemSelector = 'div.x-grid3-row';
		var mainElement = view.el.dom;
		Ext.each(Ext.query(itemSelector, mainElement), function(el) {
			rsOrig[rsOrig.length] = Ext.get(el).getRegion();
			rs[rs.length] = Ext.get(el).getRegion();
		});
	}
	
	function syncRowRegions() {
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
        if (scrollTop !== 0) {
			fillRowRegions();
		}
		/*if (rs.length && rsOrig.length && rs.length === rsOrig.length) {
			for(var i = 0; i < rs.length; i++){
				//console.log('substract ' + scrollTop);
				rs[i].top = rsOrig[i].top - scrollTop;
				rs[i].bottom = rsOrig[i].bottom - scrollTop;
			}
		}*/
	}
	
    function cancelClick(e){
        ctrlState = e.ctrlKey;
        shiftState = e.shiftKey;
        grid.stopEditing();
        var target = e.getTarget();        
        if (!ctrlState && !shiftState && (target.className === 'x-grid3-scroller' || target.className === 'x-grid3-body' )) {
            selModel.clearSelections();
        }
        return true;
	}

    function onBeforeStart(e){
        var target = e.getTarget();
		if (!target || (target.className !== 'x-grid3-scroller' && target.className !== 'x-grid3-body')) {
			return false;	
		}
		if (grid.getSelectionModel().singleSelect === true) {
			return false;	
		}
		// return false if is a right mouseclick
		if (e.button === 2) {
			return false;	
		}
		// return false if any grid editor is active
		if (grid.activeEditor && grid.activeEditor !== null) {
			return false;	
		}
		
		// return false if the header was clicked
		if (e.getPageY() <= view.el.getY() + 25) {
			return false;
		}
        
		// return false if the header was clicked
		if (grid.bbar && e.getPageY() > view.el.getY() + view.el.dom.clientHeight) {
			return false;
		}
        
		// scrollbar fix from digitalbucket.net :)
		if (e.getPageX() > view.el.getX() + view.el.dom.clientWidth - 20) {
			return false;
		}
		
		// call cancelClick
		cancelClick(e);
		// return
		return !dragSafe || e.target == view.el.dom;
    }

    function onStart(e){
		if (grid.getSelectionModel().singleSelect === true) {
			return false;	
		}
		scrollTopStart = scroller.getScroll().top;
		fillAllRegions();
        // init drag proxy
		if(!proxy){
            proxy = view.el.createChild({cls:'x-view-selector'});
        } else {
            proxy.setDisplayed('block');
        }
		isDragging = true;
    }

    function onDrag(e, scaleSelector){
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
		// get drag start position
		var startXY = tracker.startXY;
        // current position
		var xy = tracker.getXY();
		// get xy, width and heigth of the drag proxy
		
		if (xy[0] < startXY[0] && !scaleSelector) {
			xy[0] += 2;	
		}
        
		if (scrollTop >= 0) {
			
			if ((startXY[1]- scrollTop) <= xy[1]) {
				// feld oben
				var y = startXY[1] - scrollTop;
				var h = Math.abs(y - xy[1]);
				
			} else {
				var y = xy[1];	
				var h = Math.abs(startXY[1] - xy[1]) - scrollTop;
			}
			
			var x = Math.min(startXY[0], xy[0]);
			var w = Math.abs(startXY[0] - xy[0]);
			
			
			
			bodyRegion.top -= scrollTop;
			
			
		} else {
			
			
			if ((startXY[1] - scrollTop)  < xy[1]) {
				
				// feld unten
				var y = startXY[1] - scrollTop;
				var h = Math.abs(y - xy[1]);
			
			} else {

				// feld oben
				var y = xy[1]; // richtig in jedem fall
				var h = Math.abs((startXY[1] - scrollTop) - xy[1]) ;
			
			}
			
			var x = Math.min(startXY[0], xy[0]);
			var w = Math.abs(startXY[0] - xy[0]);
			
			bodyRegion.bottom -= scrollTop;
		}
		// set this values
		dragRegion.left = x;
		dragRegion.top = y ;
		dragRegion.right = x+w;
        dragRegion.bottom = y+h;
		
        dragRegion.constrainTo(bodyRegion);
        proxy.setRegion(dragRegion);

        for(var i = 0, len = rs.length; i < len; i++){
            var r = rs[i], sel = dragRegion.intersect(r);
            var selected = selModel.isSelected(i);
            var selectedBefore = objectsSelected[i];
			
			if (ctrlState) {
				if (selectedBefore) {
					if(sel && selected){
						selModel.deselectRow(i);
					} else if(!sel && !selected){
						selModel.selectRow(i, true);
					}
				} else {
					if(sel && !selected){
						selModel.selectRow(i, true);
					} else if(!sel && selected){
						selModel.deselectRow(i);
					}
				}
			} else {
				if(sel && !selected){
					selModel.selectRow(i, true);
				} else if(!sel && selected){
					selModel.deselectRow(i);
				}
			}
			
        }
		
		if (xy[1] + 10 >= mainRegion.bottom) {
			if (Ext.isIE) {
				setTimeout(function() {
					scroller.scrollTo('top', scroller.getScroll().top + 40);
				}, 100);
			} else {
				scroller.scrollTo('top', scroller.getScroll().top + 40);
			}
		}
		
		if (xy[1] - 10 <= mainRegion.top) {
			if (Ext.isIE) {
				setTimeout(function() {
					scroller.scrollTo('top', scroller.getScroll().top - 40);
				}, 100);
			} else {
				scroller.scrollTo('top', scroller.getScroll().top - 40);
			}
		}
    }

    function onEnd(e){
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
		isDragging = false;
        if(proxy){
            proxy.setDisplayed(false);
        }
    }
	
    function onRender(view){
		if (grid.getSelectionModel().singleSelect === true) {
			return;	
		}
        tracker = new Ext.dd.DragTracker({
            onBeforeStart: onBeforeStart,
            onStart: onStart,
            onDrag: onDrag,
            onEnd: onEnd
        });
        tracker.initEl(view.el);
		scroller = Ext.get(grid.getView().scroller);
    }
	
};
