function [ ret ] = nestedcellfun(varargin)
% ret = nestedcellfun(varargin)
% Wrapper function calling cellfun for each cell in a nested array
% [ret] = nestedcellfun(func, C1, C2, ..., [options] ) applies the function func(x1,x2,...) to the contents of each cell of cell array C1,C2,... .
%
% Input:
%   func                    function handle
%   C1,C2,                  cell arrays, nested cell arrays or matrix. All of the Ci must have the same topology.
%
% Options:
%   'UniformOutput',false   Then ret has the same topology as C1, otherwise (default) it is a matrix. Thus the default behaviour is the same as for cellfun.
%
% Output:
%   ret                     Either a scalar or something with the same topology as C1
%   
% Eg: nestedcellfun(@(x) ndimsm(x),{{[1 2 1]},[1 2; 2 3]},'UniformOutput',false)
%
% See also: flatten, unflatten
%
% Written by: tommsch, 2017

if(~iscell(varargin{2})); 
    varargin{2}=varargin(2); 
    nocell=1; 
else; 
    nocell=0; 
end;

[UniformOutput,varargin]=parsem('UniformOutput',varargin,true);
handle=varargin{1}; varargin(1)=[]; %the function handle

j=1;
C={};
Cf={};
while(j<=sizem(varargin,2) && iscell(varargin{j}))
    C{j}=varargin{j}; %#ok<AGROW>
    Cf{j}=flatten(varargin{j}); %#ok<AGROW>
    j=j+1;
end

if(isequal(UniformOutput,0) || strcmp(UniformOutput,'false'))
    UNFLAT=cellfun(handle,Cf{:},varargin{j:end},'UniformOutput',false);
    ret=unflatten(UNFLAT,C{1});
else
    ret=cellfun(handle,Cf{:},varargin{j:end});
end

if(nocell && ~UniformOutput); 
    ret=ret{1}; 
end;

end

function dummy; end %#ok<DEFNU> %Generates an error, if the 'end' of a function is missing. 