var ScrollWithWindowManager = Class.create({
	pe: null,
	initialize: function(elements, options){
		this.options = Object.extend({
			interval: 0.1
		}, options);
		this.elements = [];
		if( elements && elements.length ){
			elements.each(function(o){
				var temp;
				if( Object.isElement(o) || Object.isString(o)){
					temp = new ScrollWithWindowElement($(o));
				}else{
					if( o.element ){
						temp = new ScrollWithWindowElement($(o.element), o.options);
					}
				}
				this.elements.push(temp);
			}, this);
		}
		this.window_observer = this.startInterval.bind(this);
		//Event.observe(window, 'scroll', this.window_observer);
		if( this.elements.length && (window.scrollX || window.scrollY) ){
			this.startInterval();
		}
	},
	addElements: function(elms, options){
		if( !Object.isArray(elms) ){
			elms = [elms];
		}
		elms.each(function(e){
			this.elements.push(new ScrollWithWindowElement($(e), options));
		}, this);
		this.startInterval();
	},
	removeElement: function(elm){
		if( Object.isNumber(elm)){
			this.elements.splice(elm, 1);
		}else{
			this.elements = this.elements.without(elm);
		}
	},
	startInterval: function(){
		if (!this.pe) {
			this.pe = new PeriodicalExecuter(this.move.bind(this), this.options.interval);
			Event.stopObserving(window, 'scroll', this.window_observer);
		}
	},
	stopInterval: function(){
		if( this.pe ){
			this.pe.stop();
			this.pe = null;
			Event.observe(window, 'scroll', this.window_observer);
		}
	},
	getWindowScroll: function(){
		var scroll = [0, 0]
		if (!Object.isUndefined(window.scrollY)) {
			scroll = [window.scrollX, window.scrollY];
		}
		else 
			if (!Object.isUndefined(document.documentElement.scrollTop)) {
				scroll = [document.documentElement.scrollLeft, document.documentElement.scrollTop];
			}
			else 
				if (!Object.isUndefined(document.scrollTop)) {
					scroll = [document.scrollLeft, document.scrollTop];
				}
		return scroll;
	},
	getWindowDims: function(){
		if( !Object.isUndefined(window.innerHeight) ){
			return [window.innerWidth, window.innerHeight];
		}else if(!Object.isUndefined(document.documentElement.clientHeight)){
			return [document.documentElement.clientWidth, document.documentElement.clientHeight];
		}else if(!Object.isUndefined(document.body.clientHeight)){
			return [document.body.clientWidth, document.body.clientHeight];
		}
		return [0, 0];
	},
	move: function(){
		/* move should compute changes for all elements then apply them */
		var l = this.elements.length;
		var change_x, change_y, new_x, new_y;
		var window_dims = this.getWindowDims();
		var scroll = this.getWindowScroll();
		var limit = [window_dims[0] + scroll[0], window_dims[1] + scroll[1]];
		for(var i=0; i<l; i++){
			var item = this.elements[i];
			if( !item ){
				continue;
			}
			var elm = item.elm;
			var dims = item.dims;
			var this_limit = [limit[0] - item.offsets[0], limit[1] - item.offsets[1]];
			if( item.parent_dims ){
				this_limit[0] = Math.min(this_limit[0], item.parent_dims[0]);
				this_limit[1] = Math.min(this_limit[1], item.parent_dims[1]);
			}
			this_limit[0] -= dims.width;
			this_limit[1] -= dims.height;
			
			if( item.options.vertical ){
				var y = parseFloat(elm.getStyle('top') || 0.0);
				var window_height_factor = 0;
				var item_height_factor = 0;
				switch( item.options.align[1] ){
					case 'bottom':
						window_height_factor = 1;
						item_height_factor = 1;
						break;
					case 'middle':
						window_height_factor = 0.5;
						item_height_factor = 0.5;
						break;
				}
				var pos_y = (item.original_pos[1] + scroll[1] + (window_height_factor * window_dims[1]) - (item_height_factor * dims.height) - item.offsets[1]);
				var change_y = pos_y - y;
				if (item.options.smooth) 
					change_y *= item.options.delta[1];
				if (change_y != 0) {
					new_y = y + change_y;
					if (new_y >= this_limit[1]) {
						new_y = this_limit[1];
					}
					if (new_y < item.original_pos[1]) {
						new_y = item.original_pos[1];
					}
					elm.setStyle({
						'top': new_y + 'px'
					});
				}
			}
			if( item.options.horizontal ){
				var x = parseFloat(elm.getStyle('left') || 0.0);
				var window_width_factor = 0;
				var item_width_factor = 0;
				switch( item.options.align[0] ){
					case 'right':
						window_width_factor = 1;
						item_width_factor = 1;
						break;
					case 'middle':
						window_width_factor = 0.5;
						item_width_factor = 0.5;
						break;
				}
				var pos_x = (item.original_pos[0] + scroll[0] + (window_width_factor * window_dims[0]) - (item_width_factor * dims.width) - item.offsets[0]);
				var change_x = pos_x - x;
				if (item.options.smooth) 
					change_x *= item.options.delta[0];
				if (change_x != 0) {
					new_x = x + change_x;
					if (new_x >= this_limit[0]) {
						new_x = this_limit[0];
					}
					if (new_x < item.original_pos[0]) {
						new_x = item.original_pos[0];
					}
					elm.setStyle({
						'left': new_x + 'px'
					});
				}
			}
		}
	}
});

var ScrollWithWindowElement = Class.create({
	initialize: function(elm){
		this.elm = $(elm);
		this.pe = null;
		if(!this.elm){
			return null;
		}
		this.options = Object.extend({
			horizontal: false,
			vertical: true,
			offsets: [0, 0],
			delta: [0.5, 0.5],
			align: ['left', 'middle'],
			smooth: true,
			mode: 'relative',
			contain_to_parent: true,
			parent_dims: null
		}, arguments[1] || {});
		if( this.options.mode == 'absolute'){
			this.elm.absolutize();
		}else{
			this.elm.setStyle({position: 'relative'});
		}
		this.elm.setStyle({'height': ''});
		this.original_pos = [parseFloat(this.elm.getStyle('left') || 0.0), parseFloat(this.elm.getStyle('top') || 0.0)];
		this.offset_parent = this.elm.getOffsetParent();
		this.dims = this.elm.getDimensions();
		if( this.offset_parent.tagName != 'BODY'){
			this.offsets = this.offset_parent.cumulativeOffset();
			if( this.options.contain_to_parent ){
				var dims = this.offset_parent.getDimensions();
				this.parent_dims = [dims.width, dims.height];
			}
		}
	}
});
