var ScrollWithWindowManager = Class.create({
	pe: null,
	initialize: function(elements, options){
		this.options = Object.extend({
			interval: 0.15
		}, 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 page_dims = $$('html')[0];
		var window_dims = this.getWindowDims();
		var scroll = this.getWindowScroll();
		page_dims = {width: page_dims.scrollWidth, height: page_dims.scrollHeight};
		for(var i=0; i<l; i++){
			var limit = [page_dims.width, page_dims.height];
			var item = this.elements[i];
			var elm = item.elm;
			var pos = {};
			var dims = elm.getDimensions();
			if( item.options.align[1] == 'bottom'){
				limit[1] = window_dims[1] + scroll[1];
			}
			if( item.options.align[0] == 'right'){
				limit[0] = window_dims[0] + scroll[0];
			}
			if( item.options.vertical ){
				var y = parseFloat(elm.getStyle('top') || 0.0);
				change_y = (item.original_pos[1] + scroll[1] - y);
				if( item.options.smooth ) change_y *= item.options.delta[1];
				if (change_y != 0) {
					new_y = y + change_y;
					if (new_y + dims.height >= limit[1]) {
						new_y = limit[1] - dims.height;
					}
					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);
				change_x = (item.original_pos[0] + scroll[0] - x);
				if( item.options.smooth ) change_x *= item.options.delta[0];
				new_x = x + change_x;
				if (change_x != 0) {
					if (new_x + dims[0] >= limit[0]) {
						new_x = limit[0] - dims[0];
					}
					if (new_x < this.original_pos[0]) {
						new_x = this.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.45, 0.45],
			align: ['left', 'bottom'],
			smooth: true,
			mode: 'relative'
		}, 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)];
	}
});
