% PLIST2CMDS convert a plist to a set of commands.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: PLIST2CMDS convert a plist to a set of commands.
%
% CALL:        cmds = plist2cmds(pl)
%
% INPUTS:
%              pl  - parameter list (see below)
%
% OUTPUTS:     cell-array of MATLAB commands.
%
%
% VERSION:     $Id: plist2cmds.m,v 1.21 2011/03/28 12:45:31 hewitson Exp $
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function cmd = plist2cmds(varargin)
  
  %%% Check if this is a call for parameters
  if utils.helper.isinfocall(varargin{:})
    cmd = getInfo(varargin{3});
    return
  end
  
  pl = varargin{1};
  
  if numel(pl) ~= 1 || nargin ~= 1
    error('### Please input (only) one plist');
  end
  
  % look at the input parameters
  if isa(pl, 'plist')
    [ps, before_pl] = writePlist(pl);
  else
    ps = '';
    before_pl = '';
  end
  if strcmp(ps, 'plist([])')
    ps = '';
  end
  
  if ~isempty(ps)
    if ps(end) == ','
      ps = ps(1:end-1);
    end
  end
  cmd = sprintf('pl = %s;', ps);
  cmd = {cmd before_pl{:}};
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               Local Functions                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
% FUNCTION:    writePlist                                                     %
%                                                                             %
% DESCRIPTION: write a plist                                                  %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ps, before_pl] = writePlist(pls)
  
  before_pl = {};
  ps = '[';
  
  for pp=1:numel(pls)
    pl = pls(pp);
%     if pl.nparams > 0
      ps = [ps 'plist('];
      for i=1:pl.nparams
        p = pl.params(i);
        pVal = p.getVal;
        
        [cmd, pre_cmd] = val2cmd(pVal);
        
        before_pl = [before_pl pre_cmd];
        
        if isempty(p.desc)
          ps = sprintf('%s''%s'', %s, ', ps, p.key, cmd);
        else
          ps = sprintf('%s{''%s'', ''%s''}, %s, ', ps, p.key, p.desc, cmd);
        end
        
      end
      if strcmp(ps(end-1:end), ', ')
        ps = ps(1:end-2);
      end
      ps = [ps '), '];
%     end
  end
  if strcmp(ps(end-1:end), ', ')
    ps = [ps(1:end-2) ']'];
  end
  
end


