% sinkarray - sink that collects data in an array
%
% sinkarray ::
%    ([[C,L]] -> action void) ~'function to do something with array on dispose',
%    C:natural ~'number of channels,
%    L:natural ~'capacity of sink',
%    R:nonneg  ~'sampling rate'
% -> sink(C,R).

classdef sinkarray < sinkbase
	properties (GetAccess=private,SetAccess=immutable)
		length   % natural
		cont     % [[C,N]] -> void
	end
	methods
		function s=sinkarray(cont,ch,len,rate)
			if nargin<4, rate=nan; end
			s=s@sinkbase(ch,rate);
			s.length=len;
			s.cont=cont;
		end

		function s=tostring(sig),
			s=sprintf('sinkarray(%s,<%dx%d>)',tostring(sig.cont),channels(sig),sig.length);
		end

		function s=construct(sig)
			s.start   = @nop;
			s.stop    = @nop;
			if isfinite(sig.length)
				length=sig.length;
				array=zeros(channels(sig),length);
				pos=0;

				s.dispose = @dispose;
				s.writer  = @writer;
			else
				gg=gatherer([channels(sig),1]);
				s.dispose = @dispose_gatherer;
				s.writer  = @writer_gatherer;
			end

			function dispose, sig.cont(array(:,1:pos)); end

			function r=writer(n)
				r = @next;
				CHUNK = 1:uint32(n);
				function rem=next(x) 
					n=size(x,2);
					if pos+n<=length
						array(:,pos+CHUNK)=x; rem=0; 
						pos=pos+n;
					else
						rem=n-(length-pos);
						array(:,pos+1:end)=x(:,1:rem);
						pos=length;
					end
				end
			end

			function dispose_gatherer, sig.cont(gg.collect()); end
			function r=writer_gatherer(n)
				r = @next;
				function rem=next(x) 
					n=size(x,2);
					for i=1:n, gg.append(x(:,i)); end
					rem=0; 
				end
			end
		end
	end
end
