function [cfg] = ft_singleplotER(cfg, varargin)

% FT_SINGLEPLOTER plots the event-related fields or potentials of a single
% channel or the average over multiple channels. Multiple datasets can be
% overlayed.
%
% Use as
%   ft_singleplotER(cfg, data)
% or
%   ft_singleplotER(cfg, data1, data2, ..., datan)
%
% The data can be an erp/erf produced by FT_TIMELOCKANALYSIS, a power
% spectrum produced by FT_FREQANALYSIS or connectivity spectrum produced by
% FT_CONNECTIVITYANALYSIS.
%
% The configuration can have the following parameters:
%   cfg.parameter     = field to be plotted on y-axis, for example 'avg', 'powspctrm' or 'cohspctrm' (default is automatic)
%   cfg.maskparameter = field in the first dataset to be used for masking of data; this is not supported when
%                       computing the mean over multiple channels, or when giving multiple input datasets (default = [])
%   cfg.maskstyle     = style used for masking of data, 'box', 'thickness' or 'saturation' (default = 'box')
%   cfg.maskfacealpha = mask transparency value between 0 and 1
%   cfg.xlim          = 'maxmin' or [xmin xmax] (default = 'maxmin')
%   cfg.ylim          = 'maxmin', 'maxabs', 'zeromax', 'minzero', or [ymin ymax] (default = 'maxmin')
%   cfg.channel       = Nx1 cell-array with selection of channels (default = 'all'), see FT_CHANNELSELECTION for details
%   cfg.title         = string, title of plot
%   cfg.showlegend    = 'yes' or 'no', show the legend with the colors (default = 'no')
%   cfg.refchannel    = name of reference channel for visualising connectivity, can be 'gui'
%   cfg.baseline      = 'yes', 'no' or [time1 time2] (default = 'no'), see ft_timelockbaseline
%   cfg.baselinetype  = 'absolute' or 'relative' (default = 'absolute')
%   cfg.trials        = 'all' or a selection given as a 1xn vector (default = 'all')
%   cfg.fontsize      = font size of title (default = 8)
%   cfg.hotkeys       = enables hotkeys (leftarrow/rightarrow/uparrow/downarrow/m) for dynamic zoom and translation (ctrl+) of the axes
%   cfg.interactive   = interactive plot 'yes' or 'no' (default = 'yes')
%                       in a interactive plot you can select areas and produce a new
%                       interactive plot when a selected area is clicked. multiple areas
%                       can be selected by holding down the shift key.
%   cfg.renderer      = 'painters', 'zbuffer', ' opengl' or 'none' (default = [])
%   cfg.linestyle     = linestyle/marker type, see options of the PLOT function (default = '-')
%                       can be a single style for all datasets, or a cell-array containing one style for each dataset
%   cfg.linewidth     = linewidth in points (default = 0.5)
%   cfg.linecolor     = color(s) used for plotting the dataset(s) (default = 'brgkywrgbkywrgbkywrgbkyw')
%                       alternatively, colors can be specified as nx3 matrix of RGB values
%   cfg.directionality = '', 'inflow' or 'outflow' specifies for
%                       connectivity measures whether the inflow into a
%                       node, or the outflow from a node is plotted. The
%                       (default) behavior of this option depends on the dimor
%                       of the input data (see below).
%
% The following options for the scaling of the EEG, EOG, ECG, EMG, MEG and NIRS channels
% is optional and can be used to bring the absolute numbers of the different
% channel types in the same range (e.g. fT and uV). The channel types are determined
% from the input data using FT_CHANNELSELECTION.
%   cfg.eegscale       = number, scaling to apply to the EEG channels prior to display
%   cfg.eogscale       = number, scaling to apply to the EOG channels prior to display
%   cfg.ecgscale       = number, scaling to apply to the ECG channels prior to display
%   cfg.emgscale       = number, scaling to apply to the EMG channels prior to display
%   cfg.megscale       = number, scaling to apply to the MEG channels prior to display
%   cfg.gradscale      = number, scaling to apply to the MEG gradiometer channels prior to display (in addition to the cfg.megscale factor)
%   cfg.magscale       = number, scaling to apply to the MEG magnetometer channels prior to display (in addition to the cfg.megscale factor)
%   cfg.nirsscale      = number, scaling to apply to the NIRS channels prior to display
%   cfg.mychanscale    = number, scaling to apply to the channels specified in cfg.mychan
%   cfg.mychan         = Nx1 cell-array with selection of channels
%   cfg.chanscale      = Nx1 vector with scaling factors, one per channel specified in cfg.channel
%
% For the plotting of directional connectivity data the cfg.directionality
% option determines what is plotted. The default value and the supported
% functionality depend on the dimord of the input data. If the input data
% is of dimord 'chan_chan_XXX', the value of directionality determines
% whether, given the reference channel(s), the columns (inflow), or rows
% (outflow) are selected for plotting. In this situation the default is
% 'inflow'. Note that for undirected measures, inflow and outflow should
% give the same output. If the input data is of dimord 'chancmb_XXX', the
% value of directionality determines whether the rows in data.labelcmb are
% selected. With 'inflow' the rows are selected if the refchannel(s) occur in
% the right column, with 'outflow' the rows are selected if the
% refchannel(s) occur in the left column of the labelcmb-field. Default in
% this case is '', which means that all rows are selected in which the
% refchannel(s) occur. This is to robustly support linearly indexed
% undirected connectivity metrics. In the situation where undirected
% connectivity measures are linearly indexed, specifying 'inflow' or
% 'outflow' can result in unexpected behavior.
%
% to facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
% if you specify this option the input data will be read from a *.mat
% file on disk. this mat files should contain only a single variable named 'data',
% corresponding to the input structure.
%
% See also FT_SINGLEPLOTTFR, FT_MULTIPLOTER, FT_MULTIPLOTTFR, FT_TOPOPLOTER, FT_TOPOPLOTTFR

% Undocumented local options:
% cfg.zlim/xparam (set to a specific frequency range or time range [zmax zmin] for an average
% over the frequency/time bins for TFR data.  Use in conjunction with e.g. xparam = 'time', and cfg.parameter = 'powspctrm').

% Copyright (C) 2003-2006, Ole Jensen
% Copyright (C) 2006-2017, F.C. Donders Centre
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEVELOPERS NOTE: This code is organized in a similar fashion for multiplot/singleplot/topoplot
% and for ER/TFR and should remain consistent over those 6 functions.
% Section 1: general cfg handling that is independent from the data
% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data
% Section 3: select the data to be plotted and determine min/max range
% Section 4: do the actual plotting
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Section 1: general cfg handling that is independent from the data

% these are used by the ft_preamble/ft_postamble function and scripts
ft_revision = '$Id$';
ft_nargin   = nargin;
ft_nargout  = nargout;

% do the general setup of the function
ft_defaults
ft_preamble init
ft_preamble debug
ft_preamble loadvar varargin
ft_preamble provenance varargin
ft_preamble trackconfig

% the ft_abort variable is set to true or false in ft_preamble_init
if ft_abort
  return
end

Ndata = numel(varargin);
for i=1:Ndata
  % check if the input data is valid for this function
  varargin{i} = ft_checkdata(varargin{i}, 'datatype', {'timelock', 'freq'});
end

% check if the input cfg is valid for this function
cfg = ft_checkconfig(cfg, 'unused',     {'cohtargetchannel'});
cfg = ft_checkconfig(cfg, 'renamedval', {'zlim', 'absmax', 'maxabs'});
cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedforward', 'outflow'});
cfg = ft_checkconfig(cfg, 'renamedval', {'directionality', 'feedback',    'inflow'});
cfg = ft_checkconfig(cfg, 'renamed',    {'matrixside',     'directionality'});
cfg = ft_checkconfig(cfg, 'renamed',    {'channelindex',   'channel'});
cfg = ft_checkconfig(cfg, 'renamed',    {'channelname',    'channel'});
cfg = ft_checkconfig(cfg, 'renamed',    {'cohrefchannel',  'refchannel'});
cfg = ft_checkconfig(cfg, 'renamed',	  {'zparam',         'parameter'});
cfg = ft_checkconfig(cfg, 'renamed',    {'graphcolor', 'linecolor'});
cfg = ft_checkconfig(cfg, 'deprecated', {'xparam'});

% set the defaults
cfg.viewmode        = ft_getopt(cfg, 'viewmode',      'average'); % average or butterfly
cfg.baseline        = ft_getopt(cfg, 'baseline',      'no');
cfg.trials          = ft_getopt(cfg, 'trials',        'all', 1);
cfg.xlim            = ft_getopt(cfg, 'xlim',          'maxmin');
cfg.ylim            = ft_getopt(cfg, 'ylim',          'maxmin');
cfg.zlim            = ft_getopt(cfg, 'zlim',          'maxmin');
cfg.comment         = ft_getopt(cfg, 'comment',        strcat([date '\n']));
cfg.axes            = ft_getopt(cfg, ' axes',         'yes');
cfg.fontsize        = ft_getopt(cfg, 'fontsize',       8);
cfg.hotkeys         = ft_getopt(cfg, 'hotkeys',       'yes');
cfg.interactive     = ft_getopt(cfg, 'interactive',   'yes');
cfg.renderer        = ft_getopt(cfg, 'renderer',       []); % let MATLAB decide on the default
cfg.maskparameter   = ft_getopt(cfg, 'maskparameter',  []);
cfg.colorgroups     = ft_getopt(cfg, 'colorgroups',   'condition'); % this is the only supported option
cfg.linecolor       = ft_getopt(cfg, 'linecolor',     'brgkywrgbkywrgbkywrgbkyw');
cfg.linestyle       = ft_getopt(cfg, 'linestyle',     '-');
cfg.linewidth       = ft_getopt(cfg, 'linewidth',      0.5);
cfg.maskstyle       = ft_getopt(cfg, 'maskstyle',     'box');
cfg.maskfacealpha   = ft_getopt(cfg, 'maskfacealpha', 1);
cfg.channel         = ft_getopt(cfg, 'channel',       'all');
cfg.title           = ft_getopt(cfg, 'title',          []);
cfg.directionality  = ft_getopt(cfg, 'directionality', []);
cfg.figurename      = ft_getopt(cfg, 'figurename',     []);
cfg.preproc         = ft_getopt(cfg, 'preproc',        []);
cfg.frequency       = ft_getopt(cfg, 'frequency',     'all'); % needed for frequency selection with TFR data
cfg.latency         = ft_getopt(cfg, 'latency',       'all'); % needed for latency selection with TFR data, FIXME, probably not used
cfg.showlegend      = ft_getopt(cfg, 'showlegend',    'no');

