var MOVE_DURATION = 0.2;
var MOVE_DELAY = 0.25;

var Clicker = Class.create();
Clicker.prototype = {

	initialize: function(element) {

		this.element = $(element);
		this.options = Object.extend({
			padding: 0,
			bottomOffset: 0,
			topOffset: 0
		}, arguments[1] || {});

		this.setup();

		if(this.maxBottom - this.maxTop > this.element.getHeight()) {

			this.element.style.position = 'absolute';
			this.moveElement();

			Event.observe(window, 'scroll', this.moveElement.bindAsEventListener(this));
			Event.observe(window, 'resize', this.windowResized.bindAsEventListener(this));
		}
	},

	setup: function() {

		this.maxTop = this.getMaximumTopValue();
		this.maxBottom = this.getMaximumBottomValue();
		
		this.originalDimensions = this.getDocumentDimensions();

		/* place the element as a child of the <body> so we can position it
		from the top left of the document */
		this.element.remove();

		$('container').appendChild(this.element);

		this.elementOriginalLeftPosition = Position.positionedOffset(this.element)[0] - Element.getStyle(this.element, 'marginLeft').replace('px', '');
	},

	moveElement: function() {

		var amount = this.getMoveAmount();

		// Drop all the previous effects from the queue, otherwise we'll get a
		// nasty stuttering effect
		var queue = Effect.Queues.get('clickerscope');
		queue.each(function(e) { e.cancel() });

		if(!this.alreadyMoved) {

			this.element.style.top = amount + 'px';
			this.element.style.left = this.elementOriginalLeftPosition + 'px';

			this.alreadyMoved = true;
		} else {

			// Now put the new effect to the front of the empty queue
			new Effect.MoveBy(this.element, amount, this.elementOriginalLeftPosition, {
							mode: 'absolute',
							duration: MOVE_DURATION,
							transition: Effect.Transitions.sinoidal,
							delay: MOVE_DELAY,
							queue: {position: 'front', scope: 'clickerscope'}
			});
		}
	},	
	
	getMoveAmount: function() {
		
		var amount = this.getDocumentDimensions()[1] + this.getPageOffset()[1] - this.options.padding - this.element.getHeight();
	
		if(this.options.snap_to == 'top') {
		
			amount = this.getPageOffset()[1] + this.options.padding;
		}

		if((amount + this.element.getHeight()) > (this.maxBottom - this.options.padding)) {

			amount = this.maxBottom - this.element.getHeight();
		} else if(amount < (this.maxTop + this.options.padding)) {

			amount = this.maxTop + this.options.padding;
		}
		
		return amount - 10;	
	},

	getMaximumTopValue: function() {

		if(typeof(this.options.topelement) == 'undefined') {

			return 0;
		}

		var elementTop = Position.cumulativeOffset($(this.options.topelement))[1];
		var elementHeight = Element.getHeight($(this.options.topelement));

		return elementTop + elementHeight + this.options.topOffset;
	},

	getMaximumBottomValue: function() {

		if(typeof(this.options.bottomelement) == 'undefined') {

			return 0;
		}

		var elementTop = Position.cumulativeOffset($(this.options.bottomelement))[1];
		var elementHeight = Element.getHeight($(this.options.bottomelement));

		return elementTop + elementHeight + this.options.bottomOffset;
	},

	getDocumentDimensions: function() {

		var width = 0, height = 0;

		if(typeof(window.innerWidth) == 'number') {

			width = window.innerWidth;
			height = window.innerHeight;
		} else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {

			width = document.documentElement.clientWidth;
			height = document.documentElement.clientHeight;
		} else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {

			width = document.body.clientWidth;
			height = document.body.clientHeight;
		}

		return [width, height];
	},

	getPageOffset: function() {

		var scrOfX = 0, scrOfY = 0;

		if(typeof(window.pageYOffset) == 'number') {

			scrOfY = window.pageYOffset;
			scrOfX = window.pageXOffset;
		} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {

			scrOfY = document.body.scrollTop;
			scrOfX = document.body.scrollLeft;
		} else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {

			scrOfY = document.documentElement.scrollTop;
			scrOfX = document.documentElement.scrollLeft;
		}

		return [scrOfX, scrOfY];
	},

	windowResized: function() {

		// Function that is called when the window is resized. Can also be called
		// externally when an external script causes the document dimensions to
		// change.

		this.maxTop = this.getMaximumTopValue();
		this.maxBottom = this.getMaximumBottomValue();

		this.originalDimensions = this.getDocumentDimensions();

		this.moveElement();
	}
}