## Copyright (C) 2017 Nicholas Jankowski
## 
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*- 
## @deftypefn {} {@var{a} =} struct2array (@var{s})
##
## Convert a structure, @var{s}, into a numeric array, @var{a}
##
## @code{struct2array} will attempt to horizontally concatenate the contents of 
## the input structure. It does this by first converting the structure to a cell
## array, and then concatenating the resulting cells into an array. 
##
## Arrays in each field must have the same number of elements in each dimension 
## except for dim2 (columns).
##
## @seealso{struct2cell, cell2struct, struct, fieldnames, }
## @end deftypefn

## Author: Nicholas Jankowski <jankowskin@asme.org>
## Created: 2017-03-23

function retval = struct2array (input_struct)
  ##input check
  if (~isstruct (input_struct) || (nargin ~= 1))
    print_usage;
  endif
  
  ##convert to cell array and flatten/concatenate output.
  retval = [ (struct2cell (input_struct)){:}];
endfunction

%!test
%! assert (struct2array (struct ('a', 1, 'b', 2)), [1, 2])
%! assert (struct2array (struct ('a', [1; 2], 'b', [3; 4])), [1, 3; 2, 4])
%! assert (struct2array (struct ('a', 'foo', 'b', 'bar')), 'foobar')
%! assert (struct2array (struct ('a', [])), [])
%! assert (struct2array (struct ('a', [], 'b', NaN)), NaN)

%!test
%! x.a = 1;
%! x.b = {'Cell', 'Array'};
%! x.c = 2;
%! rightans = {[1], 'Cell', 'Array', [2]};
%! assert (struct2array (x), rightans);

%!test
%! x(1,1).a = 1;
%! x(1,2).a = 2;
%! x(2,1).a = 3;
%! x(2,2).a = 4;
%! assert (struct2array (x), [1 3 2 4]);
%! assert (size(struct2array (x)), [1 4]);

%!test
%! x(1).a = 1;
%! x(3).a = 3;
%! assert (struct2array (x), [1 3]);
%! assert (size(struct2array (x)), [1 2]);

%!test
%! x(1,1).a = [1;2];
%! x(1,2).a = [3;4];
%! x(2,1).a = [5;6];
%! x(2,2).a = [7;8];
%! assert (struct2array (x), [1 5 3 7; 2 6 4 8]);
%! assert (size(struct2array (x)), [2 4]);


## Test input validation
%!error struct2array ()
%!error struct2array ([])
%!error struct2array(NaN)
%!error struct2array ([1 2])
%!error struct2array ({[1 2]})
%!error struct2array (struct ('foo', [1;2], 'bar', 3))
%!error struct2array (struct ('foo', [1;2], 'bar', 'blah'))
%!error struct2array (struct ('a', 1, 'b', magic (3)))

