

// TVG - SCRIPTICIAN - CHRON


// FAMILY: CHRON TIMELINE CONTROL
// main timeline, the beating heart of CHRON
// parameter "timeline_frame_interval" accepts: number in milliseconds or omit
// parameter "timeline_frame_shift" accepts: number in frames or omit
// parameter "timeline_console" accepts: "true" or "false" or omit
// note: apart from the console controls, there are no mechanisms to externally alter the running of the timeline
if (TVGS) function chron_timeline(timeline_frame_interval, timeline_frame_shift, timeline_console)
{
	
	// PARAMETERS
	
	// check input
	
	// check frame interval
	if (timeline_frame_interval == null) timeline_frame_interval = 40; // default is 25 frames per second (40 milliseconds)
	
	// set minimum of 1 millisecond
	// note: this prevents rupturing of the space-time continuum
	if (timeline_frame_interval < 1) timeline_frame_interval = 1;
	
	// check frame shift
	if (timeline_frame_shift == null) timeline_frame_shift = Math.round(500 / timeline_frame_interval); // default is to skip about half a second to one second of frames
	
	// check console activity
	if (timeline_console == null) timeline_console = false;
	



	// PUBLIC INFO
	
	// set frame interval
	this.frame_interval = timeline_frame_interval;
	
	
	// set time shift	
	// shifts the entire timeline execution by a number of frames
	// note: can be used to set a small delay to avoid messy page starts
	this.time_shift = this.frame_interval * timeline_frame_shift;
	
	// set time zero point
	this.time_zero_point = new Date().getTime();
	
	
	
	
	// PUBLIC FUNCTIONS
	
	// get internal time in milliseconds (actual time minus the zero point in milliseconds)
	this.time = function()
	{
		return new Date().getTime() - this.time_zero_point;
	}
	
	// generate unique trace string
	// note: consists of 16 lowercase letters
	this.trace = function()
	{
		var trace = '';
		while (trace.length < 16) trace += String.fromCharCode(97 + Math.floor(Math.random()*26));
		return trace;
	}
	
	
	
	
	
	
	// set actions list
	this.actions = [];
	
	// set chains list
	// devnote: obsolete???
	this.chains = [];
	
	
	

	// PRIVATE TRACKERS
	
	// get first frame timestamp
	var timeline_start = this.time() - this.time_shift;
	
	
	// set first frame start and end
	var frame_start = timeline_start;
	var frame_start_measured = timeline_start;
	var frame_end = timeline_start + this.frame_interval;
	
	
	// set timeline trackers
	var total_frames = 0;
	var total_frames_delay = 0;
	var total_frames_delayed = 0;
	var total_frames_overshot = 0;
	var total_frames_overshot_on_delay = 0; // delay only 
	var total_frames_overshot_on_actions = 0; // actions duration only
	var total_frames_overshot_on_combi = 0; // delay plus action duration
	var total_actions = 0;
	var total_actions_duration = 0;
	var total_actions_skipped = 0;
	var total_actions_smothered = 0;
	
	
	// set frame trackers
	var frame_delay = 0;
	var frame_overshot = false;
	var previous_frame_overshot = false;
	var frame_actions = 0;
	var frame_actions_skipped = 0;
	var total_actions_pending = 0;
	var actions_finished = 0;
	var actions_duration = 0;
	var frame_time_left = 0;
	
 
 

 	// TIMELINE CONSOLE
 	// note: set to false to disable display and all internal tracking
 	// note: internal tracking and console output generates overhead that will make the engine run slower
 	
 	// setup console and tracking
 	if (timeline_console)
 	{

		// find output elements
 		try
 		{
 			
 			// set console
 			var console = {};
 			
 			// set console output elements
 			console.output = {};
 			console.output.main_display = document.getElementById('tvgs_timeline_console');
 			console.output.total_frames_output = document.getElementById('tvgs_tc_total_frames');
 			console.output.total_time_output = document.getElementById('tvgs_tc_total_time');
 			console.output.total_actions_output = document.getElementById('tvgs_tc_total_actions');
 			console.output.total_actions_skipped_output = document.getElementById('tvgs_tc_skipped_actions');
 			console.output.total_actions_smothered_output = document.getElementById('tvgs_tc_smothered_actions');
 			console.output.total_actions_pending_output = document.getElementById('tvgs_tc_pending_actions');
 			console.output.framerate_integrity_output = document.getElementById('tvgs_tc_framerate_integrity');
 			console.output.frames_overshot_output = document.getElementById('tvgs_tc_frames_overshot');
 			console.output.frames_delay_output = document.getElementById('tvgs_tc_frames_delay');
 			console.output.frames_interval_output = document.getElementById('tvgs_tc_frames_interval');
 			console.output.frames_duration_output = document.getElementById('tvgs_tc_frames_duration');
 			console.output.frames_overshot_actions_output = document.getElementById('tvgs_tc_frames_overshot_actions');
 			console.output.frames_overshot_delay_output = document.getElementById('tvgs_tc_frames_overshot_delay');
 			console.output.frames_overshot_combi_output = document.getElementById('tvgs_tc_frames_overshot_combi');
 			
 			// check output elements
 			for (var i in console.output)
 			{

 				// if one of the output elements is missing cancel console output
 				if (console.output[i] == null) throw '';
 			
 			}
 
 		}
 		catch(error)
 		{
 			
 			//alert('TVGS Timeline Console could not be initialized!');
 			
 			// abort console output
 			timeline_console = false;
 			
 		}
 		
 		
 		// finish setup
 		if (timeline_console)
 		{
			
			// set global timeline console options
			this.console = {};
 			this.console.enable = true;
 			this.console.reset_all_counters = false;
		
			// set fixed readout values
			
			// get target framerate in frames per second
			// note: default is 25 frames per second (40 milliseconds)
			var target_framerate = 1000 / this.frame_interval;
			var target_framerate_rounded = tvgs_round_to_string(target_framerate, 1);
			
			// set dynamic readout values
			
			// set console trackers
			var average_frame_interval = 0;
			var frames_interval_readout = '';
			var framerate_integrity = 0;
			var framerate_per_second = 0;
			var framerate_integrity_readout = '';
			var average_frames_delay = 0;
			var frames_delay_readout = '';
			var console_finished = 0;
			var console_duration = 0;
 		
 		}

 	}
 	
 	
 	
 	
 	// TIMELINE FRAMES
 	
	// start timeline
	if (total_frames == 0) setTimeout(timeline_frame, 0);

	// timeline frame repeater
	function timeline_frame()
	{
	
		
		// reset frame trackers
		frame_actions = 0;
		frame_actions_skipped = 0;
		total_actions_pending = 0;
		
		
		if (total_frames != 0)
		{
			
			// get previous frame overshot
			previous_frame_overshot = frame_overshot;
			
			// get previous frame end as this frame's intended start
			frame_start = frame_end;
			
			// update frame_start with current timestamp
			frame_start_measured = TVGS.CHRON.time() - TVGS.CHRON.time_shift;
			
			// set new frame end
			frame_end = frame_start + TVGS.CHRON.frame_interval;

		}
		
		

		
		
		// skip some frames to avoid messy page start
		if (total_frames >= timeline_frame_shift)
		{
			
				
			// proces frame
			// note: all frame items wil be processed, even this frame takes longer than the set frame time, items from the next frames will then be skipped
			
			
			// outer loop controls
			
			// monitor actions progress in this frame
			var frame_actions_pending = true;
			//var items = 0;
			
			// collect instigates to execute at the end of this frame
			var instigate_by_relay = [];
			var instigate_by_script = [];
			
			
			// inner loop controls
			var delete_actions_keys = [];
			var smother_action_keys = [];
			var loop_reset = false;
			
			
			// action controls
			var carry_out_action = false;
			
		
			
			// get pending actions at start of frame for console
			total_actions_pending = TVGS.CHRON.actions.length;
			
			//document.getElementById('output').innerHTML += ' frameactions pre ' + TVGS.CHRON.actions.length + ' ';
			
			// no actions pending at all
			//if (total_actions_pending == 0) frame_actions_pending = false;
			
			// restart frame loop every time the timeline is altered while processing actions (by smothers and such)
			while (frame_actions_pending && TVGS.CHRON.actions.length > 0) //  && TVGS.CHRON.actions.length > 0
			{
				
				//if (loop_reset) document.getElementById('output').innerHTML += ' resume after loop reset  ' + TVGS.CHRON.actions.length + ' <br>';
				//else document.getElementById('output').innerHTML += ' frame actions pending  ' + TVGS.CHRON.actions.length + ' <br>';
		
				delete_actions_keys = [];
				smother_action_keys = [];
				loop_reset = false;
				
				
				// sort timeline by trigger time
				TVGS.CHRON.actions.sort(function(a, b) {return a.time - b.time});
				
			
				//items = TVGS.CHRON.actions.length;
				
			//	if (items == 0) TVGS.CHRON.actions.length;
				
				//document.getElementById('output').innerHTML += ' timeline ' + TVGS.CHRON.actions.length + ' ';
				
		
				// check timeline items
				// custom loop with cached length property, maximum full-loop performance on very large arrays
				for (var key = 0, items = TVGS.CHRON.actions.length; key < items; ++key)
				{
					
					// assume skipped action
					carry_out_action = false;
					
					// evaluate late actions
					if (TVGS.CHRON.actions[key].time < frame_start)
					{
						
						// check for obligatory action
						if (TVGS.CHRON.actions[key].complete == 1)
						{
							
							// approve
							carry_out_action = true;
	
						}
						else
						{
							
							// skip
							
							// track timeline
							total_actions_skipped++;
							
							// track frame
							frame_actions_skipped++;
							
						}
						
						
						// mark for deletion from timeline
						delete_actions_keys.push(key);
						
						//document.getElementById('output').innerHTML += ' check 1 before frame <br>';
						// track timeline
						total_actions++;
						
						// track frame
						frame_actions++;
					
					}
					// process current actions
					else if (TVGS.CHRON.actions[key].time < frame_end)
					{
						
						// approve
						carry_out_action = true;
	
						
						// mark for deletion from timeline
						delete_actions_keys.push(key);
						
						//document.getElementById('output').innerHTML += ' check 2 in frame <br>';
						// track timeline
						total_actions++;
						
						// track frame
						frame_actions++;
					
					}
					else
					{
						//document.getElementById('output').innerHTML += ' check 3 after frame <br>';
						// no more items in this frame
						frame_actions_pending = false;
						break;
					
					}
		
		
					//document.getElementById('output').innerHTML += ' check 1 ';
					
					// carry out action
					if(carry_out_action)
					{
						
						// run actions
						if (TVGS.CHRON.actions[key].values !== null)
						{
							//document.getElementById('output').innerHTML += ' => run action ';
							// run action by values
							tvgs_timeline_action_relay(TVGS.CHRON.actions[key].values);
							//document.getElementById('output').innerHTML += ' => run action finished ';
						}
						
						if (TVGS.CHRON.actions[key].script !== null)
						{
							//document.getElementById('output').innerHTML += ' run script ' + TVGS.CHRON.actions[key].script + ' ';
							// run action by script
							eval(TVGS.CHRON.actions[key].script);
						
						}
						// actions with missing info get skipped
						
						
						// smother actions
						// note: smothers are executed immediately, so any items of the active chain that still fall into this frame are also wiped and not processed anymore
						if (!TVGS.nil(TVGS.CHRON.actions[key].smother))
						{
				
							smother_action_keys = chron_timeline_remove_actions(TVGS.CHRON.actions[key].smother.name, TVGS.CHRON.actions[key].smother.element, TVGS.CHRON.actions[key].trace);
							
							total_actions_smothered += smother_action_keys.length;
							
							if (smother_action_keys.length > 0)
							{
								
								// add to actions to delete
								delete_actions_keys = delete_actions_keys.concat(smother_action_keys);
								
								// trigger loop reset
								loop_reset = true;							
							
							}
							
						}
						
						
						// collect instigates
						// note: instigates are collected in separate arrays, and will be executed after the original actions are deleted
						// note: this way the actions of the instigated chain cannot interfere with this frame, and will possibly be dropped in the next frame
						if (!TVGS.nil(TVGS.CHRON.actions[key].instigate))
						{
							
							for (var i in TVGS.CHRON.actions[key].instigate){ if (TVGS.key(i)){
							
								if (TVGS.CHRON.actions[key].instigate[i].relay)
								{
							
									// run action by values
									instigate_by_relay.push(TVGS.CHRON.actions[key].instigate[i].relay);
									//chron_chain_instigate_relay(TVGS.CHRON.actions[key].instigate.values);
							
								}
								
								if (TVGS.CHRON.actions[key].instigate[i].script)
								{

									// run action by script
									instigate_by_script.push(TVGS.CHRON.actions[key].instigate[i].script);
									//eval(TVGS.CHRON.actions[key].instigate.script);
								
								}
								// actions with missing info get skipped
								
							}}
							
						}
				
					
					}  // end carry out action
					
					
				//	document.getElementById('output').innerHTML += ' check 2 ';
					
					
					
					// restart loop when actions must be deleted immediately
					if (loop_reset) break;
				
				} // end check timeline items	
				
				//document.getElementById('output').innerHTML += ' frameactions predelete ' + TVGS.CHRON.actions.length + ' ';
				
				// delete actions from timeline
				// note: can be the final delete or a loop reset
				delete_actions_keys = cleanup_numeric_array(delete_actions_keys);
				//alert(delete_actions_keys);
				for (var i in delete_actions_keys){ if (TVGS.key(i)){

					TVGS.CHRON.actions.splice(delete_actions_keys[i], 1);

				}}
			
			
		
				
			} // end while frame actions pending
			

			//document.getElementById('output').innerHTML += ' frameactions post ' + TVGS.CHRON.actions.length + ' ';
			
			// execute collected instigates
			for (var i in instigate_by_relay){ if (TVGS.key(i)){

				// run instigate by values
				TVGS.chron_chain_instigate_relay(instigate_by_relay[i]);
				
			}}
			
			// execute collected scripts
			for (var i in instigate_by_script){ if (TVGS.key(i)){
			
				// run instigate by script
				eval(instigate_by_script[i]);
				
			}}
			
			
			
		
		} // end skip start of timeline frames
		
		//document.getElementById('output').innerHTML += ' main loop finished <br><br>';
		
		
		
		// get frame duration
		actions_finished = TVGS.CHRON.time() - TVGS.CHRON.time_shift;
		actions_duration = actions_finished - frame_start_measured;
		
		// calculate time left till next frame start
		frame_time_left = frame_end - actions_finished;
		
		// check time left
		if (frame_time_left < 0) 
		{
			
			// frame interval time is exceeded
			
			// next frame starts immediately
			frame_time_left = 0;
			
			// end time of this frame is increased to current time
			frame_end = actions_finished;
			
			// set frame overshot
			frame_overshot = true;
			
			// track total frames overshot
			total_frames_overshot++;
			
		}
		else
		{
		
			frame_overshot = false;
		
		}
		
		
		
		
	
		
		
		// track total frames
		total_frames++;
		
		
		// console and tracking
		// note: this adds etra frame delay and an extra timecheck for compensation
		if (timeline_console && TVGS.CHRON.console.enable)
		{
			
			// when the console is disabled, main counters keep running with minimal overhead
			// when it switched back on trivial info should reset
						
			
			// check for total reset
			if (TVGS.CHRON.console.reset_all_counters)
			{
			
				alert('reset');
				
				// some info like pending actions is not resettabel
				
				// most other actions could be reset here wit a big wipe of all vars to zero, calculated readouts would then also set back to 0/nothing
				
				
				// reset completed
				TVGS.CHRON.console.reset_all_counters = false;
			
			}
			
			
			// track total actions duration
			total_actions_duration = total_actions_duration + actions_duration;
			
			
			// see if this frame is running late
			// note: frame delay can also be negative if the frame is early
			// note: actions from the previous frame that fall into this negative delay will already have been processed, so this has no further consequence
			frame_delay = frame_start_measured - frame_start;
			
			// track frame delay only when the previous frame was not overshot
			if (previous_frame_overshot == false)
			{
				total_frames_delay = total_frames_delay + frame_delay;
				total_frames_delayed++;
			}
			
			
			// see if this frame is overshot and/or delayed and track overshot type
			
			// certain overshot, action time is longer than frame interval
			if (actions_duration > TVGS.CHRON.frame_interval)
			{
				total_frames_overshot_on_actions++;
			}
			
			// certain overshot, delay time is longer than frame interval
			if (frame_delay > TVGS.CHRON.frame_interval)
			{
				total_frames_overshot_on_delay++;
			}
			
			
			// certain overshot, delay plus action time combined is longer than frame interval
			if (actions_duration <= TVGS.CHRON.frame_interval && frame_delay <= TVGS.CHRON.frame_interval && frame_overshot == true)
			{
				total_frames_overshot_on_combi++;
			}

		
		
				
			// get framerate integrity
			// note: this is calculated over the entire running length of the timeline
			if (total_frames > 0)
			{
				// total average frame interval
				average_frame_interval = (frame_start - timeline_start) / total_frames;
				frames_interval_readout = tvgs_round_to_string(average_frame_interval, 2) + 'ms (of ' + TVGS.CHRON.frame_interval + 'ms target)';
				
				// total framerate integrity as percentage
				framerate_integrity = TVGS.CHRON.frame_interval / average_frame_interval;
				framerate_per_second = 1000 / average_frame_interval;
				framerate_integrity_readout = tvgs_round_to_string((framerate_integrity * 100), 1) + '% (' + tvgs_round_to_string(framerate_per_second, 1) + 'fps of ' + target_framerate_rounded + 'fps target)';
			}
			
			
			// get framerate overshot
			// note: this calculated over the entire running length of the timeline
			average_frames_delay = total_frames_delay / total_frames_delayed;
			frames_delay_readout = tvgs_round_to_string(average_frames_delay, 2) + 'ms';
			
			
			// get actions duration
			// note: this calculated over the entire running length of the timeline
			average_actions_duration = total_actions_duration / total_frames;
			actions_duration_readout = tvgs_round_to_string(average_actions_duration, 2) + 'ms';
			
			
			// get total running time
			// note: this calculated over the entire running length of the timeline
			total_running_time = actions_finished - timeline_start;
			total_running_time_readout = tvgs_round_to_string((total_running_time / 1000), 1) + 's';
			
			
			
		
			// update readout
			console.output.total_time_output.innerHTML = total_running_time_readout;
			console.output.total_frames_output.innerHTML = total_frames;
 			console.output.total_actions_output.innerHTML = total_actions;
 			console.output.total_actions_skipped_output.innerHTML = total_actions_skipped;
 			console.output.total_actions_smothered_output.innerHTML = total_actions_smothered;
 			console.output.total_actions_pending_output.innerHTML = total_actions_pending;
 			console.output.framerate_integrity_output.innerHTML = framerate_integrity_readout;
 			console.output.frames_interval_output.innerHTML = frames_interval_readout;
			console.output.frames_delay_output.innerHTML = frames_delay_readout;
 			console.output.frames_duration_output.innerHTML = actions_duration_readout;
 			console.output.frames_overshot_output.innerHTML = total_frames_overshot;
 			console.output.frames_overshot_actions_output.innerHTML = total_frames_overshot_on_actions;
 			console.output.frames_overshot_delay_output.innerHTML = total_frames_overshot_on_delay;
 			console.output.frames_overshot_combi_output.innerHTML = total_frames_overshot_on_combi;
 			
 			
 			// compensate frame delay readout for console activity
 			// note: this only compensates for all frames looking consistently delayed in the readout
 			// note: real frame status or duration is not altered by this basic readout fix
 			// note: if console activity makes a frame overshot it will not be treated as such in this or the next frame
 			// note: however, actions will be skipped as normal because of console overhead
 			if (frame_time_left > 0) 
			{
				
				// get console duration
				console_finished = TVGS.CHRON.time() - TVGS.CHRON.time_shift;
				console_duration = console_finished - actions_finished;
				
				// adjust frame time left
				frame_time_left = frame_time_left - console_duration;
				
				// set back to zero when negative				
				if (frame_time_left < 0) frame_time_left = 0;
				
			}

		}
		
		
		// schedule next frame
		setTimeout(timeline_frame, frame_time_left);
			
	} // end function timeline_frame
	
	
	// sorts descending and cleans out duplicates
	function cleanup_numeric_array(numeric_array)
	{
	
		//document.getElementById('output').innerHTML += ' getting ' + numeric_array + ' <br>';
	
		numeric_array.sort(function(a, b) {return b - a});
		
		for (var key = (numeric_array.length - 1); key > -1; key--)
		{
		
			if (typeof last_entry != 'undefined')
			{
			
				if (numeric_array[key] == last_entry)
				{
				
					numeric_array.splice(last_entry_key, 1);
				
				}

			}

			var last_entry = numeric_array[key];
			var last_entry_key = key;
		
		}
		
		
		
		//document.getElementById('output').innerHTML += ' returning ' + numeric_array + ' <br>';
		
		
		return numeric_array;
		
		
		
	} // end function cleanup_numeric_array
		


} // end function chron_timeline






