function varargout = UTN_repo_test_func(varargin)
  
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % DESCRIPTION: UTN_REPO_TEST_FUNC Tests the submit and retrieve of LTPDA objs in
  % the AEI LTPDA database, from UTN, measuring the submit/retrieve time.
  %
  % CALL:        s =  UTN_repo_test_func(pl)
  %
  % INPUTS:      pl - parameter list(s)
  %
  % OUTPUTS:     s  - a struct containing the results of the test. In detail:
  %
  %              ret_time    - time for retrieval (s)
  %              sub_time    - time for submission (s)
  %              t           - absolute time of test execution
  %              test_ID     - test identifier, also repeated in saved file
  %              status      - result of comparison between submitted and
  %                            retrieved objs
  %              OBJids      - submitted objs IDs assigned by database
  %              cid         - submitted objs collection ID assigned by database
  %              start_time  - beginning time of test execution
  %              stop_time   - ending time of test execution
  %              obj_size    - length (in s) of submitted tsdata AO (if applicable)
  %              sinfo       - a struct with infos about the connection
  %
  % PARAMETER LIST:
  % <key>            <default value>             <description>
  % 'N_OBJ'           1               produces N_OBJ objects at a time.
  %                                   Insert 0 for random number of objects
  % 'OBJ_TYPE         'ao'            defines the object(s) to produce
  %                                   If empty or 'RAND', it will pick at random within
  %                                   the ltpda_uo class
  % 'NSECS'           100             sets time series lenght for aos
  % 'FS'              10              sets time series sampling frequency for aos
  % 'SUBMIT'          false           actually performs the submit/retrieve test
  % 'CONN'            empty           a conn struct if the connection was
  %                                   already open (for group tests)
  % 'HOSTNAME'        '130.75.117.67' the repository host IP (for individual tests)
  % 'DBASE'           'ltpda_test'    the database name (for individual tests)
  % 'COLL_RETRIEVE'   false           retrieves via the submitted collection ID
  % 'SAVE_OBJS'       false           saves the first produced obj
  % 'OBJ_FILENAME'    'submit_trial_ao.xml'  filename to save first produced obj
  % 'SAVE_RESULTS'    true            saves the individual test results
  % 'RESULTS_FILENAME' 'repo_test_UTN'        filename to save results in
  %
  % VERSION:     $Id: UTN_repo_test_func.m,v 1.14 2008/11/18 17:29:40 mauro Exp $
  %
  % HISTORY:     23-11-2007 M Hueller
  %                 Creation
  %              18-11-2008 M Hueller
  %                 Formatted for OO toolbox
  %                 Default plist extended
  %
  % M-FILE INFO: Get information about this methods by calling
  %              >> ao.getInfo('UTN_repo_test_func')
  %
  %              Get information about a specified set-plist by calling:
  %              >> ao.getInfo('UTN_repo_test_func', 'None')
  %
  % SEE ALSO: run_UTN_repo_test
  %
  % SEE: <a href="matlab: help ao/Contents;">HELP: All Analysis Object Functions:</a>
  %      <a href="matlab: helpwin ao/Contents;">DOC: All Analysis Object Functions:</a>
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  
  
  %% Check if this is a call for parameters
  if utils.helper.isinfocall(varargin{:})
    varargout{1} = getInfo(varargin{3});
    return
  end
  
  % Collect input variable names
  in_names = cell(size(varargin));
  for ii = 1:nargin
    in_names{ii} = inputname(ii);
  end
  
  % Collect all plists
  pls             = utils.helper.collect_objects(varargin(:), 'plist', in_names);
  
  %% ---------------- Produce one plist
  if isa(pls, 'plist')
    pls = combine(pls, getDefaultPL());
  else
    pls = getDefaultPL();
  end
  
  
  %% ---------------- Gathers the settings
  % Number of submitted objects during the test
  N_OBJ = find(pls, 'N_OBJ');
  
  if N_OBJ < 1
    % Pick a random rumber between 1 and 5
    N_OBJ = randsample(5,1);
  end
  
  % Collects the conn struct. If empty, the test is individual, with
  % connection opened and closed
  conn = find(pls, 'conn');
  if isempty(conn)
    single_conn = true;
  else
    single_conn = false;
  end
  
  %% Builds the trial objects
  
  objs = {};
  obj_type = find(pls, 'obj_type');
  user_class_list = utils.helper.ltpda_userclasses;
  
  if strcmpi(obj_type, 'RAND') || isempty(obj_type)
    % Empty class name or explicitely asked random value
    rand_type = true;
  else
    % Checks if user entered a user class name
    chk_ind = false;
    for kk = 1:length(user_class_list)
      if strcmpi(user_class_list{kk}, obj_type)
        chk_ind = true;
      end
    end
    
    % Invalid class name, go for random
    if ~chk_ind
      disp('Invalid object type, picking up random')
      rand_type = true;
    else
      rand_type = false;
    end
  end
  
  for kk = 1:N_OBJ
    if rand_type
      % Picks up at random one user class name
      index = ceil(length(user_class_list)*rand(1));
      obj_type = user_class_list{index};
    end
    
    % Test ID based on time elapsed since a reference time
    ref_time = time('2008-01-01 00:00:00');
    test_ID = floor(time - ref_time);
    
    switch obj_type
      case 'ao'
        % Makes the trial object(s)
        nsecs = find(pls, 'NSECS');
        fs    = find(pls, 'FS');
        f_m = 0.01;
        phi = 0;
        noise_type = 'Normal';
        
        pl_w = plist('fs', fs, 'nsecs', nsecs, ...
          'waveform', 'sine wave','f', f_m, 'phi', phi, 'test_ID', test_ID);
        pl_n = plist('fs', fs, 'nsecs', nsecs, ...
          'waveform', 'noise', 'type', noise_type, 'test_ID', test_ID);
        
        % Puts the trial object(s) in a cell array
        objs{kk} = ao(pl_w) + ao(pl_n);
        
      case 'plist'
        % Puts the trial object(s) in a cell array
        objs{kk} = plist('a', 'val', 'b', 3);
        
      case 'mfir'
        pl_f = plist('type', 'lowpass', 'order', 1, 'gain', 2.0, ...
          'fs', 10, 'fc', 0.2);
        % Puts the trial object(s) in a cell array
        objs{kk} = mfir(pl_f);
        
      case 'miir'
        pl_f = plist('type', 'lowpass', 'order', 1, 'gain', 2.0, ...
          'fs', 10, 'fc', 0.2);
        % Puts the trial object(s) in a cell array
        objs{kk} = miir(pl_f);
        
      case 'pzmodel'
        pl_pzm = plist('gain', 1, ...
          'poles', [pz(1) pz(2,10)], 'zeros', [pz(4.3)]);
        % Puts the trial object(s) in a cell array
        objs{kk} = pzmodel(pl_pzm);
        
      case 'timespan'
        t1 = time();
        % Puts the trial object(s) in a cell array
        objs{kk} =  timespan(t1, t1 + 100);
        
      case 'ssm'
        pl_ssm = plist('built-in', 'Interferometer_readout');
        % Puts the trial object(s) in a cell array
        objs{kk} =  ssm(pl_ssm);
        
      case 'parfrac'
        % A small example from help
        % Puts the trial object(s) in a cell array
        %       objs{kk} = parfrac([1 2], {4, [6 2]}, []);
        disp('For the time being, use a timespan obj rather than parfrac')
        t1 = time();
        objs{kk} =  timespan(t1, t1 + 100);
        
      case 'rational'
        % A small example from help
        % Puts the trial object(s) in a cell array
        %       objs{kk} = rational([1 2], [6 2]);
        disp('For the time being, use a timespan obj rather than rational')
        t1 = time();
        objs{kk} =  timespan(t1, t1 + 100);
        
      otherwise
        disp(['Object ' obj_type ' not coded already, use timespan instead'])
        t1 = time();
        % Puts the trial object(s) in a cell array
        objs{kk} =  timespan(t1, t1 + 100);
    end
  end
  
  
  %% Executes the submit/retrieve test
  if find(pls, 'SUBMIT')
    
    start_time = now;
    
    disp(' ')
    disp(sprintf('*===== Test %d =========', test_ID))
    disp(' ')
    
    % Connection
    if single_conn
      
      % Get the hostname
      hostname = find(pls, 'hostname');
      
      % Get the database name
      database_name = find(pls, 'dbase');
      
      % Opens the connection
      conn = utils.mysql.connect(hostname, database_name);
    end
    
    % Submission and retrieval
    results = submitretrieve(conn, objs, test_ID, find(pls, 'coll_retrieve'));
    
    if single_conn
      % Close connection
      close(conn);
    end
    
    % Includes time for start and stop in serial form
    stop_time = now;
    results.start  = start_time;
    results.stop   = stop_time;
    if exist('fs','var') && exist('nsecs','var')
      results.obj_size = nsecs * fs;
    else
      results.obj_size = 0;
    end
    
    if find(pls, 'save_results')
      % Saves the test results
      save([find(pls,'results_filename') '_' num2str(test_ID) '.mat'], 'results');
    end
    
    varargout{1} = results;
  else
    varargout{1} = struct();
  end
  
  %% Saves on disk the first trial data object, for future comparison
  if find(pls,'save_objs')
    save(objs{1}, find(pls,'obj_filename'));
  end
