function cfg_serial(guifcn, job, varargin)

% This function is deprecated.
% The functionality should replaced by the following sequence of calls:
%
% Instead of
% cfg_serial(guifcn, job, varargin)
% use
% cjob = cfg_util('initjob', job);
% sts  = cfg_util('filljobui', cjob, guifcn, varargin);
% if sts
%      cfg_util('run', cjob);
% end;
% cfg_util('deljob', cjob);
%
% Instead of
% cfg_serial(guifcn, tagstr, varargin)
% use
% cjob = cfg_util('initjob');
% mod_cfg_id = cfg_util('tag2cfg_id', tagstr);
% cfg_util('addtojob', cjob, mod_cfg_id);
% sts  = cfg_util('filljobui', cjob, guifcn, varargin);
% if sts
%      cfg_util('run', cjob);
% end;
% cfg_util('deljob', cjob);
%
% Instead of
% cfg_serial(guifcn, mod_cfg_id, varargin)
% use
% cjob = cfg_util('initjob');
% cfg_util('addtojob', cjob, mod_cfg_id);
% sts  = cfg_util('filljobui', cjob, guifcn, varargin);
% if sts
%      cfg_util('run', cjob);
% end;
% cfg_util('deljob', cjob);
%
% If no guifcn is specified, use cfg_util('filljob',... instead.
%
% GuiFcn semantics
% [val sts] = guifcn(item)
% val should be suitable to set item.val{1} using setval(item, val,
% false) for all cfg_leaf items. For cfg_repeat/cfg_choice items, val
% should be a cell array of indices into item.values. For each element of
% val, setval(item, [val{k} Inf], false)
% will be called and thus item.values{k} will be appended to item.val.
% sts should be set to true, if guifcn returns with success (i.e. a
% valid value is returned or input should continue for the next item,
% regardless of value validity).

% Old help
% function cfg_serial(guifcn, job|tagstr|mod_cfg_id, varargin)
% A matlabbatch user interface which completes a matlabbatch job with
% incomplete inputs one at a time and runs the job.
% This interface may be called with or without user interaction. If
% guifcn is a function handle, then this function will be called to enter
% unspecified inputs. Otherwise, the first argument will be ignored and
% inputs will be assigned from the argument list only.
% During job completion and execution, this interface may interfere with
% cfg_ui. However, after the job is executed, it will be removed from the
% job list.
%
% cfg_serial(guifcn, job|tagstr|mod_cfg_id[, input1, input2, ...inputN])
% Ask for missing inputs in a job. Job should be a matlabbatch job as
% returned by cfg_util('harvest'). Modifications to the job structure are
% limited:
% - no new modules can be added
% - no dependencies can be created
% - unset cfg_choice items can be selected, but not altered
% - unset cfg_repeat items can be completed, but no repeats can be added
%   to or removed from already set items
% Data to complete a job can specified as additional arguments. This
% allows to script filling of a predefined job with missing inputs.
% For cfg_entry and cfg_file items, this can be any data that meets the 
% consistency (type, filter, size) constraints of the item.
% For cfg_menu and cfg_choice items, it can be the number of a menu
% option, counting from 1.
% For cfg_repeat items, it is a cell list of numbers of menu options. The
% corresponding option will be added at the end of the repeat list.
% Any input data that can not be assigned to the current input item will
% be discarded.
%
% cfg_serial(guifcn, tagstr)
% Start input at the node addressed by tagstr in the configuration
% tree. If tagstr points to an cfg_exbranch, then only this cfg_exbranch
% will be filled and run. If tagstr points to a node above cfg_exbranch
% level, then multiple cfg_exbranches below this node may be added and
% filled.
%
% guifcn Interface 
% The guifcn will be called to enter inputs to cfg_choice, cfg_repeat,
% cfg_entry, cfg_files, cfg_menu items. The general call syntax is
% val = feval(guifcn, class, name, item_specific_data);
% Input arguments
%   class - string: one of cfg_choice, cfg_repeat, 
%                        cfg_entry, cfg_files, cfg_menu
%   name  - string: Item display name
%   Item specific data
%   * cfg_choice, cfg_menu
%     labels - cell array of strings, menu labels
%     values - cell array of values corresponding to labels
%   * cfg_repeat
%     labels and values as above
%     num    - 2-vector of min/max number of required elements in val
%   * cfg_entry
%     strtype - input type
%     extras  - extra data to evaluate input
%     num     - required size of data
%   * cfg_files
%     filter, ufilter - file filter specifications (see cfg_select)
%     dir - initial directory
%     num - 2-vector of min/max number of required files
%
% This code is part of a batch job configuration system for MATLAB. See 
%      help matlabbatch
% for a general overview.
%_______________________________________________________________________
% Copyright (C) 2007 Freiburg Brain Imaging

% Volkmar Glauche
% $Id: cfg_serial.m 1862 2008-06-30 14:12:49Z volkmar $

rev = '$Rev: 1862 $'; %#ok

cfg_message('matlabbatch:deprecated:cfg_serial', '''cfg_serial'' is deprecated. Please use cfg_util(''filljob[ui]'',...) to fill a job in serial mode.');
if ischar(job)
    % Assume dot delimited sequence of tags
    mod_cfg_id = cfg_util('tag2mod_cfg_id', job);
    if cfg_util('ismod_cfg_id', mod_cfg_id)
        % tag string points to somewhere in an cfg_exbranch
        % initialise new job
        cjob = cfg_util('initjob');
        % add mod_cfg_id
        cfg_util('addtojob', cjob, mod_cfg_id);
    else
        % tag string points to somewhere above cfg_branch
        cjob = local_addtojob(job);
    end;
elseif cfg_util('ismod_cfg_id', job)
        % initialise new job
        cjob = cfg_util('initjob');
        % add mod_cfg_id
        cfg_util('addtojob', cjob, job);    
else
    % assume job to be a saved job structure
    cjob = cfg_util('initjob', job);
end;
% varargin{:} is a list of input items
in = varargin;
% get job information
[mod_job_idlist str sts dep sout] = cfg_util('showjob', cjob);
for cm = 1:numel(mod_job_idlist)
    % loop over modules, enter missing inputs
    if ~sts(cm)
        in = local_fillmod(guifcn, cjob, mod_job_idlist{cm}, in);
    end;
end;
cfg_util('run',cjob);
cfg_util('deljob',cjob);

%% local functions

function cjob = local_addtojob(job)
% traverse tree down to cfg_exbranch level, add selected modules to job
cfg_message('matlabbatch:cfg_serial:notimplemented', ...
      'Menu traversal not yet implemented.');

function inputs = local_fillmod(guifcn, cjob, cm, inputs)
[item_mod_idlist stop contents] = ...
    cfg_util('listmod', cjob, cm, [], cfg_findspec({{'hidden',false}}), ...
             cfg_tropts({{'hidden', true}},1,Inf,1,Inf,false), ...
             {'class', 'all_set_item'});
for ci = 1:numel(item_mod_idlist)
    % loop over items, enter missing inputs
    if ~contents{2}{ci}
        if ~isempty(inputs)
            sts = local_setval(cjob, cm, item_mod_idlist, contents, ci, inputs{1});
            % discard input{1}, even if setval failed
            inputs = inputs(2:end);
        else
            sts = false;
        end;
        if ~sts && ~isa(guifcn, 'function_handle')
            % no input given, or input did not match required criteria
            cfg_message('matlabbatch:cfg_serial:notimplemented', ...
                  'User prompted input not yet implemented.');
        end;
        while ~sts
            % call guifcn until a valid input is returned
            val = local_call_guifcn(guifcn, cjob, cm, item_mod_idlist{ci}, ...
                                    contents{1}{ci});
            sts = local_setval(cjob, cm, item_mod_idlist, contents, ci, val);
        end;
        if strcmp(contents{1}{ci}, 'cfg_choice')||...
                strcmp(contents{1}{ci}, 'cfg_repeat')
            % restart filling current module, break out of for loop
            % afterwards
            inputs = local_fillmod(guifcn, cjob, cm, inputs);
            return;
        end;
    end;
end;

function sts = local_setval(cjob, cm, item_mod_idlist, contents, ci, val)
if strcmp(contents{1}{ci}, 'cfg_repeat')
    % assume val to be a cell array of indices into
    % .values
    % note that sts may return true even if some of the
    % indices failed. sts only indicates that the cfg_repeat
    % all_set_item status is met (i.e. the min/max number of
    % repeated items are present).
    sts = false;
    for cv = 1:numel(val)
        % do not use fast track || here, otherwise
        % cfg_util('setval') must be called in any case to
        % append val{cv} to cfg_repeat list.
        sts = sts | cfg_util('setval', cjob, cm, item_mod_idlist{ci}, ...
                             [val{cv} Inf]);
    end;
else
    % try to set val
    sts = cfg_util('setval', cjob, cm, item_mod_idlist{ci}, ...
                   val);
end;

function val = local_call_guifcn(guifcn, cjob, cm, citem, cmclass)
% fieldnames depend on class of item
switch cmclass
    case {'cfg_choice', 'cfg_repeat'},
        fnames = {'name', 'values', 'num'};
    case 'cfg_entry',
        fnames = {'name', 'strtype', 'num', 'extras'};
    case 'cfg_files',
        fnames = {'name', 'num', 'filter', 'dir', 'ufilter'};
    case 'cfg_menu',
        fnames = {'name', 'labels', 'values'};
end;

% only search current module/item
fspec  = cfg_findspec({{'hidden',false}});
tropts = cfg_tropts({{'hidden', true}},1,1,1,1,false);
if isempty(citem)
    % we are not in a module
    [u1 u2 contents] = cfg_util('listcfgall', cm, fspec, tropts, fnames);
else
    [u1 u2 contents] = cfg_util('listmod', cjob, cm, citem, fspec, tropts, fnames);
end;

cmname = contents{1}{1};
switch cmclass
    case {'cfg_choice', 'cfg_repeat'}
        % construct labels and values from 'values' field
        for k = 1:numel(contents{2}{1})
            labels{k} = contents{2}{1}{k}.name;
        end;
        values = num2cell(1:numel(contents{2}{1}));
        args = {labels, values};
        if strcmp(cmclass, 'cfg_repeat')
            args{3} = contents{3}{1};
        end;
    case {'cfg_entry', 'cfg_files', 'cfg_menu'}
        for k = 2:numel(contents)
            args{k-1} = contents{k}{1};
        end;
end;
val = feval(guifcn, cmclass, cmname, args{:});