% check for linestyle being a cell-array
if ischar(cfg.linestyle)
  cfg.linestyle = repmat({cfg.linestyle}, 1, Ndata);
end
% check it's length, and lengthen it if does not have enough styles in it
if (length(cfg.linestyle) > 1) && (length(cfg.linestyle) < Ndata )
  ft_error('either specify cfg.linestyle as a cell-array with one cell for each dataset, or only specify one linestyle')
elseif (length(cfg.linestyle) == 1)
  cfg.linestyle = repmat(cfg.linestyle, 1, Ndata);
end

% this is needed for the figure title and correct labeling of linecolor later on
if isfield(cfg, 'dataname') && ~isempty(cfg.dataname)
  dataname = cfg.dataname;
elseif isfield(cfg, 'inputfile') && ~isempty(cfg.inputfile)
  dataname = cfg.inputfile;
elseif nargin>1
  dataname = arrayfun(@inputname, 2:nargin, 'UniformOutput', false);
else
  dataname = {};
end

%% Section 2: data handling, this also includes converting bivariate (chan_chan and chancmb) into univariate data

for i=1:Ndata
  dtype{i}    = ft_datatype(varargin{i});
  hastime(i)  = isfield(varargin{i}, 'time');
  hasfreq(i)  = isfield(varargin{i}, 'freq');
end

% check if the input has consistent datatypes
if ~all(strcmp(dtype, dtype{1})) || ~all(hastime==hastime(1)) || ~all(hasfreq==hasfreq(1))
  ft_error('different datatypes are not allowed as input');
else
  dtype   = dtype{1};
  hastime = hastime(1);
  hasfreq = hasfreq(1);
end

% Set x/y/parameter according to datatype and dimord
switch dtype
  case 'timelock'
    xparam = 'time';
    if isfield(varargin{1}, 'trial')
      cfg.parameter = ft_getopt(cfg, 'parameter', 'trial');
    elseif isfield(varargin{1}, 'individual')
      cfg.parameter = ft_getopt(cfg, 'parameter', 'individual');
    elseif isfield(varargin{1}, 'avg')
      cfg.parameter = ft_getopt(cfg, 'parameter', 'avg');
    end
  case 'freq'
    if hastime && hasfreq
      xparam = 'time';   % average over selected frequencies
    else
      xparam = 'freq';
    end
    cfg.parameter = ft_getopt(cfg, 'parameter', 'powspctrm');
  case 'comp'
    % not supported
  otherwise
    % not supported
end

% check whether rpt/subj is present and remove if necessary
dimord = getdimord(varargin{1}, cfg.parameter);
dimtok = tokenize(dimord, '_');
hasrpt = any(ismember(dimtok, {'rpt' 'subj'}));

if ~hasrpt
  assert(isequal(cfg.trials, 'all') || isequal(cfg.trials, 1), 'incorrect specification of cfg.trials for data without repetitions');
else
  assert(~isempty(cfg.trials), 'empty specification of cfg.trials for data with repetitions');
end

% parse cfg.channel
if isfield(cfg, 'channel') && isfield(varargin{1}, 'label')
  cfg.channel = ft_channelselection(cfg.channel, varargin{1}.label);
elseif isfield(cfg, 'channel') && isfield(varargin{1}, 'labelcmb')
  cfg.channel = ft_channelselection(cfg.channel, unique(varargin{1}.labelcmb(:)));
end

% apply baseline correction
if ~strcmp(cfg.baseline, 'no')
  tmpcfg = keepfields(cfg, {'baseline', 'baselinetype', 'baselinewindow', 'demean', 'parameter', 'channel'});
  for i=1:Ndata
    % keep mask-parameter if it is set
    if ~isempty(cfg.maskparameter)
      tempmask = varargin{i}.(cfg.maskparameter);
    end
    if strcmp(dtype, 'timelock') && strcmp(xparam, 'time')
      varargin{i} = ft_timelockbaseline(tmpcfg, varargin{i});
    elseif strcmp(dtype, 'freq') && strcmp(xparam, 'time')
      varargin{i} = ft_freqbaseline(tmpcfg, varargin{i});
    elseif strcmp(dtype, 'freq') && strcmp(xparam, 'freq')
      ft_error('baseline correction is not supported for spectra without a time dimension');
    else
      ft_warning('baseline correction not applied, please set xparam');
    end
    % put mask-parameter back if it is set
    if ~isempty(cfg.maskparameter)
      varargin{i}.(cfg.maskparameter) = tempmask;
    end
  end
end

% channels should NOT be selected and averaged here, since a topoplot might follow in interactive mode
tmpcfg = keepfields(cfg, {'showcallinfo', 'trials'});
if hasrpt
  tmpcfg.avgoverrpt = 'yes';
else
  tmpcfg.avgoverrpt = 'no';
end
if hastime && hasfreq
  tmpcfg.avgoverfreq = 'yes';       % average over selected frequencies
  tmpcfg.frequency = cfg.frequency; % not to be confused with cfg.xlim or cfg.ylim
  tmpcfg.keepfreqdim = 'no';
else
  tmpcfg.avgoverfreq = 'no';
end
tmpvar = varargin{1};
[varargin{:}] = ft_selectdata(tmpcfg, varargin{:});
% restore the provenance information and put back cfg.channel
tmpchannel  = cfg.channel;
[cfg, varargin{:}] = rollback_provenance(cfg, varargin{:});
cfg.channel = tmpchannel;

if isfield(tmpvar, cfg.maskparameter) && ~isfield(varargin{1}, cfg.maskparameter)
  % the mask parameter is not present after ft_selectdata, because it is
  % not included in all input arguments. Make the same selection and copy
  % it over
  tmpvar = ft_selectdata(tmpcfg, tmpvar);
  varargin{1}.(cfg.maskparameter) = tmpvar.(cfg.maskparameter);
end

clear tmpvar tmpcfg dimord dimtok hastime hasfreq hasrpt

% ensure that the preproc specific options are located in the cfg.preproc
% substructure, but also ensure that the field 'refchannel' remains at the
% highest level in the structure. This is a little hack by JM because the field
% refchannel can relate to connectivity or to an EEg reference.

if isfield(cfg, 'refchannel'), refchannelincfg = cfg.refchannel; cfg = rmfield(cfg, 'refchannel'); end
cfg = ft_checkconfig(cfg, 'createsubcfg',  {'preproc'});
if exist('refchannelincfg', 'var'), cfg.refchannel  = refchannelincfg; end

if ~isempty(cfg.preproc)
  % preprocess the data, i.e. apply filtering, baselinecorrection, etc.
  fprintf('applying preprocessing options\n');
  if ~isfield(cfg.preproc, 'feedback')
    cfg.preproc.feedback = cfg.interactive;
  end
  for i=1:Ndata
    varargin{i} = ft_preprocessing(cfg.preproc, varargin{i});
  end
end

% Handle the bivariate case
dimord = getdimord(varargin{1}, cfg.parameter);
if startsWith(dimord, 'chan_chan_') || startsWith(dimord, 'chancmb_')
  % convert the bivariate data to univariate and call this plotting function again
  cfg.originalfunction = 'ft_singleplotER';
  cfg.trials = 'all'; % trial selection has been taken care off
  bivariate_common(cfg, varargin{:});
  return
end

% Apply channel-type specific scaling
fn = fieldnames(cfg);
tmpcfg = keepfields(cfg, fn(endsWith(fn, 'scale') | startsWith(fn, 'mychan') | strcmp(fn, 'channel') | strcmp(fn, 'parameter')));
for i=1:Ndata
  varargin{i}= chanscale_common(tmpcfg, varargin{i});
end

%% Section 3: select the data to be plotted and determine min/max range

% Take the desided subselection of channels, this is the same in all datasets
[selchan] = match_str(varargin{1}.label, cfg.channel);

% Get physical min/max range of x, i.e. time or frequency
if strcmp(cfg.xlim, 'maxmin')
  % Find maxmin throughout all varargins:
  xmin = [];
  xmax = [];
  for i=1:Ndata
    xmin = min([xmin varargin{i}.(xparam)]);
    xmax = max([xmax varargin{i}.(xparam)]);
  end
else
  xmin = cfg.xlim(1);
  xmax = cfg.xlim(2);
end

% Get the index of the nearest bin, this is the same in all datasets
xminindx = nearest(varargin{1}.(xparam), xmin);
xmaxindx = nearest(varargin{1}.(xparam), xmax);
xmin = varargin{1}.(xparam)(xminindx);
xmax = varargin{1}.(xparam)(xmaxindx);
selx = xminindx:xmaxindx;
xval = varargin{1}.(xparam)(selx);

% get physical y-axis range, i.e. parameter to be plotted
if ~isnumeric(cfg.ylim)
  % find maxmin throughout all varargins
  ymin = [];
  ymax = [];
  for i=1:Ndata
    % select the channels in the data that match with the layout and that are selected for plotting
    switch cfg.viewmode
      case 'average'
        dat = nanmean(varargin{i}.(cfg.parameter)(selchan, selx), 1); % mean over channels
      case 'butterfly'
        dat = varargin{i}.(cfg.parameter)(selchan,selx);
    end
    ymin = nanmin([ymin nanmin(nanmin(nanmin(dat(:))))]);
    ymax = nanmax([ymax nanmax(nanmax(nanmax(dat(:))))]);
  end
  if strcmp(cfg.ylim, 'maxabs') % handle maxabs, make y-axis center on 0
    ymax = max([abs(ymax) abs(ymin)]);
    ymin = -ymax;
  elseif strcmp(cfg.ylim, 'zeromax')
    ymin = 0;
  elseif strcmp(cfg.ylim, 'minzero')
    ymax = 0;
  end