// FAMILY: CHRON TIMELINE CONTROL
// adds an action to the timeline
if (TVGS) function chron_timeline_add_action(trace, time, name, values, script, chain, complete, smother, instigate)
{
	
	// setup action
	var timeline_action = {};
	
	// fill with parameters
	timeline_action.trace = trace; // unique identifier string
	timeline_action.time = time - TVGS.CHRON.time_shift; // time to trigger the action
	timeline_action.name = name; // the frame action name, this is paired to a registered action function
	timeline_action.values = values; // the values of the parameters for the frame action
	timeline_action.script = script; // the frame action to carry out by means of eval when "name" and "values" are not set
	timeline_action.chain = chain; // the chain identifier, used to link a series of actions
	timeline_action.complete = complete; // mandatory completion of this action by setting to 1, meaning the action will not be skipped even if it is late
	timeline_action.smother = smother; // break and complete or pause the same action type chain on the same element before continuing
	//timeline_action.propagate = propagate; // how often to repeat the original action, 0 is infinite
	timeline_action.instigate = instigate; // updated transscript of the original chain creation
	
	// set instigate
	/*
	if (instigate == null)
	{
		timeline_action.instigate = null; // transscript of the original action creation, used for propagation
	}
	else
	{
	
		timeline_action.instigate = {};
		timeline_action.instigate.name = instigate.name;
		timeline_action.instigate.values = instigate.values;
		timeline_action.instigate.script = instigate.script;
		
	}
	*/
	//document.getElementById('output').innerHTML += trace + ' add action<br>';
 	// add to timeline
	TVGS.CHRON.actions.push(timeline_action);
	
	//document.getElementById('output').innerHTML += ' temline addframe ' + time + ' ';
	
}



