function a_db = sum(a_db, dim, props)

% sum - Creates a tests_db by summing all rows.
%
% Usage:
% a_db = sum(a_db, dim, props)
%
% Description:
%   Applies the sum function to whole DB. The resulting DB will have one row.
%
%   Parameters:
%	a_db: A tests_db object.
%	props: Optional properties.
%		
%   Returns:
%	a_db: The resulting tests_db.
%
% See also: sum
%
% $Id$
%
% Author: Cengiz Gunay <cgunay@emory.edu>, 2006/05/24

% Copyright (c) 2007 Cengiz Gunay <cengique@users.sf.net>.
% This work is licensed under the Academic Free License ("AFL")
% v. 3.0. To view a copy of this license, please look at the COPYING
% file distributed with this software or visit
% http://opensource.org/licenses/afl-3.0.php.

if ~ exist('props', 'var')
  props = struct([]);
end

if ~ exist('dim', 'var')
  dim = 1;                              % rows
end

% Always do row-wise
order = 1:length(dbsize(a_db));
if dim ~= 1
  order(dim) = 1;
  order(1) = dim;
  data = permute(a_db.data, order);
else
  data = a_db.data;
end

% Allocate results array
db_size = size(data);
s = repmat(NaN, [1 db_size(2:end)]);

[s, n] = recsum(data, length(db_size));

if dim ~= 1
  s = ipermute(s, order);
end

a_db = set(a_db, 'data', s);

a_db = set(a_db, 'id', [ 'summed ' get(a_db, 'id') ]);
switch (dim)
  case 1
    a_db = set(a_db, 'row_idx', makeIdx({'sum'}));
  case 2
    a_db = set(a_db, 'col_idx', makeIdx({'sum'}));
end

% Recursive std needed for stripping NaNs in each dimension
% TODO: taken from mean, generalize it!
function [s, n] = recsum(data, dim)
  if dim == 1
    sdata = data(~isnan(data(:)) & ~isinf(data(:)));
    n = size(sdata, 1);
    if n == 0
      % If a divide by zero error occured, 
      % give it NaN value instead of an empty matrix.
      s = NaN;
    else
      s = sum(sdata, 1);
    end
  else
    for num=1:size(data, dim)
      % Otherwise recurse
      [dims{1:(dim-1)}] = deal(':');
      dims{dim} = num;
      [s(dims{:}) n(dims{:})] = recsum(data(dims{:}), dim - 1);
    end
  end