% ugather - Run a processing unit and collect output
%
% ugather :: 
%    unit({}, {[[N,1]]}, _) ~'live processing unit',
%    T:natural              ~'number of iterations to run (can be inf)',
%    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';
%       expand :: boolean/false~'do binary expansion of results array'
%    } 
% -> [[N,T]] ~'collected output'.
%
% This function accepts the live processing unit associated
% with an arrow (as created by with_arrow). The arrow must
% have zero inputs and one output. The requested number of outputs
% are collected into an array and returned. If inf outputs are
% requested, the system is run until an EOF exception is caught.

function X=ugather(u,its,varargin)
	opts=options('expand',1,varargin{:});
	szout = u.sizes_out{1};

	if szout(2)==1
		if opts.expand && isinf(its)
			X=zeros(szout(1),32); % initial size is arbitrarily 32
			done=uiter(u,its,@gatherxx,[],'label','ugather',opts);
			if done<size(X,2), X=X(:,1:done); end
		else
			if ~isinf(its), X=zeros(szout(1),its); end

			done=uiter(u,its,@gatherx,[],'label','ugather',opts);
			if done<its, X=X(:,1:done); end
		end
	else
		if opts.expand && isinf(its)
			X=zeros(szout(1),32); % initial size is arbitrarily 32
			done=szout(2)*uiter(u,its,@gatherxxw,[],'label','ugather',opts);
			if done<size(X,2), X=X(:,1:done); end
		else
			if ~isinf(its), X=zeros(szout(1),its*szout(2)); end

			done=szout(2)*uiter(u,its,@gatherxw,[],'label','ugather',opts);
			if done<its, X=X(:,1:done); end
		end
	end

	function s=gatherx(i,s), X(:,i)=u.process(); end
	function s=gatherxx(i,s), 
		if i>size(X,2),
			%fprintf('ugather: expanding at %d.\n',size(X,2));
			X=[X,zeros(size(X))]; % double size
		end
		X(:,i)=u.process(); 
	end

	function s=gatherxw(i,s), 
		i1=1+(i-1)*szout(2);
		i2=i*szout(2);
		X(:,i1:i2)=u.process(); 
	end
	function s=gatherxxw(i,s), 
		i1=1+(i-1)*szout(2);
		i2=i*szout(2);
		if i2>size(X,2),
			%fprintf('ugather: expanding at %d.\n',size(X,2));
			X=[X,zeros(size(X))]; % double size
		end
		X(:,i1:i2)=u.process(); 
	end
end