else
  ymin = cfg.ylim(1);
  ymax = cfg.ylim(2);
end

% gather the data from all input data structures
datamatrix = zeros(Ndata, length(selx));
for i=1:Ndata
  datamatrix(i,:) = mean(varargin{i}.(cfg.parameter)(selchan, selx), 1); % mean over channels
end

% gather the mask from the first input data structure
if ~isempty(cfg.maskparameter)
  maskmatrix = mean(varargin{1}.(cfg.maskparameter)(selchan, selx), 1); % mean over channels
else
  % create an Nx0 matrix
  maskmatrix = zeros(length(selchan), 0);
end

%% Section 4: do the actual plotting

% determine the coloring of channels/conditions
linecolor = linecolor_common(cfg, varargin{:});

cla
hold on

yval = datamatrix;
mask = maskmatrix;

if strcmp(cfg.maskstyle, 'difference')
  % combine the conditions in a single plot, highlight the difference
  ft_plot_vector(xval, yval, 'color', linecolor, 'linewidth', cfg.linewidth, 'style', cfg.linestyle{1}, 'linewidth', cfg.linewidth, 'highlight', mask, 'highlightstyle', cfg.maskstyle, 'hlim', [xmin xmax], 'vlim', [ymin ymax], 'facealpha', cfg.maskfacealpha);
else
  % loop over the conditions, plot them on top of each other
  for i=1:Ndata
    ft_plot_vector(xval, yval(i,:), 'color', linecolor(i,:), 'linewidth', cfg.linewidth, 'style', cfg.linestyle{i}, 'highlight', mask, 'highlightstyle', cfg.maskstyle, 'linewidth', cfg.linewidth, 'hlim', [xmin xmax], 'vlim', [ymin ymax], 'facealpha', cfg.maskfacealpha);
  end
end

if ischar(linecolor)
  set(gca, 'ColorOrder', char2rgb(linecolor))
elseif isnumeric(linecolor)
  set(gca, 'ColorOrder', linecolor)
end

% show the legend with the colors of the conditions
if istrue(cfg.showlegend) && Ndata>1
  if strcmp(cfg.maskstyle, 'difference')
    colorLabels = {'difference'};
  else
    colorLabels = {};
  end
  for i=1:Ndata
    if ischar(linecolor)
      colorLabels{end+1} = [dataname{i} '='         linecolor(i)     ];
    elseif isnumeric(linecolor)
      colorLabels{end+1} = [dataname{i} '=' num2str(linecolor(i, :)) ];
    end
  end
  legend(colorLabels)
end

% set xlim and ylim
if xmin~=xmax
  xlim([xmin xmax]);
end
if ymin~=ymax
  ylim([ymin ymax]);
end

% adjust mask box extents to ymin/ymax
if ~isempty(cfg.maskparameter)
  ptchs = findobj(gcf, 'type', 'patch');
  for i = 1:length(ptchs)
    YData = get(ptchs(i), 'YData');
    YData(YData == min(YData)) = ymin;
    YData(YData == max(YData)) = ymax;
    set(ptchs(i), 'YData',YData);
  end
end

% Set callback to adjust axes
if strcmp('yes', cfg.hotkeys)
  %  attach data and cfg to figure and attach a key listener to the figure
  set(gcf, 'KeyPressFcn', {@key_sub, xmin, xmax, ymin, ymax})
end

% Create axis title containing channel name(s) and channel number(s):
if ~isempty(cfg.title)
  t = cfg.title;
else
  if length(cfg.channel) == 1
    t = [char(cfg.channel) ' / ' num2str(selchan) ];
  else
    t = sprintf('mean(%0s)', join_str(', ', cfg.channel));
  end
end
title(t, 'fontsize', cfg.fontsize);

% set the figure window title, add channel labels if number is small
if isempty(get(gcf, 'Name'))
  if length(selchan) < 5
    chans = join_str(', ', cfg.channel);
  else
    chans = '<multiple channels>';
  end
  if ~isempty(cfg.figurename)
    set(gcf, 'name', cfg.figurename);
    set(gcf, 'NumberTitle', 'off');
  elseif ~isempty(dataname)
    set(gcf, 'Name', sprintf('%d: %s: %s (%s)', double(gcf), mfilename, join_str(', ', dataname), chans));
    set(gcf, 'NumberTitle', 'off');
  else
    set(gcf, 'Name', sprintf('%d: %s (%s)', double(gcf), mfilename, chans));
    set(gcf, 'NumberTitle', 'off');
  end
end