// FAMILY: CHRON TIMELINE CONTROL
// removes actions based on criteria
// note: name and element are inclusive properties (actions will only get deleted when they are the right name and element)
// note: timestamp and trace are exclusive properties (actions will only get deleted when they are not the right timestamp and trace)

/*

- of multiple chains started in the same frame, the former smothers the latter, while it should be the other way round (roughly)
- protecting the first smother frame does not work entirely, because technically the smother frame of the first chain should be deleted as well
- smothered frames are now wiped immediately, they should be flagged for non-evaluation, so the chain can be reactivated.... mhz
- collect smothers like instigates?
- drop the smother action when the first frame to smother that is encountered is a first chain frame with a similar smother, this means it is a later frame and this chain should be preserved, and the old one gets wiped a bit later on, this also works for multiple consecutive chains!



*/
if (TVGS) function chron_timeline_remove_actions(name, element, trace)
{
	
	
	//document.getElementById('output').innerHTML += ' deleting ' + name + ' ' + element.nodeName + ' ' + trace + ' <br>';
	
	//set break and return flag
	var return_results = false;
	
	// set removal flag
	var remove_action = false;
	
	// make actions delete list
	var remove_action_keys = [];
	
	
	// delete all pending actions from the timeline
	for (var key_2 = 0, items_2 = TVGS.CHRON.actions.length; key_2 < items_2; ++key_2)
	{
		
		// set removal flag
		remove_action = false;
		
		
		// inclusive
		
		// check action name and element
		if (name != null && TVGS.CHRON.actions[key_2].name == name && element != null && TVGS.CHRON.actions[key_2].values.element == element)
		{
			// name and element match
			remove_action = true;
			
			// override and break when new chain with identical smother is encountered
			// note: this prevents the newer chain from getting wiped, any outstanding actions which should be smothered but get skipped by this break will be smothered by the newer chain
			if (!TVGS.nil(TVGS.CHRON.actions[key_2].smother) && TVGS.CHRON.actions[key_2].name == TVGS.CHRON.actions[key_2].smother.name && TVGS.CHRON.actions[key_2].values.element == TVGS.CHRON.actions[key_2].smother.element && TVGS.CHRON.actions[key_2].trace != trace)
			{
				remove_action = false;
				return_results = true;
				
				//document.getElementById('output').innerHTML += ' smotherdetect ' + ' ';
				
			}
			
			
		}
		else if (name == null && element != null && TVGS.CHRON.actions[key_2].values.element == element)
		{
			// element matches
			remove_action = true;
		}
		else if (element == null && name != null && TVGS.CHRON.actions[key_2].values.name == name)
		{
			// name matches
			remove_action = true;
		}
		
		
			
		// exclusive
	
		// check action trace
		if (trace != null && TVGS.CHRON.actions[key_2].trace == trace)
		{
			// trace matches
			remove_action = false;
		}
		
		
		// add to removal list
		if (remove_action)
		{
			remove_action_keys.push(key_2);
		}
		
		
		// break and return results
		if (return_results)
		{
			return remove_action_keys;
		}
		

	}

	
	/*
	// delete actions from timeline
	for (var i in remove_action_keys.reverse())
	{
		TVGS.CHRON.actions.splice(remove_action_keys[i], 1);
	}
	*/
	
	//document.getElementById('output').innerHTML += ' deleted ' + remove_action_keys.length + ' actions,';
	
	// full scan completed
	return remove_action_keys;
	
}






