% uiter - Run iterative thing on a live processing unit 
%
% uiter :: 
%    unit({}, _, _) ~'live processing unit',
%    T:natural      ~'number of iterations to run (can be inf)',
%    (natural,Q->Q) ~'function to run one step, can be stateful',
%    Q              ~'initial value to thread through calls to step fn',
%    options {
%       draw  :: boolean/false ~'whether or not to call drawnow after each iteration';
%       quiet :: boolean/false ~'whether or not to suppress progress messages';
%       chunk :: natural/1     ~'print progress every chunk interations';
%       label :: string/'uiter'~'used to identify progress messages'
%    } 
% -> natural ~'number of iterations actually done',
%    Q       ~'final value returned by step function'.
%
% This function accepts the live processing unit associated
% with an arrow (as created by with_arrow). Then system is
% started, an arbitrary function is called repeatedly, and then
% the system is stopped. If an EOF exception is thrown, the
% itertion is cut short but the function returns normally.
% If any other exception is thrown, the system is stopped before
% rethrowing the exception.

function [itsdone,state]=uiter(u,its,nextfn,state,varargin)
	opts=options('label','uiter','draw',1,'quiet',0,'chunk',1,varargin{:});
	quiet=opts.quiet; draw=opts.draw;
	chunk=opts.chunk;
	u.starting();
	try
		i=1;
		while i<=its, 
			if ~quiet && mod(i,chunk)==0, fprintf(' %s: %d   \r',opts.label,i); end
			state=nextfn(i,state);
			if draw, drawnow; end
			i=i+1;
		end
	catch ex
		if ~iseof(ex)
			if ~quiet, fprintf('exception at %d iterations.\n',i); end
			u.stopping();
			rethrow(ex); 
		end
	end
	itsdone=i-1;
	if ~quiet, fprintf('done %d iterations.\n',itsdone); end
	u.stopping();
end
