function Timer=lsched(action,evs)
% lsched - SCHEDule using List of times and parameters to fixed action
%
% lsched ::
%    (  S      ~'action parameter'
%       double ~'scheduled time',
%       double ~'actual time'
%    -> double ~'actual execution time'
%    ) ~'the action to perform at each time',
%    seq cell {
%       double ~'time of event',
%       S      ~'argument to pass to action'
%    } ~'the list of times and parameters to action'
% -> action timer ~'timer being used'.
%
% Note: this timer will DROP events if they cannot be scheduled roughly
% on time. However, if an event is scheduled with time to spare, but
% for some reason is called late, then it is not dropped.

	persistent ERROR % for estimating of timing errors

	ERROR=[];
	
	warning('off','MATLAB:TIMER:STARTDELAYPRECISION');

	Timer=timer;
	if isempty(evs), return; end

	[t0,s0]=cdeal(head(evs));

	% plan is to use a one shot timer to schedule next
	% event. Then, after the timer stops, the StopFcn callback
	% is called and we schedule the next event and restart the 
	% timer. This is really messy - should use my own timer
	% facilities written in Java..
	set(Timer,'UserData',{t0,s0,next(evs)}); % fst event and rest
	set(Timer,'TimerFcn',@onalarm,'StopFcn',@chain);
	set(Timer,'StartDelay',max(0,t0-nows)); 
	start(Timer);

	function onalarm(o,e)
		[t0,s0,evs]=cdeal(get(o,'UserData')); 
		% could potentially call a 'stalled' 
		% action if we are very late here
		tt=a(s0,t0,e.Data.time);
		ERROR=vertcat(ERROR,tt-t0);
	end

	% called 
	function chain(o,e)
		[t0,s0,evs]=cdeal(get(o,'UserData')); 
		
		if ~isempty(evs)
			correction=mean(ERROR);

			while 1
				[t1,s1]=cdeal(head(evs)); 
				delay=t1-correction-nows;
				if delay>=0 break; end
				fprintf('\n| dropping event, lag=%g',-delay);
				evs=next(evs);
			end
				
			set(o,'UserData',{t1,s1,next(evs)}); 
			set(o,'StartDelay',delay); 
			start(o);
		else
			fprintf('\n| stopping\n');
			plot(ERROR);
			timer_release(o);
		end
	end
end