function [cmd, pre_cmd] = val2cmd(pVal)
  pre_cmd = {};
  cmd = '';
  if ischar(pVal)
    %%%   char   %%%
    cmd = sprintf('''%s''', strrep(pVal, '''', ''''''));
    
  elseif isnumeric(pVal)
    %%%   numeric   %%%
    if isempty(pVal)
      cmd = '[]';
    else
      cmd = sprintf('[%s]', utils.helper.mat2str(pVal));
    end
    
  elseif islogical(pVal)
    %%%   logical   %%%
    cmd = sprintf('[%s]', mat2str(pVal));
    
  elseif isjava(pVal)
    %%%   java   %%%
    if strcmp(class(pVal), 'sun.util.calendar.ZoneInfo')
      cmd = sprintf('java.util.TimeZone.getTimeZone(''%s'')',char(pVal.getID));
    else
      error('### Unknown java object [%s]', class(pVal));
    end
    
  elseif isa(pVal, 'history') || isa(pVal, 'ltpda_uoh')
    %%%   history   %%%
    if isa(pVal, 'ltpda_uoh')
      h = [pVal(:).hist];
      h = reshape(h, size(pVal));
    else
      h = pVal;
    end
    
    varnames = '[';
    
    for vv1 = 1:size(h,1)
      for hh1 = 1:size(h,2)
        
        obj      = h(vv1,hh1);
        objpl    = hist2m(obj);
        objpl(1) = []; % drop last 'a_out' line
        pre_cmd  = [pre_cmd objpl];
        varnames = [varnames strtok(objpl{1})];
        if size(h,2) > 1 && hh1 ~= size(h,2)
          varnames = [varnames, ', '];
        end
      end
      if size(h,1) > 1 && vv1 ~= size(h,1)
        varnames = [varnames, '; '];
      end
    end
    
    cmd = [strtrim(varnames) ']'];
    
  elseif isa(pVal, 'ltpda_nuo')
    %%%   non-user object   %%%
    cmd = string(pVal);
    
  elseif isa(pVal, 'plist')
    %%%   plist object   %%%
    [cmd, pre_cmd] = writePlist(pVal);
    
  elseif isa(pVal, 'sym')
    %%%   symbolic math object   %%%
    cmd = sprintf('sym(''%s'')', char(pVal));
    
  elseif iscell(pVal)
    %%% Cell %%%
    if isempty(pVal)
      cmd = sprintf('cell(%d,%d)', size(pVal,1), size(pVal,2));
    else
      cmd = '{';
      
      for vv = 1:size(pVal,1)
        for hh = 1:size(pVal,2)
          [cell_cmd, cell_pre_cmd] = val2cmd(pVal{vv,hh});
          cmd = [cmd, cell_cmd];
          pre_cmd = [pre_cmd cell_pre_cmd];
          if size(pVal,2) > 1 && hh ~= size(pVal,2)
            cmd = [cmd, ', '];
          end
        end
        if size(pVal,1) > 1 && vv ~= size(pVal,1)
          cmd = [cmd, '; '];
        end
      end
      
      cmd = [strtrim(cmd) '}'];
    end
    
  elseif isstruct(pVal)
    %%% Struct %%%
    ss     = pVal;
    ss_str = '[';
    fields = fieldnames(ss);
    for oo = 1:numel(pVal)
      ss_str = sprintf('%s struct(', ss_str);
      for ii = 1:numel(fields)
        if isnumeric(ss(oo).(fields{ii})) || islogical(ss(oo).(fields{ii}))
          ss_str = sprintf('%s''%s'', [%s], ', ss_str, fields{ii}, utils.helper.mat2str(ss(oo).(fields{ii})));
        elseif ischar(ss(oo).(fields{ii}))
          ss_str = sprintf('%s''%s'', ''%s'', ',ss_str, fields{ii}, strrep(ss(oo).(fields{ii}), '''', ''''''));
        elseif isa(ss(oo).(fields{ii}), 'ltpda_nuo')
          ss_str = sprintf('%s''%s'', %s, ', ss_str, fields{ii}, string(ss(oo).(fields{ii})));
        elseif isa(ss(oo).(fields{ii}), 'plist')
          [struct_cmd, struct_pre_cmd] = writePlist(ss(oo).(fields{ii}));
          ss_str = sprintf('%s''%s'', %s, ', ss_str, fields{ii}, struct_cmd);
          pre_cmd = [pre_cmd struct_pre_cmd];
        elseif isa(ss(oo).(fields{ii}), 'ltpda_uoh')
          h = ss(oo).(fields{ii}).hist;
          varnames = '[';
          for kk=1:numel(h)
            obj       = h(kk);
            objpl = hist2m(obj);
            objpl(1) = []; % drop last 'a_out' line
            pre_cmd = [pre_cmd objpl];
            varnames = [varnames strtok(objpl{1}) ' '];
          end
          ss_str = sprintf('%s''%s'', %s, ', ss_str, fields{ii}, [strtrim(varnames) ']']);
        elseif isa(ss(oo).(fields{ii}), 'sym')
          symstr = char(ss(oo).(fields{ii}));
          ss_str = sprintf('%s''%s'', sym(''%s''), ', ss_str, fields{ii}, symstr);
        elseif isjava(ss(oo).(fields{ii}))
          if strcmp(class(ss(oo).(fields{ii})), 'sun.util.calendar.ZoneInfo')
            ss_str = sprintf('%s''%s'', java.util.TimeZone.getTimeZone(''%s''), ', ss_str, fields{ii}, char(getID(ss(oo).(fields{ii}))));
          else
            error('### Unknown java object [%s]', class(ss(oo).(fields{ii})));
          end
        else
          error('### Unknown type [%s] in struct', class(ss(oo).(fields{ii})));
        end
      end
      ss_str = [ss_str(1:end-2), ')'];
    end
    cmd = sprintf('%s]', ss_str);
  else
    error(['### unknown parameter type: ' p.key '  ' class(pVal)]);
  end
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION:    getInfo
%
% DESCRIPTION: Get Info Object
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function ii = getInfo(varargin)
  if nargin == 1 && strcmpi(varargin{1}, 'None')
    sets = {};
    pl   = [];
  else
    sets = {'Default'};
    pl   = getDefaultPlist;
  end
  % Build info object
  ii = minfo(mfilename, 'plist', 'ltpda', utils.const.categories.internal, '$Id: plist2cmds.m,v 1.21 2011/03/28 12:45:31 hewitson Exp $', sets, pl);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FUNCTION:    getDefaultPlist
%
% DESCRIPTION: Get Default Plist
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function plo = getDefaultPlist()
  plo = plist();
end

