function packed = pack_fields(unpacked,fnames,mode)

% PACK_FIELDS -- struct array w/ simple fields --> 1 struct w/ complex fields
%
%  packed = pack_fields(unpacked)
%  packed = pack_fields(unpacked,fnames)
%  packed = pack_fields(unpacked,fnames,mode)
%  packed = pack_fields(unpacked,[],mode)
%
%  UNPACKED is a structure array of N elements (e.g. one per subject).
%  If N==1 the UNPACKED structure is returned unchanged.
%  FNAMES must be a cell array of strings. When not supplied, it
%  defaults to FIELDNAMES(UNPACKED). 
%  MODE must be one of the following strings (default 'rows2rows'):
%    - 'rows2rows' -- row vectors from UNPACKED go to row vectors in PACKED
%    - 'rows2cols' -- rows go to columns in the PACKED matrices
%    - 'cols2rows' -- columns go to rows
%    - 'cols2cols' -- columns go to colums
%
%  PACKED is a single structure with fields listed in FNAMES.
%  For each field name, PACK_FIELDS does the following:
%    - If the filler of UNPACKED is a row-vector (for MODE='rows2xxx') 
%      or a column vector (for 'cols2xxx') then the filler of PACKED is
%      a matrix with N rows (for 'xxx2rows') or columns (for 'xxx2cols'),
%      one for each element of UNPACKED structure array. Note that the 
%      fillers of the UNPACKED structure must be of equal length.
%    - Otherwise the filler of PACKED is a cell array of size N-by-1
%      (for 'xxx2rows') or 1-by-N (for 'xxx2cols') containing the 
%      fillers of the corresponding UNPACKED elements.
%
%  There is one special case in which the output value is not a structure
%  but a matrix. This is when a single string (as opposed to a cell array
%  of strings) is passed as FNAMES. In this case the function returns
%  a matrix rather than a structure with a single field containing this
%  matrix.
%  
%  Example:
%    Let u(1).a=1;u(1).b=[11 21]; u(2).a=2;u(2).b=[12 22];
%    Then  pack_fields(unpacked) produces a single structure with fields:
%      a: [1      and    b: [11 21
%          2]                12 22]
%    Also  pack_fields(unpacked,'b')  produces the matrix  [11 21; 12 22]
%
%  See also UNPACK_FIELDS, SUMMARIZE, FULL_ANALYSIS, IS_ROW_VECTOR.

% Original coding by Alex Petrov, Ohio State University
% $Revision: 1.0 $  $Date: 2000/06/13 20:30 $
%
% Part of the utils toolbox version 1.1 for MATLAB version 5 and up.
% http://alexpetrov.com/softw/utils/
% Copyright (c) Alexander Petrov 1999-2006, http://alexpetrov.com
% Please read the LICENSE and NO WARRANTY statement in ../utils_license.m

%-- Check the special case N==1
N = length(unpacked) ;
if (N==1)
  packed = unpacked ;  % return unchanged
  return
end

%-- Initialize FNAMES if necessary
single_field = 0 ;
if (nargin < 2)
  fnames = fieldnames(unpacked) ;   % default
elseif (isempty(fnames))
  fnames = fieldnames(unpacked) ;   % default
elseif (ischar(fnames))             % single string?
  single_field = fnames ;
  fnames = {fnames} ;               % convert into a cell array
elseif (~iscellstr(fnames))
  error('FNAMES must be a cell array of strings.') ;
end

%-- Decipher MODE
if (nargin < 3)
  mode = 'rows2rows' ;              % default
end
switch lower(mode)
  case 'rows2rows'
    rows_in = 1 ;
    rows_out = 1 ;
    predicate = 'is_row_vector' ;
  case 'rows2cols'
    rows_in = 1 ;
    rows_out = 0 ;
    predicate = 'is_row_vector' ;
  case 'cols2rows'
    rows_in = 0 ;
    rows_out = 1 ;
    predicate = 'is_col_vector' ;
  case 'cols2cols'
    rows_in = 0 ;
    rows_out = 0 ;
    predicate = 'is_col_vector' ;
  otherwise
    warning('Unknown MODE method. Using ''rows2rows'' instead.') ;
    rows_in = 1 ;
    rows_out = 1 ;
    predicate = 'is_row_vector' ;
end

%-- Main work
packed = struct(fnames{1},[]) ;     % create an empty structure

for fn = 1:length(fnames)
  fname = fnames{fn} ;
  representative_filler = getfield(unpacked(1),fname) ;
  if (feval(predicate,representative_filler))  % is row/column vector?
    packed_filler = zeros(N,length(representative_filler)) ;
    if rows_in    % 'rows2xxx'
      for k = 1:N
        packed_filler(k,:) = getfield(unpacked(k),fname) ;
      end
    else          % 'cols2xxx'
      for k = 1:N
        packed_filler(k,:) = getfield(unpacked(k),fname)' ;
      end
    end
    if rows_out   % 'xxx2rows'
      packed = setfield(packed,fname,packed_filler) ;
    else
      packed = setfield(packed,fname,packed_filler') ;
    end
  else  % representative_filler is not a row/col vector
    packed_filler = cell(N,1) ;
    for k = 1:N
      packed_filler{k} = getfield(unpacked(k),fname) ;
    end
    packed = setfield(packed,fname,packed_filler) ;
  end
end

if (single_field)
  packed = getfield(packed,single_field) ;
end

%%  Return PACKED
%%%%%% End of file PACK_FIELDS.M