% make the figure interactive
if strcmp(cfg.interactive, 'yes')
  % add the cfg/data/channel information to the figure under identifier linked to this axis
  ident                  = ['axh' num2str(round(sum(clock.*1e6)))]; % unique identifier for this axis
  set(gca, 'tag', ident);
  info                   = guidata(gcf);
  info.(ident).cfg       = cfg;
  info.(ident).varargin  = varargin;
  info.(ident).dataname  = dataname;
  guidata(gcf, info);
  set(gcf, 'windowbuttonupfcn',     {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttonupfcn'});
  set(gcf, 'windowbuttondownfcn',   {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttondownfcn'});
  set(gcf, 'windowbuttonmotionfcn', {@ft_select_range, 'multiple', false, 'yrange', false, 'callback', {@select_topoplotER}, 'event', 'windowbuttonmotionfcn'});
end

% set renderer if specified
if ~isempty(cfg.renderer)
  set(gcf, 'renderer', cfg.renderer)
end

hold off

% do the general cleanup and bookkeeping at the end of the function
ft_postamble debug
ft_postamble trackconfig
ft_postamble previous varargin
ft_postamble provenance
ft_postamble savefig

% add a menu to the figure, but only if the current figure does not have subplots
menu_fieldtrip(gcf, cfg, false);

if ~ft_nargout
  % don't return anything
  clear cfg
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION which is called after selecting a time range
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function select_topoplotER(range, varargin)

% fetch cfg/data based on axis indentifier given as tag
ident    = get(gca, 'tag');
info     = guidata(gcf);
cfg      = info.(ident).cfg;
varargin = info.(ident).varargin;
if ~isempty(range)
  cfg = removefields(cfg, 'inputfile');   % the reading has already been done and varargin contains the data
  cfg = removefields(cfg, 'showlabels');  % this is not allowed in topoplotER
  cfg.baseline = 'no';                    % make sure the next function does not apply a baseline correction again
  cfg.dataname = info.(ident).dataname;   % put data name in here, this cannot be resolved by other means
  cfg.channel = 'all';                    % make sure the topo displays all channels, not just the ones in this singleplot
  cfg.comment = 'auto';
  cfg.trials = 'all';                     % trial selection has already been taken care of
  cfg.xlim = range(1:2);
  % if user specified a ylim, copy it over to the zlim of topoplot
  if isfield(cfg, 'ylim')
    cfg.zlim = cfg.ylim;
    cfg = rmfield(cfg, 'ylim');
  end
  fprintf('selected cfg.xlim = [%f %f]\n', cfg.xlim(1), cfg.xlim(2));
  % ensure that the new figure appears at the same position
  f = figure('position', get(gcf, 'Position'));
  ft_topoplotER(cfg, varargin{:});
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SUBFUNCTION which handles hot keys in the current plot
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function key_sub(handle, eventdata, varargin)
xlimits = xlim;
ylimits = ylim;
incr_x = abs(xlimits(2) - xlimits(1)) /10;
incr_y = abs(ylimits(2) - ylimits(1)) /10;

if length(eventdata.Modifier) == 1 && strcmp(eventdata.Modifier{:}, 'control')
  % TRANSLATE by 10%
  switch eventdata.Key
    case 'leftarrow'
      xlim([xlimits(1)+incr_x xlimits(2)+incr_x])
    case 'rightarrow'
      xlim([xlimits(1)-incr_x xlimits(2)-incr_x])
    case 'uparrow'
      ylim([ylimits(1)-incr_y ylimits(2)-incr_y])
    case 'downarrow'
      ylim([ylimits(1)+incr_y ylimits(2)+incr_y])
  end % switch
else
  % ZOOM by 10%
  switch eventdata.Key
    case 'leftarrow'
      xlim([xlimits(1)-incr_x xlimits(2)+incr_x])
    case 'rightarrow'
      xlim([xlimits(1)+incr_x xlimits(2)-incr_x])
    case 'uparrow'
      ylim([ylimits(1)-incr_y ylimits(2)+incr_y])
    case 'downarrow'
      ylim([ylimits(1)+incr_y ylimits(2)-incr_y])
    case 'm'
      xlim([varargin{1} varargin{2}])
      ylim([varargin{3} varargin{4}])
  end % switch
end % if


function obj = read_from_file(obj)
% Reads data from image filenames into obj.dat
%
% Try obj = check_image_filenames(obj) first.
%
% This is automatically called if you create a new image_vector object with
% names but do not directly enter data. e.g., the commands below will load data:
%   - name = 'salientmap.nii';
%   - img = image_vector('image_names', name);
%

% disp('Reading image data into object .dat field.');

% if we have mask info, use that. Otherwise, create
if isempty(obj.volInfo)
    % disp('Creating mask info from first image and storing in .volInfo.');
    obj.volInfo = iimg_read_img(obj.fullpath(1, :), 2);
else
    % disp('Using mask and space-defining info already stored in .volInfo field.');
end

% Now extract the actual data from the mask
switch spm('Ver')

    case {'SPM8', 'SPM5','SPM12'}
        obj.dat = iimg_get_data(obj.volInfo, obj.fullpath, 'single', 'noexpand')';

    case {'SPM2', 'SPM99'}
        % legacy, for old SPM
        obj.dat = iimg_get_data(obj.volInfo, obj.fullpath, 'single')';

    otherwise
        error('Unknown version of SPM! Update code, check path, etc.');
end

end % function


% --------------------------------------------------------
% MDP Tracking
% Copyright (c) 2015 CVGL Stanford
% Licensed under The MIT License [see LICENSE for details]
% Written by Yu Xiang
% --------------------------------------------------------
%
% offline training using ground truth annotations
function tracker = MDP_train_gt(seq_idx, tracker)

is_show = 0;
is_save = 1;
is_text = 0;
is_pause = 0;

opt = globals();
opt.is_show = is_show;

seq_name = opt.mot2d_train_seqs{seq_idx};
seq_num = opt.mot2d_train_nums(seq_idx);
seq_set = 'train';

if is_show
    close all;
end

% build the dres structure for images
filename = sprintf('%s/%s_dres_image.mat', opt.results, seq_name);
if exist(filename, 'file') ~= 0
    object = load(filename);
    dres_image = object.dres_image;
    fprintf('load images from file %s done\n', filename);
else
    dres_image = read_dres_image(opt, seq_set, seq_name, seq_num);
    fprintf('read images done\n');
    save(filename, 'dres_image', '-v7.3');
end

% read ground truth
filename = fullfile(opt.mot, opt.mot2d, seq_set, seq_name, 'gt', 'gt.txt');
dres_gt_all = read_mot2dres(filename);
dres_gt_all = fix_groundtruth(seq_name, dres_gt_all);

% generate training data
I = dres_image.Igray{1};
[dres_train, dres_det, labels] = generate_training_data(seq_idx, dres_image, opt);

% for debugging
% dres_train = {dres_train{6}};

% intialize tracker
if nargin < 2 || isempty(tracker) == 1
    fprintf('initialize tracker from scratch\n');
    tracker = MDP_initialize(I, dres_det, labels, opt);
else
    % continuous training
    fprintf('continuous training\n');
    tracker.image_width = size(I,2);
    tracker.image_height = size(I,1);
    tracker.max_width = max(dres_det.w);
    tracker.max_height = max(dres_det.h);
    tracker.max_score = max(dres_det.r);

    factive = MDP_feature_active(tracker, dres_det);
    index = labels ~= 0;
    tracker.factive = [tracker.factive; factive(index,:)];
    tracker.lactive = [tracker.lactive; labels(index)];
    tracker.w_active = svmtrain(tracker.lactive, tracker.factive, '-c 1 -q');
end

% for each training sequence
num_train = numel(dres_train);
for t = 1:num_train

    fprintf('tracking sequence %d\n', t);

    dres_gt = dres_train{t};

    % first frame
    fr = dres_gt.fr(1);
    id = dres_gt.id(1);

    % reset tracker
    tracker.prev_state = 1;
    tracker.state = 1;
    tracker.target_id = id;

    % start tracking
    while fr <= dres_gt.fr(end)
        if is_text
            fprintf('\nframe %d, state %d\n', fr, tracker.state);
        end

        % show results
        if is_show
            figure(1);
            % show ground truth
            subplot(2, 3, 1);
            show_dres(fr, dres_image.I{fr}, 'GT', dres_gt);

            % show detections
            subplot(2, 3, 2);
            show_dres(fr, dres_image.I{fr}, 'Detections', dres_det);
        end

        if tracker.state == 0
            break;

        elseif tracker.state == 1

            % initialize the LK tracker with gt
            tracker = LK_initialize(tracker, fr, id, dres_gt, 1, dres_image);
            tracker.state = 2;
            tracker.streak_occluded = 0;

            % build the dres structure
            dres_one = [];
            dres_one.fr = fr;
            dres_one.id = id;
            dres_one.x = dres_gt.x(1);
            dres_one.y = dres_gt.y(1);
            dres_one.w = dres_gt.w(1);
            dres_one.h = dres_gt.h(1);
            dres_one.r = 1;
            dres_one.state = 2;
            tracker.dres = dres_one;

        % tracking by association
        else

            % find the ground truths for association
            index_gt = find(dres_gt_all.fr == fr);
            dres = sub(dres_gt_all, index_gt);
            dres = MDP_crop_image_box(dres, dres_image.Igray{fr}, tracker);
            [dres, index_det, ctrack] = generate_association_index(tracker, fr, dres);

            % check if occluded or not
            index_gt = find(dres_gt.fr == fr);
            if isempty(index_gt) == 1 || dres_gt.covered(index_gt) ~= 0
                index_det = [];
            end

            if is_show
                figure(1);
                subplot(2, 3, 3);
                show_dres(fr, dres_image.I{fr}, 'Potential Associations', sub(dres, index_det));
                hold on;
                plot(ctrack(1), ctrack(2), 'ro', 'LineWidth', 2);
                hold off;
            end

            % compute features
            if isempty(index_det) == 0 && isempty(find(dres.id(index_det) == tracker.target_id, 1)) == 0
                % extract features with LK association
                dres_associate = sub(dres, index_det);
                features = MDP_feature_occluded(fr, dres_image, dres_associate, tracker);

                % compute labels
                m = size(features, 1);
                labels = -1 * ones(m, 1);
                ind = find(dres_associate.id == tracker.target_id);
                labels(ind) = 1;

                % update features
                tracker.f_occluded(end+1:end+m,:) = features;
                tracker.l_occluded(end+1:end+m) = labels;
                if is_text
                    fprintf('training examples in occluded state %d\n', size(tracker.f_occluded,1));
                end

                % update template
                dres_one = sub(dres_associate, ind);
                tracker = LK_associate(fr, dres_image, dres_one, tracker);

                tracker.prev_state = tracker.state;
                tracker.state = 2;
                % build the dres structure
                dres_one = [];
                dres_one.fr = fr;
                dres_one.id = tracker.target_id;
                dres_one.x = tracker.bb(1);
                dres_one.y = tracker.bb(2);
                dres_one.w = tracker.bb(3) - tracker.bb(1);
                dres_one.h = tracker.bb(4) - tracker.bb(2);
                dres_one.r = 1;
                dres_one.state = 2;

                if tracker.dres.fr(end) == fr
                    dres_tmp = tracker.dres;
                    index_tmp = 1:numel(dres_tmp.fr)-1;
                    tracker.dres = sub(dres_tmp, index_tmp);
                end
                tracker.dres = interpolate_dres(tracker.dres, dres_one);
                % update LK tracker
                tracker = LK_update(fr, tracker, dres_image.Igray{fr}, dres_associate, 1);

            else
                tracker.state = 3;
                dres_one = sub(tracker.dres, numel(tracker.dres.fr));
                dres_one.fr = fr;
                dres_one.id = tracker.target_id;
                dres_one.state = 3;

                if tracker.dres.fr(end) == fr
                    dres_tmp = tracker.dres;
                    index_tmp = 1:numel(dres_tmp.fr)-1;
                    tracker.dres = sub(dres_tmp, index_tmp);
                end
                tracker.dres = concatenate_dres(tracker.dres, dres_one);
            end

        end

        % show results
        if is_show
            figure(1);

            % show tracking results
            subplot(2, 3, 4);
            show_dres(fr, dres_image.I{fr}, 'Tracking', tracker.dres, 2);

            % show lost targets
            subplot(2, 3, 5);
            show_dres(fr, dres_image.I{fr}, 'Lost', tracker.dres, 3);

            subplot(2, 3, 6);
            show_templates(tracker, dres_image);

            fprintf('frame %d, state %d\n', fr, tracker.state);
            if is_pause
                pause();
            else
                pause(0.01);
            end

%             filename = sprintf('results/%s_%06d.png', seq_name, fr);
%             hgexport(h, filename, hgexport('factorystyle'), 'Format', 'png');
        end

        fr = fr + 1;
    end

end
tracker.w_occluded = svmtrain(tracker.l_occluded, tracker.f_occluded, '-c 1 -q -g 1 -b 1');
fprintf('Finish training %s\n', seq_name);

% save model
if is_save
    filename = sprintf('%s/%s_tracker_gt.mat', opt.results, seq_name);
    save(filename, 'tracker');
end


function header = egi_writeRawHeader( fid, header )
% Write EGI RAW header structure to an open file.
%
% USAGE:  header = egi_writeRawHeader( fid, header )
%
% INPUT:
%    - fid    : Matlab file handle to the EGI RAW file (file must be already open)
%    - header : Header structure of the same file
% OUTPUT:
%    - epochLength : length (in number of time samples) of each epoch in the RAW file

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2008
% ----------------------------- Script History ---------------------------------
% FT  24-Jun-2008  Creation
% ------------------------------------------------------------------------------

% WRITE RAW HEADER
fwrite(fid, header.versionNumber,           'integer*4');
fwrite(fid, header.recordingTime.Year     , 'integer*2');
fwrite(fid, header.recordingTime.Month    , 'integer*2');
fwrite(fid, header.recordingTime.Day      , 'integer*2');
fwrite(fid, header.recordingTime.Hour     , 'integer*2');
fwrite(fid, header.recordingTime.Minute   , 'integer*2');
fwrite(fid, header.recordingTime.Second   , 'integer*2');
fwrite(fid, header.recordingTime.Millisec , 'integer*4');
fwrite(fid, header.samplingRate           , 'integer*2');
fwrite(fid, header.numChans               , 'integer*2');
fwrite(fid, header.boardGain              , 'integer*2');
fwrite(fid, header.numConvBits            , 'integer*2');
fwrite(fid, header.ampRange               , 'integer*2');
fwrite(fid, header.numSamples             , 'integer*4');
fwrite(fid, header.numEvents              , 'integer*2');

% WRITE EVENTS
if (header.numEvents ~= 0)  % File contains event info.
    for i = 1:header.numEvents
        fwrite(fid, header.eventCodes{i}, 'uchar');
    end
end


function pagelayo
% PAGELAYO Set up graphical objects for Tutor environment.
%          PAGELAYO sets up all the axes, line, and text graphical objects
%          depending upon the desired arrangement.

% Author: Craig Borghesani
% Date: 10/17/94
% Revised: 11/13/94
% Copyright (c) 1999, Prentice-Hall

page_chil = [];

f = gcf;
ui_data = get(f,'userdata');
ui_han = ui_data{1};

page_setup = get(ui_han(34),'userdata');
page_layout = get(ui_han(35),'userdata');
if length(page_layout),
 delete(page_layout(find(page_layout~=0)));
 page_chil = get(ui_han(90),'userdata');
 set(page_chil,'vis','off');
end
page_layout = zeros(4,8);

% locations of axes
scrn_size = get(0,'screensize');
fig_size = get(gcf,'position');
%fig_wdt = scrn_size(3)-10*2;
fig_wdt = fig_size(3);
frm_wdt = 190;
ers = 'xor';

%axs1_l = (frm_wdt+2+60)/fig_wdt;
axs1_l = 0.07;
axs1_b = 0.15;
%axs1_w = 0.97 - axs1_l;
axs1_w = 0.97 - (frm_wdt+2+60)/fig_wdt;
axs1_h = 0.68;

axs2_b = 0.58;
axs2_w = axs1_w/2 - 0.05;
axs2_l = axs1_l + axs2_w + 0.1;
%axs2_h = axs2_w;
axs2_h = 0.26;

if ~length(page_chil),
 for k = 1:8,
  page_chil(k) = uimenu(ui_han(90),'vis','off');
 end
 set(ui_han(90),'userdata',page_chil);
end

page_ct = 0;
for page_num = 1:8,
 lab_tit = [];
 plots = page_setup(:,page_num); plots(find(plots==0)) = [];

 if length(plots)==1,
  axs_pos = [axs1_l,axs1_b,axs1_w,axs1_h];
 elseif length(plots)==2,
  axs_pos = [axs1_l,axs2_b,axs1_w,axs2_h;
             axs1_l,axs1_b,axs1_w,axs2_h];
 elseif length(plots)==3,
  axs_pos = [axs1_l,axs2_b,axs1_w,axs2_h;
             axs1_l,axs1_b,axs2_w,axs2_h;
             axs2_l,axs1_b,axs2_w,axs2_h];
 elseif length(plots)==4,
  axs_pos = [axs1_l,axs2_b,axs2_w,axs2_h;
             axs2_l,axs2_b,axs2_w,axs2_h;
             axs1_l,axs1_b,axs2_w,axs2_h;
             axs2_l,axs1_b,axs2_w,axs2_h];
 else
  break;
 end

 for k = 1:length(plots),
  if any(plots(k)==[2,3,6,7]),
   xscale = 'log';
  else
   xscale = 'linear';
  end
  if plots(k) == 1, % Nyquist
   xlab = 'Real';
   ylab = 'Imaginary';
   titl = 'Nyquist';
   xlim = [-1,1]; ylim = [-1,1];
  elseif plots(k) == 2, % Bode (Magnitude)
   xlab = 'Frequency (rad/sec)';
   ylab = 'Magnitude (dB)';
   titl = 'Bode (Magnitude)';
   xlim = [0.01,1000]; ylim = [-20,20];
  elseif plots(k) == 3, % Bode (Phase)
   xlab = 'Frequency (rad/sec)';
   ylab = 'Phase (degrees)';
   titl = 'Bode (Phase)';
   xlim = [0.01,1000]; ylim = [-360,0];
  elseif plots(k) == 4, % Nichols
   xlab = 'Phase (degrees)';
   ylab = 'Magnitude (dB)';
   titl = 'Nichols';
   xlim = [-360,0]; ylim = [-20,20];
  elseif plots(k) == 5, % Root Locus
   xlab = 'Real';
   ylab = 'Imaginary';
   titl = 'Root Locus';
   xlim = [-1,1]; ylim = [-1,1];
  elseif plots(k) == 6, % Gain (Magnitude)
   xlab = 'K';
   ylab = 'Magnitude';
   titl = 'Gain (Magnitude)';
   xlim = [0.01,1000]; ylim = [0.01,10];
  elseif plots(k) == 7, % Gain (Phase)
   xlab = 'K';
   ylab = 'Phase (degrees)';
   titl = 'Gain (Phase)';
   xlim = [0.01,1000]; ylim = [0,360];
  elseif plots(k) == 8, % Time Response
   xlab = 'Time (seconds)';
   ylab = 'Amplitude';
   titl = 'Time Response';
   xlim = [0,10]; ylim = [0,5];
  end

  axs = axes('vis','off','box','on','pos',axs_pos(k,:),...
             'xscale',xscale,'xgrid','on','ygrid','on',...
             'xlim',xlim,'ylim',ylim,...
             'drawmode','fast',...
             'tag',['1',int2str(plots(k)),'20']);
%             'buttondownfcn',['pagemous(1,',int2str(plots(k)),',10)']);
  XLabelHandle = get(axs,'xlabel');
  YLabelHandle = get(axs,'ylabel');
  TitleHandle  = get(axs,'title');
  set(XLabelHandle,'string',xlab);
  set(YLabelHandle,'string',ylab);
  set(TitleHandle,'string',titl);

  if any(plots(k)==[1,5]),
%   set(axs,'dataaspectratio',[1,1,1]);
   axis equal;
  end

  if any(plots(k)==[1,2,3,4]), % frequency response plots
   clr = 'g';
   lin = [];
   for k2 = 1:15,
    if k2 > 6, clr = 'r'; end
%    if k2 > 3, ers = 'norm'; end
    lin(k2) = line('xdata',0,'ydata',0,'color',clr,'erase',ers,...
                   'vis','off',...
                   'tag',['2',int2str(plots(k)),int2str(k2)]);
%     'buttondownfcn',['pagemous(2,',int2str(plots(k)),',',int2str(k2),')']);
   end
   set(axs,'userdata',[plots(k),lin]);

  elseif any(plots(k) == [5,6,7]), % root locus, gain plots

   set(axs,'userdata',plots(k),'nextplot','add');

   if plots(k) == 6,
    set(axs,'yscale','log');
   end

  else % time response
   clr = ['r';'g';'b';'y';'m';'c'];
   lin = [];
   for k2 = 1:6,
    lin(k2) = line('xdata',0,'ydata',0,'color',clr(k2),...
                   'vis','off',...
                   'erase',ers,...
                   'tag',['1',int2str(plots(k)),int2str(20+k2)]);
%     'buttondownfcn',['pagemous(1,',int2str(plots(k)),',10)']);
   end
   txt = [];
   for k2 = 1:12,
    txt(k2) = text('pos',[0,0,0],'vis','off',...
     'tag',['1',int2str(plots(k)),int2str(26+k2)],'color','k',...
     'erase',ers);
%     'buttondownfcn',['pagemous(1,',int2str(plots(k)),',10)']);
   end
   set(axs,'userdata',[plots(k),lin,txt]);

  end

  page_layout(k,page_num)=axs;
  lab_tit = [lab_tit,titl,', '];

 end

 if length(lab_tit),
  lab_tit((length(lab_tit)-1):length(lab_tit))=[];
  set(page_chil(page_num),'label',lab_tit,'vis','on',...
                   'callback',['pagesele(',int2str(page_num),',14)']);
 end
 page_ct = page_ct + 1;
