% buffer - collect elements of sequence into sequence of arrays
%
% buffer :: 
% 	  seq([Size:[[1,E]]])  ~'sequence of E dimensional arrays',
%	  L:natural       ~'buffer width',
%    E:natural       ~'effective dimension of input values',
%    buffer_tailfn   ~'function to deal with last incomplete buffer'
% -> seq([[Size,L]]) ~'buffered sequence (no-overlapping)'.
%
% buffer_tailfn can be 
%    seq.buffer.truncate :: void -> tailfn  ~'discard incomplete buffer'.
%    seq.buffer.append   :: void -> tailfn  ~'append smaller buffer to sequence'.
%    seq.buffer.pad      :: [[N]]-> tailfn  ~'pad final buffer with value'.

classdef buffer < seq
	properties (GetAccess=private, SetAccess=immutable)
		width
		colons
		tailfn
	end
	properties (GetAccess=private, SetAccess=private)
		source
		buf
	end
	methods
		function a=buffer(source,L,dim,tailfn)
			sz=size1(source);
			if nargin<3, dim=length(sz); end
			if nargin<4, tailfn=seq.buffer.truncate; end
			colons = repmat({':'},1,dim);
			buf=repmat(head(source),tosize([ones(size(colons)),L]));
			source=next(source);
			for i=2:L
				if isempty(source), a=tailfn(buf,i-1,colons); return; end
				buf(colons{:},i)=head(source);
				source=next(source);
			end
			a.source = source;
			a.width = L;
			a.colons=colons;
			a.tailfn = tailfn;
			a.buf=buf;
		end

		function z=elsize(a), z=size(a.buf); end
		function s=tostring(a), s=sprintf('%s >> buffer(%d,%d)',tostring(a.source),a.width,length(a.colons)+1); end
		function x=head(a), x=a.buf; end
		function a=next(a)
			% read next lot of values and make an array
			for i=1:a.width
				if isempty(a.source), a=a.tailfn(a.buf,i-1,a.colons); return; end
				a.buf(a.colons{:},i)=head(a.source);
				a.source=next(a.source);
			end
		end
	end

	methods (Static)
		function f=truncate, f=@(buf,i,colons)[]; end
		function f=append,   f=@(buf,i,colons)singleton(buf(colons{:},1:i)); end
		function f=pad(x),   f=@padfn;
			function s=padfn(buf,i,colons)
			L=size(buf,length(colons)+1); 
			buf(colons{:},i+1:L)=repmat(x,tosize([ones(size(colons)),L-i]));
				s=singleton(buf); 
			end
		end
	end
end