/*
// FAMILY: CHRON TIMELINE CONTROL
// finds a chain and deletes all its (remaining) actions and the chain itself, so a new one can be started
if (TVGS) function chron_timeline_remove_chain(name, element)
{
	
	//document.getElementById('output').innerHTML = 'smothering chain ' + name + ' for ' + element.id;
	
	
	// delete chains
		
	// make chains delete list
	var delete_chains_keys = [];
	
	// check chain items
	for (var key_1 = 0, items_1 = TVGS.CHRON.chains.length; key_1 < items_1; ++key_1)
	{
		
		//document.getElementById('output').innerHTML += ' CHAIN ' + key_1;
		
		
		
		// get the right chain type and the right element
		if (TVGS.CHRON.chains[key_1].name == name && TVGS.CHRON.chains[key_1].element == element)
		{
			
			// active chain exists

			
			// delete chain
			//TVGS.CHRON.chains.splice(key_1, 1); // ERRORS!!!!! do not delete while iterating!!!!
			delete_chains_keys.push(key_1);

		}
		
		//document.getElementById('output').innerHTML += ' CHAIN_END ' + key_1;
		
	}
	
	
	// delete chains
	for (var i in delete_chains_keys.reverse())
	{
	
		TVGS.CHRON.chains.splice(delete_chains_keys[i], 1);
	
	}
	
	
	
	// delete actions
	
	// make actions delete list
	var delete_actions_keys = [];
	
	// delete all pending actions from the timeline
	for (var key_2 = 0, items_2 = TVGS.CHRON.actions.length; key_2 < items_2; ++key_2)
	{
		
		//document.getElementById('output').innerHTML += ' action ' + key_2;
		
		// get the right action type and the right element
		if (TVGS.CHRON.actions[key_2].values.element == element && TVGS.CHRON.actions[key_2].name == name)
		{
		
			delete_actions_keys.push(key_2);
		
		}
	
	}

	// delete actions from timeline
	for (var i in delete_actions_keys.reverse())
	{
	
		TVGS.CHRON.actions.splice(delete_actions_keys[i], 1);
	
	}
	
	//alert ('deleted ' + delete_actions_keys.length + ' actions');
	document.getElementById('output').innerHTML += ' deleted ' + delete_actions_keys.length + ' actions,';		
			
			
			
			
			
	
	//document.getElementById('output').innerHTML += ' FINISHED ';
	
}

*/

