function arrMean = slarrmean(data, arrsiz, n, varargin)
%SLARRMEAN Computes the mean of a set of arrays
%
% $ Syntax $
%   - slarrmean(arrs, arrsiz, n, ...)
%   - slarrmean(fns, arrsiz, n, ...)
%
% $ Arguments $
%   - arrs:         the super-array consisting of all arrays
%   - fns:          the file paths of all array files
%   - arrsiz:       the size of each array unit. (for a column vector, it
%                   is the length of the vector)
%   - n:            the total number of array units
%
% $ Description $
%   - slarrmean(arrs, arrsiz, n, ...) computes the mean of all array units
%     with the size of each unit specified by arrsiz. If there are more 
%     than one array unit, the size of arrs should be [arrsiz, n].
%
%   - slarrmean(fns, arrsiz, n, ...) computes the mean of all array units
%     stored in the array files given in fns. Each array file stores
%     an super-array of a set of array units.
%
%   - You can specify additional properties.
%       \t      The properties of slarrmean
%       \h      name       &        description
%              'weights'   &  The weights of each array unit, default = []
%             
% $ History $
%   - Created by Dahua Lin on Jul 27th, 2006
%

%% parse and verify input arguments

if nargin < 3
    raise_lackinput('slarrmean', 3);
end
    
if isnumeric(data)
    isdirect = true;
    arrs = data;
    arrsiz = arrsiz(:)';
    if ~isequal(size(arrs), [arrsiz, n])
        error('sltoolbox:sizmismatch', ...
            'The size of arrs (data) is invalid');
    end
    
elseif iscell(data)
    isdirect = false;
    fns = data;
    arrsiz = arrsiz(:)';
    nfiles = numel(fns);
    
else
    error('sltoolbox:invalidarg', ...
        'The first argument for slarrmean should be an numeric array or a cell array of file names');
end

opts.weights = [];

opts = slparseprops(opts, varargin{:});
hasweights = ~isempty(opts.weights);

if (hasweights)
    opts.weights = opts.weights(:);
    if length(opts.weights) ~= n
        error('sltoolbox:invalidarg', ...
            'The length of weights is inconsistent with the number of units');
    end
end


%% Main skeleton

if isdirect
    arrMean = compute_array_sum(arrs, arrsiz, n, opts.weights);
else
    arrMean = zeros(arrsiz);
    c = 0;          
    for i = 1 : nfiles
        curarrs = slreadarray(fns{i});
        curn = size(curarrs, length(arrsiz) + 1);
        if ~hasweights
            arrMean = arrMean + compute_array_sum(curarrs, arrsiz, curn, []);
        else
            arrMean = arrMean + compute_array_sum(curarrs, arrsiz, curn, opts.weights(c+1:c+curn));
        end
        c = c + curn;
        
        if c > n
            error('sltoolbox:sizmismatch', ...
                'The total number of units in the set of array files is not n');
        end
    end
    
    if c ~= n
        error('sltoolbox:sizmismatch', ...
            'The total number of units in the set of array files is not n');
    end
    
end

if ~hasweights
    arrMean = arrMean / n;
else
    arrMean = arrMean / sum(opts.weights);
end



%% Compute function

function S = compute_array_sum(arrs, arrsiz, n, w)

if ~isequal(size(arrs), [arrsiz, n])
    error('sltoolbox:sizmismatch', ...
        'The size of array is not consistent as specified');
end

d = length(arrsiz);
if isempty(w)
    S = sum(arrs, d+1);
else
    S = reshape(arrs, [prod(arrsiz), n]) * w;
    if d == 1
        S = reshape(S, [arrsiz, 1]);
    else
        S = reshape(S, arrsiz);
    end
end