end

if page_ct < 2,
 set(ui_han(90),'enable','off');
else
 set(ui_han(90),'enable','on');
end

set(ui_han(35),'userdata',page_layout);


function [counter, listofimages] = HandleImgFolder(pth)
%
% read all images - and find problematic ones
%
% Usage:
% counter = HandleImgFolder( pth )
%
% Inputs:
% pth - full path on local disk where LM (or SUN) images are.
% this should be the same path as "destImages" used in SUNinstall function
%
% Outputs:
% counter - number of problematic images encountered and deleted
%
% Note: problematic images will be deleted, their names (full path) will be
% printed to stdout.
%
% written by: Shai Bagon, Oct 2012.
%
% modified by Torralba to return a list of problematic images
%

counter = 0;
listofimages  = {};

fls = dir(fullfile(pth,'*'));

imgfrmt = imformats();

for fi=3:numel(fls) % skip first '.' and '..'
    fnm = fullfile(pth, fls(fi).name);
    % process sub folder
    if fls(fi).isdir
        disp(fls(fi))
        [c,l] = HandleImgFolder( fnm );
        counter = counter + c;
        listofimages = [listofimages l];
        continue;
    end

    % process image file
    try
        fbit = arrayfun( @(x) x.isa(fnm), imgfrmt);
        if any( fbit )
            % switch off warnings
            lastwarn('');
            imgfrmt(fbit).read( fnm );
            [wm wi] = lastwarn();
            if ~isempty(wi)
                lastwarn(''); % clear warning
                error('LMVerifyDownload:HandleFolder:warn',...
                    'Got warning %s\nthrowing a custom error', wm);
            end
        end
    catch em
        fprintf(1, '\tProblematic image %s \n', fnm);
        %delete(fnm);
        counter = counter + 1;
        listofimages{counter} = fnm;
    end
end


function varargout = lvd_editFminconOptionsGUI(varargin)
% LVD_EDITFMINCONOPTIONSGUI MATLAB code for lvd_editFminconOptionsGUI.fig
%      LVD_EDITFMINCONOPTIONSGUI, by itself, creates a new LVD_EDITFMINCONOPTIONSGUI or raises the existing
%      singleton*.
%
%      H = LVD_EDITFMINCONOPTIONSGUI returns the handle to a new LVD_EDITFMINCONOPTIONSGUI or the handle to
%      the existing singleton*.
%
%      LVD_EDITFMINCONOPTIONSGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in LVD_EDITFMINCONOPTIONSGUI.M with the given input arguments.
%
%      LVD_EDITFMINCONOPTIONSGUI('Property','Value',...) creates a new LVD_EDITFMINCONOPTIONSGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before lvd_editFminconOptionsGUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to lvd_editFminconOptionsGUI_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help lvd_editFminconOptionsGUI

% Last Modified by GUIDE v2.5 03-Jan-2021 15:29:14

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @lvd_editFminconOptionsGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @lvd_editFminconOptionsGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before lvd_editFminconOptionsGUI is made visible.
function lvd_editFminconOptionsGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to lvd_editFminconOptionsGUI (see VARARGIN)

