########################################################################
##
## Copyright (C) 2021 The Octave Project Developers
##
## See the file COPYRIGHT.md in the top-level directory of this
## distribution or <https://octave.org/copyright/>.
##
## This file is part of Octave.
##
## Octave 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.
##
## Octave 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 Octave; see the file COPYING.  If not, see
## <https://www.gnu.org/licenses/>.
##
########################################################################

## -*- texinfo -*-
## @deftypefn  {} {@var{r} =} convertContainedStringsToChars (@var{a})
## @deftypefnx {} {[@var{r1}, @var{r2}, @dots{}, @var{rn}] =} convertContainedStringsToChars (@var{a1}, @var{a2}, @dots{}, @var{an})
## Convert any string objects within an array into characters arrays.
##
## Like @code{convertCharsToStrings}, convert string scalars into character
## row vectors and string arrays into cell arrays of character row vectors, but
## also perform this conversion recursively within structure and cell arrays.
##
## This function can be used for compatibility with functions that make use of
## characters arrays or cell arrays of strings as input arguments but are not
## compatible with string objects.  For example:
##
## @example
## @group
## function example_function (a, b)
##   [a, b] = convertContainedStringsToChars (a, b);
##   ...
## endfunction
## @end group
## @end example
## or
## @example
## @group
## function varargout = example_function (varargin)
##   [vararging{1:nargin}] = convertContainedStringsToChars (varargin{:});
##   ...
## endfunction
## @end group
## @end example
##
## @seealso{convertStringsToChars, convertCharsToStrings}
## @end deftypefn

function varargout = convertContainedStringsToChars (varargin)

  if (! (nargin < 2 && ! nargout) && (nargin != nargout))
    error ("Mismatch between number of input and output arguments.");
  endif

  varargout = convert_strings_to_chars (varargin);

endfunction

function retval = convert_strings_to_chars (a)

  switch (class (a))
    case "struct"
      retval = structfun (@convert_strings_to_chars, a, "UniformOutput", false);

    case "cell"
      retval = cellfun (@convert_strings_to_chars, a, "UniformOutput", false);

    case "string"
      retval = convertStringsToChars (a);

    otherwise
      retval = a;
  endswitch

endfunction


%!test
%! convertContainedStringsToChars;
%! convertContainedStringsToChars ("Octave");

%!test
%! r = convertContainedStringsToChars ("Octave");
%! assert (ischar (r));
%! [r1, r2] = convertContainedStringsToChars ("GNU", "Octave");
%! assert (ischar (r1));
%! assert (ischar (r2));

%!test
%! a = {"Octave 5.1", 2019; ["Octave 5.2", "Octave 6.1"], 2020};
%! r = convertContainedStringsToChars (a);
%! assert (ischar (r{2,1}));

%!test
%! a = struct ("key", "Octave 5.1", "value", 2019);
%! r = convertContainedStringsToChars (a);
%! assert (ischar (r.key));
%! a(2) = struct ("key", "Octave 5.2", "value", 2020);
%! r = convertContainedStringsToChars (a);
%! assert (ischar (r(1).key));
%! assert (ischar (r(2).key));

%!test
%! a1 = {"Octave 5.1", 2019; ["Octave 5.2", "Octave 6.1"], 2020};
%! a2 = struct ("key", "Octave 5.1", "value", 2019);
%! [r1, r2] = convertContainedStringsToChars (a1, a2);
%! assert (ischar (r1{2,1}));
%! assert (ischar (r2.key));

%!test
%! a = containers.Map ({"Octave 5.1", "Octave 5.2"}, [2019, 2020]);
%! r = convertContainedStringsToChars (a);
%! assert (isa (r, "containers.Map"));

%!error r = convertContainedStringsToChars;
%!error r = convertContainedStringsToChars ("GNU", "Octave");
%!error [r1, r2] = convertContainedStringsToChars ("Octave");
