package com.netgrind.core {
	import flash.display.Stage;
	import flash.events.Event;
	import flash.utils.getTimer;
	
	/**
	 * ...
	 * @author netgrind
	 */
	public class Scheduler {
		
		private static var _functions:Array = new Array();
		private static var lastMS:int;
		public static var ms:int;
		public static var deltaMS:int;
		private static var _paused:Boolean = false;
		public static var sin:Number;
		public static var cos:Number;
		public static var c:Number = 0
		private static var stage:Stage;
		private static var _deltaTime:Number;
		static public var step:Number = Math.PI* .02;
		static public var fps:Array = [];
		static public var timeScale:Number = 1;
		
		public static function init(s:Stage):void {
			s.addEventListener(Event.ENTER_FRAME, onFrame);
			stage = s;
		}
		
		static public function get deltaTime():Number {
			return _deltaTime
		}
		
		static private function onFrame(e:Event):void {
			ms = getTimer();
			deltaMS = ms - lastMS;
			fps.unshift(1000 / deltaMS);
			if (fps.length > 100) fps.pop();
			_deltaTime = (1000 / stage.frameRate) / deltaMS*timeScale;
			//DebugWindow.log(_deltaTime);
			c += step;//*deltaTime;
			sin = Math.sin(c);
			cos = Math.cos(c);
			if (!paused && _functions.length) {
				for (var i:int = _functions.length - 1; i >= 0; i--) {
					if (_functions[i] == null) {
						_functions.splice(i, 1);
						continue;
					}
					if (_functions[i][4] == true) {
						continue;
					}
					if (_functions[i][1] == -1){
						_functions[i][0].apply(null, _functions[i][2]);
					}else {
						if(_functions[i][3]==true){
							_functions[i][1]--;
						}else {
							_functions[i][1] -= deltaMS;
						}
						if (_functions[i][1] <= 0) {
							var f:Function = _functions[i][0];
							var data:Array = _functions[i][2];
							_functions[i] = null;
							_functions.splice(i, 1);
							f.apply(null, data);
						}						
					}
				}
			}
			lastMS = ms;
		}
		
		public static function invokeEvery(func:Function, ...args):void {
			_functions.push([func,-1,args,true]);
		}
		
		public static function invokeIn(func:Function, frames:int = 1, ...args):void {
			_functions.push([func,frames,args,true]);
		}
		
		public static function invokeInMS(func:Function, ms:int = 1000, ...args):void {
			_functions.push([func,ms,args,false])
		}
		
		public static function cancel(func:Function):void {
			for (var i:int = _functions.length - 1; i >= 0 ; i--) {
				if (_functions[i][0] == func) {
					_functions[i] = null;
					_functions.splice(i, 1);
				}
			}
		}
		
		static public function functionCount():int {
			return _functions.length;
		}
		
		static public function clearAll():void {
			for (var i:int = _functions.length-1; i >=0 ; i--) {
				_functions[i] = null;
				_functions.splice(i, 1);
			}
		}
		
		static public function pause(func:Function, value:Boolean):void {
			for (var i:int = _functions.length - 1; i >= 0 ; i--) {
				if (_functions[i][0] == func) {
					_functions[i][4] = value
				}
			}
		}
		
		static public function invoking(func:Function):Boolean {
			for (var i:int = _functions.length - 1; i >= 0 ; i--) {
				if (_functions[i][0] == func) {
					return true;
				}
			}
			return false;
		}
		
		static public function lag(fpsThreshold:Number, frames:int):Boolean {
			frames = Math.min(frames, fps.length);
			for (var i:int = 0; i < frames; i++) {
				if (fps[i] > fpsThreshold) return false;
			}
			return true;
		}
		
		static public function cancelAll():void {
			while (_functions.length > 0) {
				for (var i:int = 0; i < _functions[0].length; i++) {
					_functions[0][i] = null;
				}
				_functions[0] = null;
				_functions.splice(0, 1);
			}
		}
		
		public static function get paused():Boolean {
			return _paused;
		}
		
		public static function set paused(value:Boolean):void {
			_paused = value;
		}
		
	}
	
}