% Choose default command line output for lvd_editFminconOptionsGUI
    handles.output = hObject;

    centerUIFigure(hObject);

    fminconOpt = varargin{1};
    setappdata(hObject,'fminconOpt',fminconOpt);

    handles = populateGUI(handles, fminconOpt);

    % Update handles structure
    guidata(hObject, handles);

    % UIWAIT makes lvd_editFminconOptionsGUI wait for user response (see UIRESUME)
    uiwait(handles.lvd_editFminconOptionsGUI);

function handles = populateGUI(handles, fminconOpt)
    options = fminconOpt.getOptions();

    setDocLbl(handles);

    algoListboxStr = LvdFminconAlgorithmEnum.getListBoxStr();
    handles.algoCombo.String = algoListboxStr;
    handles.algoCombo.Value = LvdFminconAlgorithmEnum.getIndForName(options.algorithm.name);

    finiteDiffTypeStrs = FminconFiniteDiffTypeEnum.getListBoxStr();
    handles.finiteDiffTypeCombo.String = finiteDiffTypeStrs;
    handles.finiteDiffTypeCombo.Value = FminconFiniteDiffTypeEnum.getIndForName(options.finDiffType.name);

    typicalXStrs = OptimizerTypicalXEnum.getListBoxStr();
    handles.typicalXCombo.String = typicalXStrs;
    handles.typicalXCombo.Value = OptimizerTypicalXEnum.getIndForName(options.typicalXType.name);

    hessApproxStrs = FminconHessApproxAlgEnum.getListBoxStr();
    handles.IpApproxAlgoCombo.String = hessApproxStrs;
    handles.IpApproxAlgoCombo.Value = FminconHessApproxAlgEnum.getIndForName(options.hessianApproxAlg.name);

    subProbStrs = FminconIpSubprobAlgEnum.getListBoxStr();
    handles.IpSubproblemAlgoCombo.String = subProbStrs;
    handles.IpSubproblemAlgoCombo.Value = FminconIpSubprobAlgEnum.getIndForName(options.subproblemAlgorithm.name);

    useParaStr = FminconUseParallelEnum.getListBoxStr();
    handles.useParallelCombo.String = useParaStr;
    handles.useParallelCombo.Value = FminconUseParallelEnum.getIndForName(options.useParallel.name);

    setOptsDoubleValueStrInGUI(handles, options, 'optTol', 'optTolText');
    setOptsDoubleValueStrInGUI(handles, options, 'tolCon', 'conTolText');
    setOptsDoubleValueStrInGUI(handles, options, 'stepTol', 'stepTolText');

    setOptsDoubleValueStrInGUI(handles, options, 'maxIter', 'maxItersText');
    setOptsDoubleValueStrInGUI(handles, options, 'maxFuncEvals', 'maxFuncEvalsText');

    setOptsDoubleValueStrInGUI(handles, options, 'finDiffStepSize', 'finiteDiffStepSizeText');

    setOptsDoubleValueStrInGUI(handles, options, 'initBarrierParam', 'IpInitBarrierParamText');
    setOptsDoubleValueStrInGUI(handles, options, 'initTrustRegionRadius', 'IpInitTrustRegionRadiusText');
    setOptsDoubleValueStrInGUI(handles, options, 'maxProjCGIter', 'IpMaxProjCGItersText');
    setOptsDoubleValueStrInGUI(handles, options, 'tolProjCG', 'IpRelProjCGTolText');
    setOptsDoubleValueStrInGUI(handles, options, 'tolProjCGAbs', 'IpAbsProjCGTolText');

    setOptsDoubleValueStrInGUI(handles, options, 'funcTol', 'AsFuncTolText');
    setOptsDoubleValueStrInGUI(handles, options, 'maxSQPIter', 'AsMaxSqpItersText');
    setOptsDoubleValueStrInGUI(handles, options, 'relLineSrchBnd', 'AsRelLineSrchBndText');
    setOptsDoubleValueStrInGUI(handles, options, 'relLineSrchBndDuration', 'AsLineSrchBndDurText');
    setOptsDoubleValueStrInGUI(handles, options, 'tolConSQP', 'AsTolConSqpText');

    setOptsDoubleValueStrInGUI(handles, options, 'numWorkers', 'numParaWorkersText');

    handles.computeOptimalStepCheckbox.Value = double(options.computeOptimalStepSizes);
    computeOptimalStepCheckbox_Callback(handles.computeOptimalStepCheckbox, [], handles);

function setDocLbl(handles)
    docLinkLblPos = handles.matlabDocLinkLabel.Position;
    docLinkLblParent = handles.matlabDocLinkLabel.Parent;
    handles.matlabDocLinkLabel.Visible = 'off';

    % Create and display the text label
    url = 'https://www.mathworks.com/help/optim/ug/fmincon.html';
    labelStr = ['
For more information, visit the MATLAB documentation for FMINCON: ' url '
'];
    jLabel = javaObjectEDT('javax.swing.JLabel', labelStr);
    [hjLabel,~] = javacomponent(jLabel, docLinkLblPos, docLinkLblParent);

    % Modify the mouse cursor when hovering on the label
    hjLabel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));

    % Set the mouse-click callback
    set(hjLabel, 'MouseClickedCallback', @(h,e)web([url], '-browser'));

% --- Outputs from this function are returned to the command line.
function varargout = lvd_editFminconOptionsGUI_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
    if(isempty(handles))
        varargout{1} = false;
    else
        fminconOpt = getappdata(hObject,'fminconOpt');
        options = fminconOpt.getOptions();

        algoListboxStr = LvdFminconAlgorithmEnum.getListBoxStr();
        options.algorithm = LvdFminconAlgorithmEnum.getEnumForListboxStr(algoListboxStr{handles.algoCombo.Value});

        finiteDiffTypeStrs = FminconFiniteDiffTypeEnum.getListBoxStr();
        options.finDiffType = FminconFiniteDiffTypeEnum.getEnumForListboxStr(finiteDiffTypeStrs{handles.finiteDiffTypeCombo.Value});

        typicalXStrs = OptimizerTypicalXEnum.getListBoxStr();
        options.typicalXType = OptimizerTypicalXEnum.getEnumForListboxStr(typicalXStrs{handles.typicalXCombo.Value});

        hessApproxStrs = FminconHessApproxAlgEnum.getListBoxStr();
        options.hessianApproxAlg = FminconHessApproxAlgEnum.getEnumForListboxStr(hessApproxStrs{handles.IpApproxAlgoCombo.Value});

        subProbStrs = FminconIpSubprobAlgEnum.getListBoxStr();
        options.subproblemAlgorithm = FminconIpSubprobAlgEnum.getEnumForListboxStr(subProbStrs{handles.IpSubproblemAlgoCombo.Value});

        useParaStrs = FminconUseParallelEnum.getListBoxStr();
        options.useParallel = FminconUseParallelEnum.getEnumForListboxStr(useParaStrs{handles.useParallelCombo.Value});

        setOptsDoubleValueInObject(handles, options, 'optTol', 'optTolText');
        setOptsDoubleValueInObject(handles, options, 'stepTol', 'conTolText');
        setOptsDoubleValueInObject(handles, options, 'tolCon', 'stepTolText');

        setOptsDoubleValueInObject(handles, options, 'maxIter', 'maxItersText');
        setOptsDoubleValueInObject(handles, options, 'maxFuncEvals', 'maxFuncEvalsText');

        setOptsDoubleValueInObject(handles, options, 'finDiffStepSize', 'finiteDiffStepSizeText');

        setOptsDoubleValueInObject(handles, options, 'initBarrierParam', 'IpInitBarrierParamText');
        setOptsDoubleValueInObject(handles, options, 'initTrustRegionRadius', 'IpInitTrustRegionRadiusText');
        setOptsDoubleValueInObject(handles, options, 'maxProjCGIter', 'IpMaxProjCGItersText');
        setOptsDoubleValueInObject(handles, options, 'tolProjCG', 'IpRelProjCGTolText');
        setOptsDoubleValueInObject(handles, options, 'tolProjCGAbs', 'IpAbsProjCGTolText');

        setOptsDoubleValueInObject(handles, options, 'funcTol', 'AsFuncTolText');
        setOptsDoubleValueInObject(handles, options, 'maxSQPIter', 'AsMaxSqpItersText');
        setOptsDoubleValueInObject(handles, options, 'relLineSrchBnd', 'AsRelLineSrchBndText');
        setOptsDoubleValueInObject(handles, options, 'relLineSrchBndDuration', 'AsLineSrchBndDurText');
        setOptsDoubleValueInObject(handles, options, 'tolConSQP', 'AsTolConSqpText');

        setOptsDoubleValueInObject(handles, options, 'numWorkers', 'numParaWorkersText');

        options.computeOptimalStepSizes = logical(handles.computeOptimalStepCheckbox.Value);

        varargout{1} = true;
        close(handles.lvd_editFminconOptionsGUI);
    end

