% PLIST Plist class object constructor.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DESCRIPTION: PLIST Parameter-List Object class object constructor.
%              Create a plist object.
%
% SUPER CLASSES: ltpda_uo < ltpda_obj
%
% CONSTRUCTORS:
%
%       pl = plist()                     - create an empty plist object.
%       pl = plist(p)                    - create a plist with elements p
%                                          where p is an array of param objects.
%       pl = plist('key', val)           - create a plist with the key/value
%                                          pair
%       pl = plsit({'key', 'desc'}, val) - create a plist with the key/value
%                                          pair and a description for the 'key'
%       pl = plist('key1', val1, ...     - create a plist with more key/value
%                  'key2', val2, ...       pairs
%                  {'key3', 'desc'}, 'val3)
%       pl = plist({'a', 1, 'b', 2})     - create a plist from a cell
%       pl = plist('file.xml')           - load a plist-object from xml-file
%       pl = plist('file.mat')           - load a plist-object from mat-file
%       pl = plist(pl)                   - copies the input plist.
%
% PARAMETERS:
%
%  If no recognised parameters are found in the input plist, the input
%  plist is simply returned. This is the copy constructor.
%
% <a href="matlab:utils.helper.displayMethodInfo('plist', 'plist')">Parameters Description</a>
%
% VERSION:      $Id: plist.m,v 1.146 2011/08/15 05:58:04 hewitson Exp $
%
% SEE ALSO:     ltpda_obj, ltpda_uo, ltpda_uoh, param
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classdef plist < ltpda_uo
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                            Property definition                            %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  %---------- Public (read/write) Properties  ----------
  properties
  end
  
  %---------- Protected read-only Properties ----------
  properties (SetAccess = protected)
    params  = []; % list of param-objects
  end
  
  %---------- Removed properties ----------
  % We have to define the removed properties as hidden constants.
  % In case of backwards compatibility it is necessary to keep them because
  % MATLAB will read older MAT-files as structures which we have to convert
  % into an object if we make major change to a class.
  % For MATLAB is a major change if we remove a proeprty.
  properties (Constant = true, Hidden = true)
    creator = [];
    created = [];
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Check property setting                           %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                                Constructor                                %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods
    function pl = plist(varargin)
      
      import utils.const.*
      
      %%%%%%%%%%   Set dafault values   %%%%%%%%%%
      
      %%%%%%%%%%   Overwrite dafault name   %%%%%%%%%%
      pl.name = '';
      
      %%%%%%%%%%   Copy constructor   %%%%%%%%%%
      % Collect all plist objects
      [pls, invars, rest] = utils.helper.collect_objects(varargin(:), 'plist');
      
      if isempty(rest) && ~isempty(pls) && numel(pls) ~=1
        % Do copy constructor and return
        utils.helper.msg(msg.OPROC1, 'copy constructor');
        pl = copy(pls, 1);
        return
      end
      
      if nargin == 0
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%   no input   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%   pl = plist()   %%%%%%%%%%
        
      elseif nargin == 1
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%   one input   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
        if isa(varargin{1}, 'plist') && numel(varargin{1}) == 1
          %%%%%%%%%%  p = param(plist)   %%%%%%%%%%
          
          pli = varargin{1};
          
          if isempty(varargin{1}.params)
            %%% If the plist is empty then return an empty plist object
            
          else
            %%% Retrieve from repository?
            if pli.isparam('hostname') || pli.isparam('conn')
              utils.helper.msg(msg.OPROC1, 'retrieving from repository %s', pli.find('hostname'));
              pl = pl.fromRepository(pli);
            elseif pli.isparam('filename')
              utils.helper.msg(msg.OPROC1, 'constructing from filename');
              pl = pl.fromFile(pli);
            elseif pli.isparam('built-in')
              utils.helper.msg(msg.OPROC1, 'constructing from model');
              pl = pl.fromModel(pli);
            else
              utils.helper.msg(msg.OPROC1, 'copying from %s', varargin{1}.name);
              pl = copy(varargin{1}, 1);
            end
          end
          
        elseif ischar(varargin{1})
          %%%%%%%%%%% From file %%%%%%%%%%%%%%%%%%%%%%%%
          
          filename = varargin{1};
          utils.helper.msg(msg.OPROC1, 'constructing from file %s', filename);
          pl = fromFile(pl, filename);
          
        elseif isstruct(varargin{1})
          %%%%%%%%%%   pl = plist(struct)   %%%%%%%%%%
          
          utils.helper.msg(msg.OPROC1, 'constructing from struct');
          pl = fromStruct(pl, varargin{1});
          
        elseif isa(varargin{1}, 'param')
          %%%%%%%%%%   pl = plist(param)   %%%%%%%%%%
          
          utils.helper.msg(msg.OPROC1, 'constructing from param');
          pl.params = varargin{1};
          
        elseif iscell(varargin{1})
          %%%%%%%%%%   pl = plist({'a', 1, 'b', 2})   %%%%%%%%%%
          c = varargin{1};
          pl = plist(c{:});
          
        else
          error ('### unknown arguments to construct a parameter list')
        end
        
      elseif nargin == 2
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%   two inputs   %%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
        if (isa(varargin{1}, 'database') || isa(varargin{1}, 'mpipeline.repository.RepositoryConnection'))
          %%%%%%%%%%%   From DATABASE   %%%%%%%%%%%
          utils.helper.msg(msg.OPROC1, 'constructing from database object');
          pl = pl.fromRepository(plist('conn', varargin{1}, 'id', varargin{2}));
          
        elseif ischar(varargin{1})
          %%%%%%%%%%   pl = plist('key1', val1)   %%%%%%%%%%
          utils.helper.msg(msg.OPROC1, 'constructing from key/value pair');
          pl.params = param(varargin{1}, varargin{2});
          
        elseif iscell(varargin{1}) && numel(varargin{1}) == 2 && ~iscell(varargin{2})
          %%%%%%%%%%   pl = plist({'key', 'desc'}, val1)   %%%%%%%%%%
          utils.helper.msg(msg.OPROC1, 'constructing from [key,desc]/value pair');
          pl.params = param(varargin{1}{1}, varargin{2}, varargin{1}{2});
          
        elseif iscell(varargin{1}) && iscell(varargin{2})
          %%%%%%%%%%   pl = plist({'key', 'desc'}, {value, {options}, selection})   %%%%%%%%%%
          pl.params = param(varargin{1}, varargin{2});
          
        elseif isa(varargin{1}, 'org.apache.xerces.dom.DeferredElementImpl') && ...
            isa(varargin{2}, 'history')
          %%%%%%%%%%   obj = plist(DOM node, history-objects)   %%%%%%%%%%
          pl = fromDom(pl, varargin{1}, varargin{2});
          
        else
          error('### Unknown constructor method for two inputs.');
        end
        
      elseif nargin > 2
        
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%   more inputs   %%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        
        utils.helper.msg(msg.OPROC1, 'constructing from key/value pairs');
        
        %%%%%%%%%%   pl = plist('key1', val1,           'key2', val2 , ...) %%%%%%%%%%
        %%%%%%%%%%   pl = plist({'key1', 'desc'}, val1, 'key2', val2 , ...) %%%%%%%%%%
        param_list = [];
        argin  = varargin;
        while length(argin) >= 2
          key  = argin{1};
          val  = argin{2};
          desc = '';
          argin = argin(3:end);
          
          % It might be that the key is specified with a description
          if iscell(key) && numel(key) == 2
            desc = key{2};
            key  = key{1};
          end
          
          if ~isempty(param_list)
            found = any(strcmpi(key, {param_list(:).key}));
            if found
              error('### Do not use the same key [%s] twice.\n### REMARK: The key is not case sensitive.', key);
            end
          end
          % add to list
          if isempty(desc)
            param_list = [param_list param(key, val)];
          else
            param_list = [param_list param(key, val, desc)];
          end
        end
        pl.params  = param_list;
      else
        error('### Unknown number of constructor arguments.');
      end
      
    end % End constructor
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Methods (Static, Public)                         %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Static = true)
    
    function out = VEROUT()
      out = '$Id: plist.m,v 1.146 2011/08/15 05:58:04 hewitson Exp $';
    end
    
    function ii = getInfo(varargin)
      ii = utils.helper.generic_getInfo(varargin{:}, 'plist');
    end
    
    function mdls = getBuiltInModels(varargin)
      mdls = ltpda_uo.getBuiltInModels('plist');
    end
    
    function out = SETS()
      out = SETS@ltpda_uo;
    end
    
    function plout = getDefaultPlist(set)
      persistent pl;
      persistent lastset;
      if exist('pl', 'var')==0 || isempty(pl) || ~strcmp(lastset, set)
        pl = plist.buildplist(set);
        lastset = set;
      end
      plout = pl;
    end
    
    varargout = getDefaultAxisPlist(varargin);
    
    function out = buildplist(set)
      
      if ~utils.helper.ismember(lower(plist.SETS), lower(set))
        error('### Unknown set [%s]', set);
      end
      
      out = plist();
      out = buildplist@ltpda_uo(out, set);
      
      switch lower(set)
        % No special sets are dfined.
      end
    end
    
    %---------- static factory plists
    
    % Plist to construct objects from a plist
    function pl = FROM_PLIST
      pl = plist();
      p = param({'Plist','A plist'}, plist);
      pl.append(p);
    end
    
    % Plist to construct an object from a built-in model
    function pl = FROM_BUILT_IN
      pl = plist();
      p = param({'built-in', 'Choose one of the built-in models. (use <i>class</i>.getBuiltInModels to get a list for a particular user class)'}, paramValue.EMPTY_STRING);
      pl.append(p);
    end
    
    % Plist to read from an XML file.
    function pl = FROM_XML_FILE
      pl = plist();
      p = param({'filename','XML filename.'},  paramValue.EMPTY_STRING);
      pl.append(p);
    end
    
    % Plist to read from an XML file.
    function pl = FROM_MAT_FILE
      pl = plist();
      p = param({'filename','MAT filename.'},  paramValue.EMPTY_STRING);
      pl.append(p);
    end
    
    % Plist for retrieving objects from a repository. This is used in all
    % user-object constructor default plists for the 'From Repository' set.
    function pl = FROM_REPOSITORY_PLIST
      pl = plist();
            
      % Hostname
      p = param({'hostname','The repository hostname'},  paramValue.EMPTY_STRING);
      pl.append(p);
      
      % ID
      p = param({'ID','A vector of object IDs.'}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % CID
      p = param({'CID','A vector of collection IDs.'}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % Database
      p = param({'database','The database name.'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Binary
      p = param({'Binary','<html>Set to ''yes'' to retrieve from<br>stored binary representation (not always available).</html>'},...
        paramValue.YES_NO);
      pl.append(p);
      
      % Username
      p = param({'Username', 'Specify a username to connect with. Leave blank to be prompted.'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Password
      p = param({'Password', 'Specify a password to connect with. Leave blank to be prompted.'}, paramValue.EMPTY_STRING);
      pl.append(p);
    end
    
    % Plist for submitting/updating objects from a repository. This is used
    % in ltpda_uo/ -submit, -bsubmit and -update.
    function pl = TO_REPOSITORY_PLIST
      pl = plist();
      
      % Hostname
      p = param({'hostname', 'Repository server hostname'},  paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Database
      p = param({'database', 'Database name'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Username
      p = param({'username', 'User name to access the repository'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Password
      p = param({'password', 'Password'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % experiment title
      p = param({'experiment title', 'Title for the submission'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % experiment description
      p = param({'experiment description', 'Description of this submission'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % analysis description
      p = param({'analysis description', 'Description of the analysis performed'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % quantity
      p = param({'quantity', 'Physical quantity represented by the data'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % keywords
      p = param({'keywords', 'Comma-delimited list of keywords'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % reference ids
      p = param({'reference ids', 'Comma-delimited list of object IDs'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % additional comments
      p = param({'additional comments', 'Additional comments'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % additional authors
      p = param({'additional authors', 'Additional author names'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      p = param({'no dialog', 'Do not use of the submission form. Mandatory fields must be supplied in the plist.'}, paramValue.FALSE_TRUE);
      pl.append(p);
      
    end
    
    % Plist for Welch-based, linearly spaced spectral estimators.
    % This is used in psd, cpsd, cohere, tfe
    function pl = WELCH_PLIST
      pl = plist();
      
      % Nfft
      p = param({'Nfft',['The number of samples in each fft [default: length of input data]. <br>', ...
        'A string value containing the variable ''fs'' can also be used, e.g., <br> ', ...
        '<tt>plist(''Nfft'', ''2*fs'')</tt>']}, paramValue.DOUBLE_VALUE(-1));
      pl.append(p);
      
      % Win
      p = param({'Win',['The window to be applied to the data to remove the ', ...
        'discontinuities at edges of segments. [default: taken from user prefs] <br>', ...
        'Only the design parameters of the window object are used. Enter ', ...
        'a string value containing the window name e.g.<br>', ...
        '<tt>plist(''Win'', ''Kaiser'', ''psll'', 200)</tt><br>', ...
        '<tt>plist(''Win'', ''BH92'')</tt>']}, paramValue.WINDOW);
      pl.append(p);
      
      % Psll
      p = param({'Psll',['The peak sidelobe level for Kaiser windows.<br>', ...
        'Note: it is ignored for all other windows']}, paramValue.DOUBLE_VALUE(200));
      pl.append(p);
      
      % Olap
      p = param({'Olap','The segment percent overlap [-1 == take from window function]'}, {1, {-1}, paramValue.OPTIONAL});
      pl.append(p);
      
      % Order
      p = param({'Order',['The order of segment detrending:<ul>', ...
        '<li>-1 - no detrending</li>', ...
        '<li>0 - subtract mean</li>', ...
        '<li>1 - subtract linear fit</li>', ...
        '<li>N - subtract fit of polynomial, order N</li></ul>']}, paramValue.DETREND_ORDER);
      p.val.setValIndex(2);
      pl.append(p);
      
      % Navs
      p = param({'Navs',['Force number of averages. If set, and if Nfft was set to 0 or -1,<br>', ...
        'the number of points for each window will be calculated to match the request.']}, paramValue.DOUBLE_VALUE(-1));
      pl.append(p);
      
      % Times
      p = param({'Times',['The time range to analyze. If not empty, sets the time interval to operate on.<br>', ...
        'As in ao/split, the interval can be specified by:<ul>' ...
        '<li>a vector of doubles</li>' ...
        '<li>a timespan object</li>' ...
        '<li>a cell array of time strings</li>' ...
        '<li>a vector of time objects</li></ul>' ...
        ]}, paramValue.DOUBLE_VALUE([]));
      pl.append(p);
      
      % Split: the same as 'times'
      p = p.copy(true);
      pl.append(p.setKey('Split'));
      
    end
    
    % Plist for Welch-based, log-scale spaced spectral estimators.
    % This is used in lpsd, lcpsd, lcohere, ltfe
    function pl = LPSD_PLIST
      pl = plist();
      
      % Kdes
      p = param({'Kdes', 'The desired number of averages.'}, {1, {100}, paramValue.OPTIONAL});
      pl.append(p);
      
      % Jdes
      p = param({'Jdes', 'The desired number of spectral frequencies to compute.'}, {1, {1000}, paramValue.OPTIONAL});
      pl.append(p);
      
      % Lmin
      p = param({'Lmin', 'The minimum segment length.'}, {1, {0}, paramValue.OPTIONAL});
      pl.append(p);
      
      % Win
      p = param({'Win',['The window to be applied to the data to remove the ', ...
        'discontinuities at edges of segments. [default: taken from user prefs] <br>', ...
        'Only the design parameters of the window object are used. Enter ', ...
        'a string value containing the window name e.g.<br>', ...
        '<tt>plist(''Win'', ''Kaiser'', ''psll'', 200)</tt><br>', ...
        '<tt>plist(''Win'', ''BH92'')</tt>']}, paramValue.WINDOW);
      pl.append(p);
      
      % Psll
      p = param({'Psll',['The peak sidelobe level for Kaiser windows.<br>', ...
        'Note: it is ignored for all other windows']}, paramValue.DOUBLE_VALUE(200));
      pl.append(p);
      
      % Olap
      p = param({'Olap','The segment percent overlap [-1 == take from window function]'}, {1, {-1}, paramValue.OPTIONAL});
      pl.append(p);
      
      % Order
      p = param({'Order',['The order of segment detrending:<ul>', ...
        '<li>-1 - no detrending</li>', ...
        '<li>0 - subtract mean</li>', ...
        '<li>1 - subtract linear fit</li>', ...
        '<li>N - subtract fit of polynomial, order N</li></ul>']}, paramValue.DETREND_ORDER);
      p.val.setValIndex(2);
      pl.append(p);
      
      % Times
      p = param({'Times',['The time range to analyze. If not empty, sets the time interval to operate on.<br>', ...
        'As in ao/split, the interval can be specified by:<ul>' ...
        '<li>a vector of doubles</li>' ...
        '<li>a timespan object</li>' ...
        '<li>a vector of time objects</li></ul>' ...
        ]}, paramValue.DOUBLE_VALUE([]));
      pl.append(p);
      
      % Split: the same as 'times'
      p = p.copy(true);
      pl.append(p.setKey('Split'));

    end
    
    % Plist for linear fitting methods
    % This is used in linfit, polynomfit
    
    function pl = LINEAR_FIT_PLIST
      pl = plist();
      
      % dy
      p = param({'dy', ['Uncertainty on Y. Can be expressed as<ul>' ...
        '<li>an AO with single value or</li>' ...
        '<li>an AO with a vector of the right lenght or</li>' ...
        '<li>a double or</li>' ...
        '<li>an array of double of the right lenght</li></ul>' ]}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % dx
      p = param({'dx', ['Uncertainty on X(1..N). Can be expressed as<ul>' ...
        '<li>an AO with single value or</li>' ...
        '<li>an AO with a vector of the right lenght or</li>' ...
        '<li>a double or</li>' ...
        '<li>an array of double of the right lenght</li></ul>' ]}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % p0
      p = param({'p0', ['Initial guess of the fit parameters. Can be expressed as:<ul>' ...
        '<li>an AOs with a vector</li>' ...
        '<li>an array of scalars or</li>' ...
        '<li>a pest object</li></ul>']}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
    end
    
    % Plist for multilinear fitting methods
    % This is used in bilinfit
    
    function pl = MULTILINEAR_FIT_PLIST
      pl = plist();
      
      % dy
      p = param({'dy', ['Uncertainty on Y. Can be expressed as<ul>' ...
        '<li>an AO with single value or</li>' ...
        '<li>an AO with a vector of the right lenght or</li>' ...
        '<li>a double or</li>' ...
        '<li>an array of double of the right lenght</li></ul>' ]}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % dx
      p = param({'dx', ['Uncertainty on X1 ... XN. Can be expressed as<ul>' ...
        '<li>an array of N AOs with single value or</li>' ...
        '<li>an array of N AOs with data vectors of the right lenght or</li>' ...
        '<li>an array of N double</li></ul>' ]}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % p0
      p = param({'p0', ['Initial guess of the fit parameters. Can be expressed as:<ul>' ...
        '<li>an AOs with a vector</li>' ...
        '<li>an array of scalars or</li>' ...
        '<li>a pest object</li></ul>']}, ...
        paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
    end
    
    % Plist for multichannel fitting methods
    % This is used in linfitsvd, mcmc, and tdfit
    
    function pl = MCH_FIT_PLIST
      pl = plist();
      
      % Model
      p = param({'Model','System model. It have to be parametric. A matrix of smodel objects or a ssm object'}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % Input Names
      p = param({'InNames','A cell array containing cell arrays of the input ports names for each experiment. Used only with ssm models.'}, {});
      pl.append(p);

      % Output Names
      p = param({'OutNames','A cell array containing cell arrays of the output ports names for each experiment. Used only with ssm models.'}, {});
      pl.append(p);
      
      % Fit Params
      p = param({'FitParams','A cell array with the names of the fit parameters'}, {});
      pl.append(p);
      
      % Injected Signals
      p = param({'Input','Collection of input signals'},paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
    end
    
    % Plist for time series
    % This is used in ao constructor
    function pl = TSDATA_PLIST
      pl = plist();
      % Fs
      p = param({'fs', 'The sampling frequency of the signal. [for all]'}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % Nsecs
      p = param({'nsecs', 'The number of seconds of data. [for all]'}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      % Xunits
      p = param({'xunits','Unit on X axis.'},  paramValue.STRING_VALUE('s'));
      pl.append(p);

      % T0
      p = param({'T0', 'The UTC time of the first sample. [for all]'}, {1, {'1970-01-01 00:00:00.000'}, paramValue.OPTIONAL});
      pl.append(p);

      % toffset
      p = param({'toffset', 'The offset between the first x sample and t0.'}, paramValue.DOUBLE_VALUE(0));
      pl.append(p);
    end
    
    % Plist for dotview methods (ltpda_uoh, ssm)
    function pl = DOTVIEW_PLIST
      pl = plist();
      
      % Filename
      p = param({'filename','the file name for the graphic file'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % View
      p = param({'view','true or false to view or not'}, paramValue.TRUE_FALSE);
      p.val.setValIndex(1);
      pl.append(p);
      
    end
    
    % Plist for saving objects
    function pl = SAVE_OBJ_PLIST
      pl = plist();
      
      % Filename
      p = param({'filename',['Name of the file to save in.<br>', ...
        'The format is determined based on the file extension:<ul>', ...
        '<li>.xml for XML format</li>', ...'
        '<li>.mat for Matlab format</li></ul>']}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Filename prefix
      p = param({'prefix', 'Filename prefix'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Filename postfix
      p = param({'postfix', 'Filename postfix'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
      % Individual Files
      p = param({'individual files', 'Save the objects into Individual files'}, paramValue.FALSE_TRUE);
      pl.append(p);
      
    end
    
    function pl = AXIS_3D_PLIST
      pl = plist();
      p = param({'axis', 'The axis on which to apply the method.'},  ...
        {3, {'x', 'y', 'z', 'xyz'}, paramValue.SINGLE});
      pl.append(p);
      
      p = param({'dim', ['The dimension of the chosen vector to apply the method '...
        'to. This is necessary for functions like mean() when ' ...
        'applied to matrices held in cdata objects. For tsdata, '...
        'fsdata or xydata, this option has no effect.']}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      p = param({'option', 'Any additional option to pass to the method.'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
    end
    
    function pl = AXIS_2D_PLIST
      pl = plist();
      p = param({'axis', 'The axis on which to apply the method.'},  ...
        {2, {'x', 'y', 'xy'}, paramValue.SINGLE});
      pl.append(p);
      
      p = param({'dim', ['The dimension of the chosen vector to apply the method '...
        'to. This is necessary for functions like mean() when ' ...
        'applied to matrices held in cdata objects. For tsdata, '...
        'fsdata or xydata, this option has no effect.']}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      p = param({'option', 'Any additional option to pass to the method.'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
    end
    
    function plout = EMPTY_PLIST
      persistent pl;
      if ~exist('pl', 'var') || isempty(pl) || pl.nparams>0
        pl = plist();
      end
      plout = pl;
    end
    
    function pl = AXIS_1D_PLIST
      pl = plist();
      p = param({'axis', 'The axis on which to apply the method.'},  ...
        {1, {'y'}, paramValue.SINGLE});
      pl.append(p);
      
      p = param({'dim', ['The dimension of the chosen vector to apply the method '...
        'to. This is necessary for functions like mean() when ' ...
        'applied to matrices held in cdata objects. For tsdata, '...
        'fsdata or xydata, this option has no effect.']}, paramValue.EMPTY_DOUBLE);
      pl.append(p);
      
      p = param({'option', 'Any additional option to pass to the method.'}, paramValue.EMPTY_STRING);
      pl.append(p);
      
    end
    
    function obj = initObjectWithSize(n,m)
      obj = plist.newarray([n m]);
    end
    
    varargout = ltp_parameters(varargin)
    
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                         Methods (static, hidden)                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Static = true, Hidden = true)
    varargout = loadobj(varargin)
    varargout = update_struct(varargin)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Methods (Private)                                %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Access = private)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                          Methods (Hidden)                                 %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  methods (Hidden = true)
    varargout = sort(varargin)
    varargout = applyDefaults(varargin)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                              Methods (public)                             %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods
    %%% Define Abstract methods
    varargout = char(varargin)
    varargout = copy(varargin)
    varargout = display(varargin)
    varargout = string(varargin)
    
    %%% Define other methods
    varargout = append(varargin)
    varargout = combine(varargin)
    varargout = find(varargin)
    varargout = isparam(varargin)
    varargout = nparams(varargin)
    varargout = pset(varargin)
    varargout = remove(varargin)
    
    
    varargout = setDescriptionForParam(varargin)
    varargout = setDefaultForParam(varargin)
    varargout = setOptionsForParam(varargin)
    varargout = setSelectionForParam(varargin)
    
    varargout = getOptionsForParam(varargin)
    varargout = getSelectionForParam(varargin)
    varargout = getDescriptionForParam(varargin)
    varargout = getKeys(varargin)
    
    varargout = setPropertyForKey(varargin)
    varargout = getPropertyForKey(varargin)
    
  end
  
  methods (Hidden = true)
    varargout = attachToDom(varargin)
  end
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %                              Methods (protected)                          %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  methods (Access = protected)
    varargout = fromRepository(varargin)
    varargout = fromFile(varargin)
    varargout = fromStruct(varargin)
    varargout = fromDom(varargin)
    varargout = processSetterValues(varargin)
  end
  
end % Class


