var syncer = function () {

//TODO: some of the public 'that' functions are actually private, no 'that' needed

	var that = this;
	var controllers = new Array();
	var mediaTime;
	//set defaults that setters can overwrite
	var interval = 500;
	var syncMediaImpl;
	var recurse = true;
	var maxRecurse = 0;
	var recurseCount = -1;

	that.stopRecurse = function (){
		recurse = false;
	};

	that.setMaxRecurse = function (madMax){
		maxRecurse = madMax;
	};
			
	that.main = function (){
		runSync();
		recurseCount++;
		if ( recurse && (recurseCount <= maxRecurse) || (maxRecurse < 0)){
			setTimeout(that.main, interval);
		}
	};

	runSync = function (){
		mediaTime = syncMediaImpl.getTimeCode();
		
		runControllers();
	};

	setNewTime = function (newTime){
		syncMediaImpl.setTimeCode(newTime);
		mediaTime = syncMediaImpl.getTimeCode();
	};	
	
	that.setInterval = function (new_interval){
		interval = new_interval;
	};
	
	that.getInterval = function (){
		return interval;
	};
	
	that.setSyncMediaImpl = function(mediaAccessObject){
		syncMediaImpl = mediaAccessObject;
	};
	
	that.addController = function (controller){
		//TODO check for duplicates
		controllers.push(controller);
		return controllers.length;
	};
	
	that.insertController = function (controller, index){
		controllers.splice(index, 0, controller);
	};
	
	that.removeController = function (index){
		//TODO to keep sparseness in check if(length > ARBITRARY_NUMBER)rewrite array	
		controllers.splice(index, 1);	
	};
	
	that.getControllers = function (){
		return controllers;
	};
	
	runControllers = function (){
	//http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays
	//for..in isn't guaranteed to preserve element ordering
		for (var i=0; i <controllers.length; i++) {
			if (controllers[i] != undefined) {
		 		newTime = controllers[i].run(mediaTime);
		 	}
			
		 	if (!(newTime == undefined) && newTime != null) {
		 		setNewTime(newTime);
		 	}
		}
	};
	
	return that;
};