end

%--------------------------------------------------------------------------
% Executes the submit/receive actions
%--------------------------------------------------------------------------
function sr_report = submitretrieve(conn, sub_obj, test_ID, coll_retr)
  
  % Get the current time
  t1 = char(time());
  
  % Put togehter the information struct
  sinfo.conn                   = conn;
  sinfo.username               = conn.username;
  sinfo.experiment_title       = ['Repository Test from UTN ' t1(1:10)];
  sinfo.experiment_description = sprintf('Submit/retrieve test # %d', test_ID);
  sinfo.analysis_description   = 'Nothing serious, just playing with submit and retrieve';
  sinfo.quantity               = 'none';
  sinfo.keywords               = 'none';
  sinfo.reference_ids          = '';
  sinfo.additional_comments    = 'Trial data for submission and retrieval';
  sinfo.additional_authors     = 'M Hewitson';
  
  
  % Submit the object
  tic;
  [OBJids, cid] = submit(sub_obj{:}, sinfo);
  st = toc;
  
  % Retrieve the object(s)
  if coll_retr
    % Retrieve the object(s) by collection ID
    disp(['Retrieve object with collection ID ' num2str(cid)]);
    tic;
    ret_obj = ltpda_uo.retrieve(conn, 'Collection', cid);
  else
    % retrieve the object(s) by obj IDs
    disp(['Retrieve object with obj ID ' num2str(OBJids)]);
    tic;
    ret_obj = ltpda_uo.retrieve(conn, OBJids);
  end
  
  % Single retrieval will give an object, not a cell array
  if ~isa(ret_obj, 'cell')
    ret_obj = {ret_obj};
  end
  rt = toc;
  
  
  % Check consistency of retrieved/submitted object(s)
  status = zeros(1,length(sub_obj));
  
  for kk = 1:length(sub_obj)
    status(kk) = status(kk) + ne(sub_obj{kk}, ret_obj{kk}, 'invars', 'hist');
  end
  
  % Build a report struct
  sr_report.ret_time = rt;
  sr_report.sub_time = st;
  sr_report.t = t1(1:19);    % Skip milliseconds
  sr_report.t(strfind(sr_report.t,':')) = '_';    % These are correct fieldnames
  sr_report.test_ID = test_ID;
  sr_report.status = status;
  sr_report.OBJids = OBJids;
  sr_report.cid = cid;
  sr_report.sinfo = rmfield(sinfo, 'conn'); % Remove the non-serializable substructs
end

%--------------------------------------------------------------------------
% 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, 'ao', '', utils.const.categories.helper, '$Id: UTN_repo_test_func.m,v 1.14 2008/11/18 17:29:40 mauro Exp $', sets, pl);
end

%--------------------------------------------------------------------------
% Get Default Plist
%--------------------------------------------------------------------------
function plo = getDefaultPlist()
  
  disp('* creating default plist...');
  plo = plist('RAND', false, ...
    'OBJ_TYPE', 'ao', ...
    'N_OBJ', 1, ...
    'NSECS', 100, ...
    'FS', 10, ...
    'SAVE_OBJS', false, ...
    'OBJ_FILENAME', 'submit_trial_ao.xml', ...
    'SUBMIT', false, ...
    'HOSTNAME', '130.75.117.67', ...
    'DBASE', 'ltpda_test', ...
    'CONN', [], ...
    'COLL_RETRIEVE', false, ...
    'SAVE_RESULTS', true, ...
    'RESULTS_FILENAME', 'repo_test_UTN');
  
  disp('* done.');
end

% END