function errMsg = validateInputs(handles)
    errMsg = {};

    errMsg = validateDoubleValue(handles, errMsg, 'optTolText', 'Optimality Tolerance', 0, 1, false);
    errMsg = validateDoubleValue(handles, errMsg, 'conTolText', 'Constraint Tolerance', 0, 1, false);
    errMsg = validateDoubleValue(handles, errMsg, 'stepTolText', 'Step Tolerance', 0, 1, false);

    errMsg = validateDoubleValue(handles, errMsg, 'maxItersText', 'Max Iterations', 0, Inf, true);
    errMsg = validateDoubleValue(handles, errMsg, 'maxFuncEvalsText', 'Max Function Evaluations', 0, Inf, true);

	errMsg = validateDoubleValue(handles, errMsg, 'finiteDiffStepSizeText', 'Finite Difference Step Size', 1E-10, 1E-2, false);

	errMsg = validateDoubleValue(handles, errMsg, 'IpInitBarrierParamText', 'I-P Intial Barrier Param', 1E-10, Inf, false);
    errMsg = validateDoubleValue(handles, errMsg, 'IpInitTrustRegionRadiusText', 'I-P Initial Trust Region', 1E-10, Inf, false);
    errMsg = validateDoubleValue(handles, errMsg, 'IpMaxProjCGItersText', 'I-P Max Projected C.G. Iterations', 1, Inf, true);
    errMsg = validateDoubleValue(handles, errMsg, 'IpRelProjCGTolText', 'I-P Relative Projected C.G. Tolerance', 1E-10, Inf, false);
    errMsg = validateDoubleValue(handles, errMsg, 'IpAbsProjCGTolText', 'I-P Absolute Projected C.G. Tolerance', 1E-10, Inf, false);

    errMsg = validateDoubleValue(handles, errMsg, 'AsFuncTolText', 'A-S Function Tolerance', 1E-10, 1, false);
    errMsg = validateDoubleValue(handles, errMsg, 'AsMaxSqpItersText', 'A-S Max SQP Iterations', 1, Inf, true);
    errMsg = validateDoubleValue(handles, errMsg, 'AsRelLineSrchBndText', 'A-S Relative Line Search Bound', 0, Inf, false);
    errMsg = validateDoubleValue(handles, errMsg, 'AsLineSrchBndDurText', 'A-S Line Search Bound Duration', 1, Inf, true);
    errMsg = validateDoubleValue(handles, errMsg, 'AsTolConSqpText', 'A-S Inner SQP Constraint Tolerance', 1E-10, Inf, false);

    errMsg = validateDoubleValue(handles, errMsg, 'numParaWorkersText', 'Number of Parallel Workers', 1, feature('numCores'), true);

function optTolText_Callback(hObject, eventdata, handles)
% hObject    handle to optTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of optTolText as text
%        str2double(get(hObject,'String')) returns contents of optTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function optTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to optTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function conTolText_Callback(hObject, eventdata, handles)
% hObject    handle to conTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of conTolText as text
%        str2double(get(hObject,'String')) returns contents of conTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function conTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to conTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function stepTolText_Callback(hObject, eventdata, handles)
% hObject    handle to stepTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of stepTolText as text
%        str2double(get(hObject,'String')) returns contents of stepTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function stepTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to stepTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in algoCombo.
function algoCombo_Callback(hObject, eventdata, handles)
% hObject    handle to algoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns algoCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from algoCombo

% --- Executes during object creation, after setting all properties.
function algoCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to algoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function maxItersText_Callback(hObject, eventdata, handles)
% hObject    handle to maxItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of maxItersText as text
%        str2double(get(hObject,'String')) returns contents of maxItersText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function maxItersText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to maxItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function maxFuncEvalsText_Callback(hObject, eventdata, handles)
% hObject    handle to maxFuncEvalsText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of maxFuncEvalsText as text
%        str2double(get(hObject,'String')) returns contents of maxFuncEvalsText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function maxFuncEvalsText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to maxFuncEvalsText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in finiteDiffTypeCombo.
function finiteDiffTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to finiteDiffTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns finiteDiffTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from finiteDiffTypeCombo

% --- Executes during object creation, after setting all properties.
function finiteDiffTypeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to finiteDiffTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function finiteDiffStepSizeText_Callback(hObject, eventdata, handles)
% hObject    handle to finiteDiffStepSizeText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of finiteDiffStepSizeText as text
%        str2double(get(hObject,'String')) returns contents of finiteDiffStepSizeText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function finiteDiffStepSizeText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to finiteDiffStepSizeText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in typicalXCombo.
function typicalXCombo_Callback(hObject, eventdata, handles)
% hObject    handle to typicalXCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns typicalXCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from typicalXCombo

% --- Executes during object creation, after setting all properties.
function typicalXCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to typicalXCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in IpApproxAlgoCombo.
function IpApproxAlgoCombo_Callback(hObject, eventdata, handles)
% hObject    handle to IpApproxAlgoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns IpApproxAlgoCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from IpApproxAlgoCombo

% --- Executes during object creation, after setting all properties.
function IpApproxAlgoCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpApproxAlgoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function IpInitBarrierParamText_Callback(hObject, eventdata, handles)
% hObject    handle to IpInitBarrierParamText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of IpInitBarrierParamText as text
%        str2double(get(hObject,'String')) returns contents of IpInitBarrierParamText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function IpInitBarrierParamText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpInitBarrierParamText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function IpInitTrustRegionRadiusText_Callback(hObject, eventdata, handles)
% hObject    handle to IpInitTrustRegionRadiusText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of IpInitTrustRegionRadiusText as text
%        str2double(get(hObject,'String')) returns contents of IpInitTrustRegionRadiusText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function IpInitTrustRegionRadiusText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpInitTrustRegionRadiusText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function IpMaxProjCGItersText_Callback(hObject, eventdata, handles)
% hObject    handle to IpMaxProjCGItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of IpMaxProjCGItersText as text
%        str2double(get(hObject,'String')) returns contents of IpMaxProjCGItersText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function IpMaxProjCGItersText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpMaxProjCGItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in IpSubproblemAlgoCombo.
function IpSubproblemAlgoCombo_Callback(hObject, eventdata, handles)
% hObject    handle to IpSubproblemAlgoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns IpSubproblemAlgoCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from IpSubproblemAlgoCombo

% --- Executes during object creation, after setting all properties.
function IpSubproblemAlgoCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpSubproblemAlgoCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function IpRelProjCGTolText_Callback(hObject, eventdata, handles)
% hObject    handle to IpRelProjCGTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of IpRelProjCGTolText as text
%        str2double(get(hObject,'String')) returns contents of IpRelProjCGTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function IpRelProjCGTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpRelProjCGTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function IpAbsProjCGTolText_Callback(hObject, eventdata, handles)
% hObject    handle to IpAbsProjCGTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of IpAbsProjCGTolText as text
%        str2double(get(hObject,'String')) returns contents of IpAbsProjCGTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function IpAbsProjCGTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to IpAbsProjCGTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in saveAndCloseButton.
function saveAndCloseButton_Callback(hObject, eventdata, handles)
% hObject    handle to saveAndCloseButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    errMsg = validateInputs(handles);

    if(isempty(errMsg))
        uiresume(handles.lvd_editFminconOptionsGUI);
    else
        msgbox(errMsg,'Invalid FMINCON Options Inputs','error');
    end

function AsTolConSqpText_Callback(hObject, eventdata, handles)
% hObject    handle to AsTolConSqpText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AsTolConSqpText as text
%        str2double(get(hObject,'String')) returns contents of AsTolConSqpText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function AsTolConSqpText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AsTolConSqpText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function AsLineSrchBndDurText_Callback(hObject, eventdata, handles)
% hObject    handle to AsLineSrchBndDurText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AsLineSrchBndDurText as text
%        str2double(get(hObject,'String')) returns contents of AsLineSrchBndDurText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function AsLineSrchBndDurText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AsLineSrchBndDurText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function AsRelLineSrchBndText_Callback(hObject, eventdata, handles)
% hObject    handle to AsRelLineSrchBndText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AsRelLineSrchBndText as text
%        str2double(get(hObject,'String')) returns contents of AsRelLineSrchBndText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function AsRelLineSrchBndText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AsRelLineSrchBndText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function AsMaxSqpItersText_Callback(hObject, eventdata, handles)
% hObject    handle to AsMaxSqpItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AsMaxSqpItersText as text
%        str2double(get(hObject,'String')) returns contents of AsMaxSqpItersText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function AsMaxSqpItersText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AsMaxSqpItersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function AsFuncTolText_Callback(hObject, eventdata, handles)
% hObject    handle to AsFuncTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of AsFuncTolText as text
%        str2double(get(hObject,'String')) returns contents of AsFuncTolText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function AsFuncTolText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to AsFuncTolText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in useParallelCombo.
function useParallelCombo_Callback(hObject, eventdata, handles)
% hObject    handle to useParallelCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns useParallelCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from useParallelCombo

% --- Executes during object creation, after setting all properties.
function useParallelCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to useParallelCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function numParaWorkersText_Callback(hObject, eventdata, handles)
% hObject    handle to numParaWorkersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of numParaWorkersText as text
%        str2double(get(hObject,'String')) returns contents of numParaWorkersText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function numParaWorkersText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to numParaWorkersText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in computeOptimalStepCheckbox.
function computeOptimalStepCheckbox_Callback(hObject, eventdata, handles)
% hObject    handle to computeOptimalStepCheckbox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of computeOptimalStepCheckbox
    if(get(hObject,'Value'))
        handles.finiteDiffStepSizeText.Enable = 'off';
    else
        handles.finiteDiffStepSizeText.Enable = 'on';
    end


function x = p00_root ( prob, i )

%*****************************************************************************80
%
%% P00_ROOT returns a known root for any problem.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    15 January 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer PROB, the number of the problem.
%
%    Input, integer I, the index of the root to return.
%
%    Output, real X, the I-th root.
%
  if ( prob == 1 )
    x = p01_root ( i );
  elseif ( prob == 2 )
    x = p02_root ( i );
  elseif ( prob == 3 )
    x = p03_root ( i );
  elseif ( prob == 4 )
    x = p04_root ( i );
  elseif ( prob == 5 )
    x = p05_root ( i );
  elseif ( prob == 6 )
    x = p06_root ( i );
  elseif ( prob == 7 )
    x = p07_root ( i );
  elseif ( prob == 8 )
    x = p08_root ( i );
  elseif ( prob == 9 )
    x = p09_root ( i );
  elseif ( prob == 10 )
    x = p10_root ( i );
  elseif ( prob == 11 )
    x = p11_root ( i );
  elseif ( prob == 12 )
    x = p12_root ( i );
  elseif ( prob == 13 )
    x = p13_root ( i );
  elseif ( prob == 14 )
    x = p14_root ( i );
  elseif ( prob == 15 )
    x = p15_root ( i );
  elseif ( prob == 16 )
    x = p16_root ( i );
  elseif ( prob == 17 )
    x = p17_root ( i );
  elseif ( prob == 18 )
    x = p18_root ( i );
  elseif ( prob == 19 )
    x = p19_root ( i );
  else
    fprintf ( 1, '\n' );
    fprintf ( 1, 'P00_ROOT - Fatal error!\n' );
    fprintf ( 1, '  Illegal problem number = %d\n', prob );
    error ( 'P00_ROOT - Fatal error!' );
  end

  return
