
function Timer(intervalValue){
	this.intervalValue = intervalValue ? intervalValue : 500;
	this.interval = null;
	this.events = [];
	this.listeners = [];
	this.onstart = new DOMEvent();
	this.onstop = new DOMEvent();
	this.isTicking = false;
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
Timer.prototype.start = function(){
	if(this.isTicking){
		return;
	}
	this.calls = 0;
	this.timeElapsed = 0;
	this.interval = setInterval(
		this.intervalFunction.bind(this),
		this.intervalValue
	);
	this.isTicking = true;
	this.onstart.fire();
};
Timer.prototype.intervalFunction = function(){
	this.calls ++;
	this.timeElapsed += this.intervalValue;
	this.events.each(function(ev, index){
		if(this.calls % ev.freq == 0){
			var ret = ev.func.apply(ev.oThis, ev.args);
			if(typeof ret != 'undefined' && ret !== false){
				this.listeners.each(function(lnr, index){
					if(lnr.name == ev.name){
						lnr.func.apply(lnr.oThis, [ret]);
					}
				})
			}
		}
	}.bind(this))
};
Timer.prototype.registerEvent = function(obj){
	if(!obj.freq){
		obj.freq = 1;
	}
	this.events.push(obj);
};
Timer.prototype.removeEvent = function(name){
	this.events.each(function(ev, ind){
		if(ev.name == name){
			this.events.remove(ind);
			throw $break;
		}
	});
	this.listeners.each(function(lnr, ind){
		if(lnr.name == name){
			this.listeners.remove(ind);
		}
	})
};
Timer.prototype.registerEventListener = function(obj){
	this.listeners.push(obj);
};
Timer.prototype.clear = function(){
	clearInterval(this.interval);
	this.isTicking = false;
	this.onstop.fire();
};
Timer.prototype.stop = Timer.prototype.clear; 
Timer.prototype.toggle = function(){
	if(this.isTicking){
		this.clear();
	}else{
		this.start();
	}
};
Timer.prototype.restart = function(){
	this.clear();
	this.start();
};
Timer.prototype.set_timeout = function(name, func, time){
	if(!this.timeouts){
		this.make_timeouts();
	}
	if(this.has_timeout(name)){
		return false;
	}
	this.timeouts.push({
		name: name,
		func: func,
		count: Math.round(time / this.intervalValue)
	});
};
Timer.prototype.clear_timeout = function(name){
	if(!this.timeouts){
		return false;
	}
	var ind = this.timeouts.detect_i(detectFuncs.name.bind(name));
	if(undefined(ind)){
		return false;
	}
	this.timeouts.remove(ind);
};
Timer.prototype.clear_all_timeouts = function(){
	if(this.timeouts){
		while(this.timeouts.length){
			this.timeouts.pop();
		}
	}
};
Timer.prototype.make_timeouts = function(){
	this.timeouts = [];
	this.registerEvent({
		name: 'observe timeouts',
		func: function(){
			var removed = [];
			this.timeouts.each(function(obj){
				if(obj.count == 0){
					obj.func();
					removed.push(obj);
				}else{
					obj.count--;
				}
			});
			this.timeouts.remove_vals(removed);
		},
		oThis: this,
		args: []
	});
};
Timer.prototype.has_timeout = function(name){
	if(!this.timeouts){
		return false;
	}
	return !!this.timeouts.detect(detectFuncs.name.bind(name));
};
Timer.prototype.toString = __toString;
Timer.prototype.__name = "Timer";

Timer.detectTimer = function(oTimer){
	if(!oTimer){
		var t = new Timer(50);
		t.start();
		return t;
	}else if(oTimer instanceof Number){
		return new Timer(oTimer)
	}else if(oTimer instanceof Timer){
		oTimer._MUTUAL = true;
		return oTimer;
	}
};
Timer._instances = [];
Timer._TO_INSTANCES = true;
Timer.__loaded = true;

Array.Timer = function(arr, timer){
	this.arr = arr;
	this.timer = Timer.detectTimer(timer);
	if(this.timer._MUTUAL){
		Array.Timer.handleMutualTimer(this.timer, this);
	}
	this.index = -1;
	this.g_index = 0;
	this.ondo = new DOMEvent(this);
	this.onstart = new DOMEvent(this);
	this.onstop = new DOMEvent(this);
	this.IS_WORKING = false;
	this.DIRECTION = true;
	if(this.constructor._TO_INSTANCES){
		this.constructor._instances.push(this);
	}
}
Array.Timer.prototype.each = function(iterator, DIR){
	this.DIRECTION = typeof DIR != "undefined" ? DIR : true;
	this.iterator = iterator;
	this.start();
}
Array.Timer.prototype._do = function(){
	if(this.index == this.arr.length || this.index < 0){
		this.stop();
		return true;
	}
	this.g_index ++;
	var item = this.arr[this.index];
	this.current_result = this.iterator(item, this.index);
	if(typeof this.current_result != "undefined"){
		this.arr[this.index] = this.current_result;
	}
	this.ondo.fire(item, this.index);

}
Array.Timer.prototype.next = function(){
	this.index++;
	this._do();
}
Array.Timer.prototype.previous = function(){
	this.index --;
	this._do();
}
Array.Timer.prototype.start = function(){
	this.IS_WORKING = true;
	if(!this.timer._MUTUAL){
		this.timer.start();
	}
	this.onstart.fire();
}
Array.Timer.prototype.stop = function(){
	this.IS_WORKING = false;
	if(!this.timer._MUTUAL){
		this.timer.clear();
	}
	this.onstop.fire();
}
Array.Timer.prototype.ch_dir = function(){
	this.DIRECTION = !this.DIRECTION;
}
Array.Timer.prototype.to_start = function(){
	this.index = -1;
}
Array.Timer.prototype.to_end = function(){
	this.index = this.arr.length - 1;
}
Array.Timer.prototype.pause = function(){
	this.IS_WORKING = false;
	if(!this.timer._MUTUAL){
		this.timer.clear();
	}	
}
Array.Timer.prototype.resume = function(){
	this.IS_WORKING = true;
	if(!this.timer._MUTUAL){
		this.timer.start();
	}
}
Array.Timer._instances = [];
Array.Timer._TO_INSTANCES = true;
Array.Timer.__loaded = true;
Array.Timer.prototype.__name = "Array.Timer";
Array.Timer.prototype.toString = __toString;
Array.Timer.handleMutualTimer = function(oTimer, oAT){
	if(oTimer.arraytimers){
		oTimer.arraytimers.push(oAT);
	}else{
		oTimer.registerEvent({
			name: "Array.Timer",
			func: function(){
				this.arraytimers.each(function(at){
					if(at.IS_WORKING){
						if(at.DIRECTION){
							at.next();
						}else{
							at.previous();
						}
					}
				})
			},
			oThis: oTimer,
			args: []
		});
		oTimer.arraytimers = [];
		oTimer.arraytimers.push(oAT);
	}
}



Timer.__loaded = true;