var MouseWheelListener = Class.create();
MouseWheelListener.prototype = {
	
	initialize: function(callback, element) {
		this.callback = callback;
		this.element = element;	
	}
	
	,invoke: function(delta) {
		
		if (! this.element) {
			this.callback(delta);
		} else {
			var dim = Dimension.createFromElement(this.element);
			var mousePoint = MousePosition.getPosition(this.element);
			
			if (dim.containsPoint(mousePoint))
				this.callback(delta);
		}
	}
};

var MouseWheel = Class.create();

MouseWheel.isInitialized = false;

MouseWheel.init = function () 
{
	

}

MouseWheel.fireEvent = function(event) {
	var delta = 0;
	
	// IE and Opera
	if (event.wheelDelta) {
		delta = event.wheelDelta/120;
		
		// In Opera 9, delta differs in sign as compared to IE.
		if (window.opera)
			delta = -delta;
			
	// Mozilla
	} else if (event.detail) {
		
		/** In Mozilla, sign of delta is different than in IE.
		  * Also, delta is multiple of 3.
		  */
		delta = -event.detail/3;
	}
	
    /** If delta is nonzero, handle it.
     * Basically, delta is now positive if wheel was scrolled up,
     * and negative, if wheel was scrolled down.
     */
    if (delta)
            MouseWheel.notifyListeners(delta);
            
    /** Prevent default actions caused by mouse wheel.
     * That might be ugly, but we handle scrolls somehow
     * anyway, so don't bother here..
     */
	if (event.preventDefault)
		event.preventDefault();
            
	event.returnValue = false;
}

MouseWheel.listeners = $A(new Array());

MouseWheel.addListener = function(callback, element) {
	
	var listener = new MouseWheelListener(callback, element);
	
	MouseWheel.listeners.push(
		listener	
	);	
	
	if (! MouseWheel.isInitialized) {
		
		// For firefox
		if (window.addEventListener)
	        window.addEventListener('DOMMouseScroll', MouseWheel.fireEvent, false);
	    else
	    	Event.observe(document, 'mousewheel', MouseWheel.fireEvent);
		    
	    MouseWheel.isInitialized = true;
	}
	
	return listener;
}

MouseWheel.removeListener = function(listener) {
	MouseWheel.listeners.remove(listener);
	
	if (! MouseWheel.listeners.length && MouseWheel.isInitialized) {
		// For firefox
		if (window.addEventListener)
	        window.removeEventListener('DOMMouseScroll', MouseWheel.fireEvent, false);
	    else
	    	Event.stopObserving(document, 'mousewheel', MouseWheel.fireEvent); 
	    	
	    MouseWheel.isInitialized = false;
	}
}

MouseWheel.notifyListeners = function(delta) {
	MouseWheel.listeners.each(
		function(listener) {
			listener.invoke(delta);
		}
	);
}

var MousePosition = Class.create();

MousePosition.init = function() 
{
	Event.observe(window, 'mousemove', MousePosition.fireEvent);
	Event.observe(document, 'mousemove', MousePosition.fireEvent);
	Event.observe(window, 'click', MousePosition.fireEvent);
}

MousePosition.position = new Point(0, 0);

MousePosition.fireEvent = function(event) {
	 if (document.layers) {
        xMousePos = event.pageX;
        yMousePos = event.pageY;
    } else if (document.all) {
        // When the page scrolls in IE, the event's mouse position 
        // reflects the position from the top/left of the screen the 
        // user is looking at. scrollLeft/Top is the amount the user
        // has scrolled into the page. clientWidth/Height is the height/
        // width of the current page the user is looking at. So, to be
        // consistent with Netscape (above), add the scroll offsets to
        // both so we end up with an absolute value on the page, no 
        // matter if the user has scrolled or not.
        xMousePos = event.clientX+document.body.scrollLeft;
        yMousePos = event.clientY+document.body.scrollTop;
    } else if (document.getElementById) {
        // Netscape 6 behaves the same as Netscape 4 in this regard 
        xMousePos = event.pageX;
        yMousePos = event.pageY;
    }
    
	MousePosition.position = new Point(xMousePos, yMousePos);
}


MousePosition.getPosition = function(relativeTo) {
	if (! relativeTo)
		return MousePosition.position;
		
	var p = Position.cumulativeOffset(relativeTo);
	
	return new Point(
		MousePosition.position.x - p[0]
		,MousePosition.position.y - p[1]
	);
}