end


function imu=readimu(opt,fname)

global glc gls
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);
fprintf('Info:reading imu file %s...',fname0);

ts=str2time(opt.ts); te=str2time(opt.te);
imu=gls.imu; ins=opt.ins;
NMAX=200000; imu.data=repmat(gls.imud,NMAX,1);
imudata=csvread(fname,1,0); n=size(imudata,1);

if ins.data_format==1
    dt=1/ins.sample_rate;
    for i=1:n
        time=gpst2time(imudata(i,1),imudata(i,2));
        if ts.time~=0&&timediff(time,ts)<0,continue;end
        if te.time~=0&&timediff(time,te)>0,continue;end

        if imu.n+1>size(imu.data,1)
            imu.data(imu.n+1:imu.n+NMAX)=repmat(gls.imud,NMAX,1);
        end
        imu.data(imu.n+1).time=time;
        imu.data(imu.n+1).dw(1:3)=imudata(i,3:5)*dt;
        imu.data(imu.n+1).dv(1:3)=imudata(i,6:8)*dt;
        imu.n=imu.n+1;
    end
elseif ins.data_format==2
    for i=1:n
        time=gpst2time(imudata(i,1),imudata(i,2));
        if ts.time~=0&&timediff(time,ts)<0,continue;end
        if te.time~=0&&timediff(time,te)>0,continue;end

        if imu.n+1>size(imu.data,1)
            imu.data(imu.n+1:imu.n+NMAX)=repmat(gls.imud,NMAX,1);
        end
        imu.data(imu.n+1).time=time;
        imu.data(imu.n+1).dw(1:3)=imudata(i,3:5);
        imu.data(imu.n+1).dv(1:3)=imudata(i,6:8);
        imu.n=imu.n+1;
    end
end

if imu.n<size(imu.data,1)
    imu.data(imu.n+1:end,:)=[];
end

fprintf('over\n');

return


function roi = roiLoad(pth, format, referenceMR);
% Load a mrVista2 ROI.
%
% roi = roiLoad(<pth='dialog'>, <format='Inplane'>, <referenceMR>);
%
% Possible formats are 'Inplane' (mrVista Inplane ROI),
% 'Volume' (mrVista Volume/Gray ROI), and 'mat' (saved MATLAB file,
% mrVista2 format).
%
% ras, 02/24/07.
if notDefined('pth')
	pth = mrvSelectFile('r', 'mat', [], 'Select an ROI to Load');
end

if notDefined('format'),	format = 'Inplane';		end

if exist(pth, 'file') | exist([pth '.mat'], 'file')
	roi = load(pth);
else
	error(sprintf('ROI path %s not found. ', pth))
end

% if we successfully loaded an ROI file, check for
% the format: first check if it's a mrVista 1 ROI:
fields = fieldnames(roi);
if ismember(fields, 'ROI')
	% it's a mrVista 1 ROI: use mrVista-specific tools
	% to parse it
	mrGlobals2;
	roi = roi.ROI; % subsume ROI struct, only thing of interest
	if isequal(lower(roi.viewType), 'inplane')
		reference = 'Inplane';
		referenceMR = fullfile(HOMEDIR, 'Inplane', 'anat.mat');
		voxelSize = mrSESSION(1).inplanes.voxelSize;
	elseif ismember(lower(roi.viewType), {'volume', 'gray'})
		reference = 'I|P|R';
		if notDefined('referenceMR')
			referenceMR = mrLoadHeader(getVAnatomyPath);
		else
			referenceMR = mrParse(referenceMR);
		end
		voxelSize = referenceMR.voxelSize(1:3);
	else
		error('ROI view type not supported yet.')

	end

	template = roiCreate(reference, roi.coords, 'color', roi.color, ...
					'name', roi.name, 'voxelSize', voxelSize, ...
					'referenceMR', referenceMR);
	for f = setdiff( fieldnames(template), fieldnames(roi) )'
		roi.(f{1}) = template.(f{1});
	end

	for f = setdiff( fieldnames(roi), fieldnames(template) )'
		roi = rmfield(roi, f{1});
	end

	return
end

return


function [efeaturesdj, adjlistdj] = mcmcGetAllEdgeData(spfeatures, imsegs, adjlist)

for f = 1:numel(imsegs)
    disp([num2str(f) ': getting edge data'])
    npertype = imsegs(f).nseg*4;
    [efeaturesdj{f}, adjlistdj{f}] = mcmcGetDisjointEdgeData(imsegs(f), spfeatures{f},  npertype, adjlist{f});
    disp(num2str([imsegs(f).nseg size(adjlist{f}, 1) size(adjlistdj{f},1)]))
end


function sS=transpose(sS)
% transpose list of slipSystem

sS.b = sS.b.';
sS.l = sS.l.';
sS.u = sS.u.';


function [varargout] = read_nex5(filename, varargin)

% READ_NEX5 reads header or data from a Nex Technologies *.nex5 file,
% which is a file containing action-potential (spike) timestamps and waveforms
% (spike channels), event timestamps (event channels), and continuous
% variable data (continuous A/D channels).
%
% LFP and spike waveform data that is returned by this function is
% expressed in microVolt.
%
% Use as
%   [hdr] = read_nex5(filename)
%   [dat] = read_nex5(filename, ...)
%   [dat1, dat2, dat3, hdr] = read_nex5(filename, ...)
%
% Optional arguments should be specified in key-value pairs and can be
%   header      structure with header information
%   feedback    0 or 1
%   tsonly      0 or 1, read only the timestamps and not the waveforms
%   channel     number, or list of numbers (that will result in multiple outputs)
%   begsample   number (for continuous only)
%   endsample   number (for continuous only)
%
% See also READ_NEX5_HEADER
%
% Copyright (C) 2020 Robert Oostenveld, Alex Kirillov
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% parse the optional input arguments
hdr       = ft_getopt(varargin, 'header');
channel   = ft_getopt(varargin, 'channel');
feedback  = ft_getopt(varargin, 'feedback', false);
tsonly    = ft_getopt(varargin, 'tsonly', false);
begsample = ft_getopt(varargin, 'begsample', 1);
endsample = ft_getopt(varargin, 'endsample', inf);

% start with empty return values and empty data
varargout = {};

if isempty(hdr)
  if feedback, fprintf('reading header from %s\n', filename); end
  hdr = read_nex5_header(filename);
  if hdr.FileHeader.NumVars<1
    ft_error('no channels present in file');
  end
end

% use Matlab for automatic byte-ordering
fid = fopen_or_error(filename, 'r', 'ieee-le');

for i=1:length(channel)
  chan = channel(i);
  vh = hdr.VarHeader(chan);
  clear buf
  status = fseek(fid, vh.DataOffset, 'bof');
  if status < 0;  ft_error('error with fseek');  end
  switch vh.Type
    case 0
      % Neurons, only timestamps
      buf.ts = Nex5ReadTimestamps(fid, vh);

    case 1
      % Events, only timestamps
      buf.ts = Nex5ReadTimestamps(fid, vh);

    case 2
      % Interval variables
      buf.begs = Nex5ReadTimestamps(fid, vh);
      buf.ends = Nex5ReadTimestamps(fid, vh);

    case 3
      % Waveform variables
      buf.ts = Nex5ReadTimestamps(fid, vh);
      if ~tsonly
        if vh.ContDataType == 0
          buf.dat = fread(fid, [vh.NumberOfDataPoints vh.Count], 'int16');
        else
          buf.dat = fread(fid, [vh.NumberOfDataPoints vh.Count], 'float32');
        end
        % convert the AD values to miliVolt, subsequently convert from miliVolt to microVolt
        buf.dat = (buf.dat * vh.ADtoUnitsCoefficient + vh.UnitsOffset) * 1000;
      end

    case 4
      % Population vector
      ft_error('population vectors are not supported');

    case 5
      % Continuously recorded variables
      buf.ts = Nex5ReadTimestamps(fid, vh);
      if vh.ContIndexOfFirstPointInFragmentDataType == 0
        buf.indx = fread(fid, [1 vh.Count], 'uint32');
      else
        buf.indx = fread(fid, [1 vh.Count], 'uint64');
      end
      if vh.Count>1 && (begsample~=1 || endsample~=inf)
        ft_error('reading selected samples from multiple AD segments is not supported');
      end
      if ~tsonly
        numsamples = min(endsample - begsample + 1, vh.NumberOfDataPoints);
        status = fseek(fid, (begsample-1)*2, 'cof');
        if status < 0;  ft_error('error with fseek');  end
        if vh.ContDataType == 0
          buf.dat  = fread(fid, [1 numsamples], 'int16');
        else
          buf.dat  = fread(fid, [1 numsamples], 'float32');
        end
        % convert the AD values to miliVolt, subsequently convert from milliVolt to microVolt
        buf.dat = (buf.dat * vh.ADtoUnitsCoefficient + vh.UnitsOffset) * 1000;
      end

    case 6
      % Markers
      buf.ts = Nex5ReadTimestamps(fid, vh);
      for j=1:vh.NumberOfMarkerFields
        buf.MarkerNames{j,1} = fread(fid, [1 64], 'uint8=>char');
        if vh.MarkerDataType == 0
          for k=1:vh.Count
            buf.MarkerValues{j,k} = fread(fid, [1 vh.MarkerLength], 'uint8=>char');
          end
        else
          buf.MarkerValues{j} = fread(fid, vh.Count, 'uint32');
        end
      end

    otherwise
      ft_error('incorrect channel type');
  end % switch channel type

  % return the data of this channel
  varargout{i} = buf;
end % for channel

% always return the header as last
varargout{end+1} = hdr;

fclose(fid);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% subfunction to read nex5 timestamps
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ts = Nex5ReadTimestamps(fid, varHeader)
if varHeader.TimestampDataType == 0
  ts = fread(fid, [1 varHeader.Count], 'int32');
else
  ts = fread(fid, [1 varHeader.Count], 'int64');
end
end