function mhd = read_itab_mhd(filename)

fid = fopen(filename, 'rb');

%  Name of structure
mhd.stname = fread(fid, [1 10], 'uint8=>char');           %  Header identifier  (VP_BIOMAG)
mhd.stver = fread(fid, [1 8], 'uint8=>char');             %  Header version
mhd.stendian = fread(fid, [1 4], 'uint8=>char');          %  LE (little endian) or BE (big endian) format

%  Subject's INFOs
mhd.first_name = fread(fid, [1 32], 'uint8=>char');       %  Subject's first name
mhd.last_name = fread(fid, [1 32], 'uint8=>char');        %  Subject's family name
mhd.id = fread(fid, [1 32], 'uint8=>char');               %  Subject's id
mhd.notes = fread(fid, [1 256], 'uint8=>char');           %  Notes on measurement

%  Other subj infos
mhd.subj_info.sex         = fread(fid, [1 1], 'uint8=>char');  %  Sex (M or F)
pad = fread(fid, [1 5], 'uint8');
mhd.subj_info.notes       = fread(fid, [1 256], 'uint8=>char'); %  Notes on subject
mhd.subj_info.height      = fread(fid, [1 1], 'float');  %  Height in cm
mhd.subj_info.weight      = fread(fid, [1 1], 'float');  %  Weight in kg
mhd.subj_info.birthday    = fread(fid, [1 1], 'int32'); %  Birtday (1-31)
mhd.subj_info.birthmonth  = fread(fid, [1 1], 'int32'); %  Birthmonth (1-12)
mhd.subj_info.birthyear   = fread(fid, [1 1], 'int32');  %  Birthyear (1900-2002)

%  Data acquisition INFOs
mhd.time = fread(fid, [1 12], 'uint8=>char');             %  time (ascii)
mhd.date = fread(fid, [1 16], 'uint8=>char');             %  date (ascii)

mhd.nchan     = fread(fid, [1 1], 'int32');          %  total number of channels
mhd.nelech    = fread(fid, [1 1], 'int32');          %  number of electric channels
mhd.nelerefch = fread(fid, [1 1], 'int32');          %  number of electric reference channels
mhd.nmagch    = fread(fid, [1 1], 'int32');          %  number of magnetic channels
mhd.nmagrefch = fread(fid, [1 1], 'int32');          %  number of magnetic reference channels
mhd.nauxch    = fread(fid, [1 1], 'int32');          %  number of auxiliary channels
mhd.nparamch  = fread(fid, [1 1], 'int32');          %  number of parameter channels
mhd.ndigitch  = fread(fid, [1 1], 'int32');          %  number of digit channels
mhd.nflagch   = fread(fid, [1 1], 'int32');          %  number of flag channels

mhd.data_type   = fread(fid, [1 1], 'int32');        %  0 - BE_SHORT      (HP-PA, big endian)
%  1 - BE_LONG       (HP-PA, big endian)
%  2 - BE_FLOAT      (HP-PA, big endian)
%  3 - LE_SHORT      (Intel, little endian)
%  4 - LE_LONG       (Intel, little endian)
%  5 - LE_FLOAT      (Intel, little endian)
%  6 - RTE_A_SHORT   (HP-A900, big endian)
%  7 - RTE_A_FLOAT   (HP-A900, big endian)
%  8 - ASCII

mhd.smpfq       = fread(fid, [1 1], 'single');        %  sampling frequency in Hz
mhd.hw_low_fr   = fread(fid, [1 1], 'single');        %  hw data acquisition low pass filter
mhd.hw_hig_fr   = fread(fid, [1 1], 'single');        %  hw data acquisition high pass filter
mhd.hw_comb     = fread(fid, [1 1], 'int32');        %  hw data acquisition 50 Hz filter  (1-TRUE)
mhd.sw_hig_tc   = fread(fid, [1 1], 'single');        %  sw data acquisition high pass time constant
mhd.compensation= fread(fid, [1 1], 'int32');        %  0 - no compensation    1 - compensation
mhd.ntpdata     = fread(fid, [1 1], 'int32');        %  total number of time points in data

mhd.no_segments    = fread(fid, [1 1], 'int32');     %  Number of segments described in the segment structure

%  INFOs on different segments
for i=1:5
  mhd.sgmt(i).start = fread(fid, [1 1], 'int32');       %  Starting time point from beginning of data
  mhd.sgmt(i).ntptot = fread(fid, [1 1], 'int32');      %  Total number of time points
  mhd.sgmt(i).type = fread(fid, [1 1], 'int32');
  mhd.sgmt(i).no_samples = fread(fid, [1 1], 'int32');
  mhd.sgmt(i).st_sample = fread(fid, [1 1], 'int32');
end

mhd.nsmpl          = fread(fid, [1 1], 'int32');     %  Overall number of samples

%  INFOs on different samples
for i=1:4096
  mhd.smpl(i).start = fread(fid, [1 1], 'int32');       %  Starting time point from beginning of data
  mhd.smpl(i).ntptot = fread(fid, [1 1], 'int32');      %  Total number of time points
  mhd.smpl(i).ntppre = fread(fid, [1 1], 'int32');      %  Number of points in pretrigger
  mhd.smpl(i).type = fread(fid, [1 1], 'int32');
  mhd.smpl(i).quality = fread(fid, [1 1], 'int32');
end

mhd.nrefchan        = fread(fid, [1 1], 'int32');    %  number of reference channels
mhd.ref_ch = fread(fid, [1 640], 'int32');          %  reference channel list
mhd.ntpref          = fread(fid, [1 1], 'int32');    %  total number of time points in reference

%  Header INFOs
mhd.raw_header_type   = fread(fid, [1 1], 'int32');  %  0  - Unknown header
%  2  - rawfile (A900)
%  3  - GE runfile header
%  31 - ATB runfile header version 1.0
%  41 - IFN runfile header version 1.0
%  51 - BMDSys runfile header version 1.0

mhd.header_type     = fread(fid, [1 1], 'int32');    %  0  - Unknown header
%  2  - rawfile (A900)
%  3  - GE runfile header
%  4  - old header
%  10 - 256ch normal header
%  11 - 256ch master header
%  20 - 640ch normal header
%  21 - 640ch master header
%  31 - ATB runfile header version 1.0
%  41 - IFN runfile header version 1.0
%  51 - BMDSys runfile header version 1.0

mhd.conf_file = fread(fid, [1 64], 'uint8=>char');        %  Filename used for data acquisition configuration

mhd.header_size      = fread(fid, [1 1], 'int32');   %  sizeof(header) at the time of file creation
mhd.start_reference  = fread(fid, [1 1], 'int32');   %  start reference
mhd.start_data       = fread(fid, [1 1], 'int32');   %  start data

mhd.rawfile          = fread(fid, [1 1], 'int32');   %  0 - not a rawfile      1 - rawfile
mhd.multiplexed_data = fread(fid, [1 1], 'int32');   %  0 - FALSE              1 - TRUE

mhd.isns        = fread(fid, [1 1], 'int32');     %  sensor code   1 - Single channel
%               28 - Original Rome 28 ch.
%               29 -  ..............
%               .. -  ..............
%               45 - Updated Rome 28 ch. (spring 2009)
%               .. -  ..............
%               .. -  ..............
%               55 - Original Chieti 55 ch. flat
%              153 - Original Chieti 153 ch. helmet
%              154 - Chieti 153 ch. helmet from Jan 2002

%  Channel's INFOs
for i=1:640
  mhd.ch(i).type = fread(fid, [1 1], 'uint8');
  pad = fread(fid, [1 3], 'uint8');
  %  type      0 - unknown
  %            1 - ele
  %            2 - mag
  %            4 - ele ref
  %            8 - mag ref
  %           16 - aux
  %           32 - param
  %           64 - digit
  %          128 - flag
  mhd.ch(i).number = fread(fid, [1 1], 'int32');         %  number
  mhd.ch(i).label = fixstr(fread(fid, [1 16], 'uint8=>char'));      %  label
  mhd.ch(i).flag = fread(fid, [1 1], 'uint8');
  pad = fread(fid, [1 3], 'uint8');
  %  on/off flag 0 - working channel
  %              1 - noisy channel
  %              2 - very noisy channel
  %              3 - broken channel
  mhd.ch(i).amvbit = fread(fid, [1 1], 'float');         %  calibration from LSB to mV
  mhd.ch(i).calib = fread(fid, [1 1], 'float');          %  calibration from mV to unit
  mhd.ch(i).unit = fread(fid, [1 6], 'uint8=>char');  %  unit label  (fT, uV, ...)
  pad = fread(fid, [1 2], 'uint8');

  %  Calibration to Tesla for (MEG, MEG REF) or Volt for (EEG, EEG REF)
  mhd.ch(i).unit = deblank(mhd.ch(i).unit);
  switch (mhd.ch(i).unit)
      case 'fT'
          mhd.ch(i).calib = mhd.ch(i).calib / 1.E-15;
      case 'pT'
          mhd.ch(i).calib = mhd.ch(i).calib / 1.E-12;
      case 'uV'
          mhd.ch(i).calib = mhd.ch(i).calib / 1.E-6;
      case 'mV'
          mhd.ch(i).calib = mhd.ch(i).calib / 1.E-3;
  end

  mhd.ch(i).ncoils = fread(fid, [1 1], 'int32');     %  number of coils building up one channel
  mhd.ch(i).wgt = fread(fid, [1 10], 'float');       %  weight of coils
  %  position and orientation of coils
  for j=1:10
    mhd.ch(i).position(j).r_s = fread(fid, [1 3], 'float');
    mhd.ch(i).position(j).u_s = fread(fid, [1 3], 'float');
  end
end

%  Sensor position INFOs

mhd.r_center = fread(fid, [1 3], 'float');          %  sensor position in convenient format
mhd.u_center = fread(fid, [1 3], 'float');
mhd.th_center      = fread(fid, [1 1], 'float');  %  sensor orientation as from markers fit
mhd.fi_center= fread(fid, [1 1], 'float');
mhd.rotation_angle= fread(fid, [1 1], 'float');
mhd.cosdir = fread(fid, [3 3], 'float');          %  for compatibility only
mhd.irefsys      = fread(fid, [1 1], 'int32');    %  reference system   0 - sensor reference system
%                     1 - Polhemus
%                     2 - head3
%                     3 - MEG

%  Marker positions for MRI integration
mhd.num_markers  = fread(fid, [1 1], 'int32');  %  Total number of markers
mhd.i_coil = fread(fid, [1 64], 'int32');       %  Markers to be used to find sensor position
mhd.marker = fread(fid, [3 64], 'float');       %  Position of all the markers  -  MODIFIED VP
mhd.best_chi     = fread(fid, [1 1], 'float');  %  Best chi_square value obtained in finding sensor position

mhd.cup_vertex_center  = fread(fid, [1 1], 'float');    %  dist anc sensor  cente vertex  (as entered
%  from keyboard)
mhd.cup_fi_center  = fread(fid, [1 1], 'float');        %  fi angle of sensor center
mhd.cup_rotation_angle  = fread(fid, [1 1], 'float');   %  rotation angle of sensor center axis

mhd.dist_a1_a2  = fread(fid, [1 1], 'float');           %  head informations
%  (used to find subject's head dimensions)
mhd.dist_inion_nasion = fread(fid, [1 1], 'float');
mhd.max_circ = fread(fid, [1 1], 'float');
mhd.nasion_vertex_inion = fread(fid, [1 1], 'float');

%  Data analysis INFOs
mhd.security  = fread(fid, [1 1], 'int32');          %  security flag
mhd.ave_alignement  = fread(fid, [1 1], 'int32');    %  average data alignement 0 - FALSE
%                          1 - TRUE

mhd.itri  = fread(fid, [1 1], 'int32');              %  trigger channel number
mhd.ntpch  = fread(fid, [1 1], 'int32');             %  no. of time points per channel
mhd.ntppre  = fread(fid, [1 1], 'int32');            %  no. of time points of pretrigger
mhd.navrg  = fread(fid, [1 1], 'int32');             %  no. of averages
mhd.nover  = fread(fid, [1 1], 'int32');             %  no. of discarded averages
mhd.nave_filt  = fread(fid, [1 1], 'int32');         %  no. of applied filters

%  Filters used before average
for i=1:15
  mhd.ave_filt(i).type = fread(fid, [1 1], 'int32');                 % type   0 - no filter
  %        1 - bandpass  - param[0]: highpass freq
  %                      - param[1]: lowpass freq
  %        2 - notch     - param[0]: notch freq 1
  %                        param[1]: notch freq 2
  %                        param[2]: notch freq 3
  %                        param[3]: notch freq 4
  %                        param[4]: span
  %        3 - artifact  - param[0]: True/False
  %        4 - adaptive  - param[0]: True/False
  %        5 - rectifier - param[0]: True/False
  %        6 - heart     - param[0]: True/False
  %        7 - evoked    - param[0]: True/False
  %        8 - derivate  - param[0]: True/False
  %        9 - polarity  - param[0]: True/False
  mhd.ave_filt(i).param = fread(fid, [1 5], 'float');             % up to 5 filter parameters
end

mhd.stdev  = fread(fid, [1 1], 'int32');             %  0 - not present
mhd.bas_start  = fread(fid, [1 1], 'int32');         %  starting data points for baseline
mhd.bas_end  = fread(fid, [1 1], 'int32');           %  ending data points for baseline

mhd.source_files  = fread(fid, [1 32], 'int32');  %  Progressive number of files (if more than one)

%  template INFOs
mhd.ichtpl = fread(fid, [1 1], 'int32');
mhd.ntptpl = fread(fid, [1 1], 'int32');
mhd.ifitpl = fread(fid, [1 1], 'int32');
mhd.corlim = fread(fid, [1 1], 'float');

%  Filters used before template
for i=1:15
  mhd.tpl_filt(i).type = fread(fid, [1 1], 'int32');                 % type   0 - no filter
  %        1 - bandpass  - param[0]: highpass freq
  %                      - param[1]: lowpass freq
  %        2 - notch     - param[0]: notch freq 1
  %                        param[1]: notch freq 2
  %                        param[2]: notch freq 3
  %                        param[3]: notch freq 4
  %                        param[4]: span
  %        3 - artifact  - param[0]: True/False
  %        4 - adaptive  - param[0]: True/False
  %        5 - rectifier - param[0]: True/False
  %        6 - heart     - param[0]: True/False
  %        7 - evoked    - param[0]: True/False
  %        8 - derivate  - param[0]: True/False
  %        9 - polarity  - param[0]: True/False
  mhd.tpl_filt(i).param = fread(fid, [1 5], 'float');             % up to 5 filter parameters
end

%  Just in case info
mhd.dummy = fread(fid, [1 64], 'int32');
% there seems to be more dummy data at the end...

fclose(fid);

function str = fixstr(str)
sel = find(str==0, 1, 'first');
if ~isempty(sel)
  str = str(1:sel-1);
end


function tidepl()
    %  tidpl  plots a time depth plot of the seismicity
    %  Stefan Wiemer 5/95
    %
    %TODO delete this, replaced by TimeDepthPlotter.plot(catalog)
    global maepi dep1 dep2 dep3 newt2 ms6 ty1 ty2 ty3 a wex wey
    report_this_filefun(mfilename('fullpath'));

    newcat = a;
    xt2  = [ ];
    meand = [ ];
    er = [];
    ind = 0;

    % Find out of figure already exists
    %
    figNumber = findobj(0,'Tag','time_depth_figure');

    % Set up the Seismicity Map window Enviroment
    %
    if isempty(figNumber)

        figNumber = figure_w_normalized_uicontrolunits(...
            'Name','Time Depth',...
            'visible','off',...
            'NumberTitle','off', ...
            'MenuBar','none', ...
            'NextPlot','new', ...
            'Tag','time_depth_figure',...
            'Units','Pixel',  'Position',[wex wey 550 400'])
        hold on
        matdraw

        % Make the menu to change symbol size and type
        %
        symbolmenu = uimenu('Label',' Symbol ');
        SizeMenu = uimenu(symbolmenu,'Label',' Symbol Size ');
        TypeMenu = uimenu(symbolmenu,'Label',' Symbol Type ');
        uimenu(SizeMenu,'Label','3','Callback','ms6 =3;eval(cal6)');
        uimenu(SizeMenu,'Label','6','Callback','ms6 =6;eval(cal6)');
        uimenu(SizeMenu,'Label','9','Callback','ms6 =9;eval(cal6)');
        uimenu(SizeMenu,'Label','12','Callback','ms6 =12;eval(cal6)');
        uimenu(SizeMenu,'Label','14','Callback','ms6 =14;eval(cal6)');
        uimenu(SizeMenu,'Label','18','Callback','ms6 =18;eval(cal6)');
        uimenu(SizeMenu,'Label','24','Callback','ms6 =24;eval(cal6)');

        uimenu(TypeMenu,'Label','dot',...
            'Callback','ty1=''.'';ty2=''.'';ty3=''.'';eval(cal6)');
        uimenu(TypeMenu,'Label','red+ blue o green x',...
            'Callback','ty1=''+'';ty2=''o'';ty3=''x'';eval(cal6)');
        uimenu(TypeMenu,'Label','o','Callback',...
            'ty1=''o'';ty2=''o'';ty3=''o'';eval(cal6)');
        uimenu(TypeMenu,'Label','x','Callback',...
            'ty1=''x'';ty2=''x'';ty3=''x'';eval(cal6)');
        uimenu(TypeMenu,'Label','*',...
            'Callback','ty1=''*'';ty2=''*'';ty3=''*'';eval(cal6)');
        uimenu(TypeMenu,'Label','none','Callback','set(deplo1,''visible'',''off'');set(deplo2,''visible'',''off'');set(deplo3,''visible'',''off''); ');
        cal6 = ...
            [ 'set(deplo1,''MarkerSize'',ms6,''LineStyle'',ty1,''visible'',''on'');',...
            'set(deplo2,''MarkerSize'',ms6,''LineStyle'',ty2,''visible'',''on'');',...
            'set(deplo3,''MarkerSize'',ms6,''LineStyle'',ty3,''visible'',''on'');' ];

    end  % if figure exist
    figure(figNumber)
    p5 = findobj(figNumber,'Tag','time_depth_plot');%assumes we only need one plot
    if isempty(p5)
        orient tall
        rect = [0.15, 0.15, 0.75, 0.65];
        p5 = gca;
        p5.Tag = 'time_depth_plot';
        p5.Position = rect;
    end

    depidx = newt2.Depth<=dep1;
    plotTimeDepthSection(p5, newt2, depidx, [ty1 'b'], 'shallower', 'timedepth_depths1');
    %{
    deplo1 = findobj(p5,'Tag','timedepth_depths1');
    if isempty(deplo1)
        deplo1 =plot(p5, newt2.Date(depidx), -newt2.Depth(depidx),'.b','DisplayName','shallower','Tag','timedepth_depths1');
    else
        set(deplo1,'Xdata',newt2.Date(depidx),'YData',newt2.Depth(depidx));
    end
    set(deplo1,'MarkerSize',ms6,'Marker',ty1)
    %}
    hold on

    depidx = newt2.Depth<=dep2&newt2.Depth>dep1;
    plotTimeDepthSection(p5, newt2, depidx, [ty2 'g'], 'mid-depth', 'timedepth_depths2');

    %deplo2 =plot(p5, newt2.Date(depidx),-newt2.Depth(depidx),'.g','DisplayName','mid-depth','Tag','timedepth_depths2');
    %set(deplo2,'MarkerSize',ms6,'Marker',ty2);

    depidx = dep3 >= newt2.Depth & newt2.Depth > dep2;
    plotTimeDepthSection(p5, newt2, depidx, [ty3 'r'], 'mid-depth', 'timedepth_depths3');

    %deplo3 =plot(p5, newt2.Date(depidx),-newt2.Depth(depidx),'.r', 'DisplayName','deeper','Tag','timedepth_depths3');
    %set(deplo3,'MarkerSize',ms6,'Marker',ty3)

    if ~isempty(maepi)
        if isnumeric(maepi)
            maepi = ZmapCatalog(maepi);
            warning('converted maepi to ZmapCatalog in tidepl');
        end
        pl = findobj(p5,'Tag','timedepth_bigevents');
        if isempty(pl)
            pl =   plot(p5, maepi.Date, -maepi.Depth,'xm','Tag','timedepth_bigevents');
        else
            set(pl,'XData',maepi.Date, 'YData', -maepi.Depth,'Color','m','Marker','x');
        end
        set(pl,'LineWidth',2.0)
    end

    xlabel(p5,'Time in Years','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)
    ylabel(p5,'Depth in [km]','FontWeight','bold','FontSize',ZmapGlobal.Data.fontsz.m)

    set(p5,'box','on',...
        'SortMethod','childorder','TickDir','out','FontWeight',...
        'bold','FontSize',ZmapGlobal.Data.fontsz.m,'Linewidth',1.2)

    grid
    hold off
    done
end
function plotTimeDepthSection(ax, catalog, idx, linechars, displayname, tag)
    % add a part to the time-depth plot
    % reuses if possible
    global ms6
    lineh = findobj(ax,'Tag', tag);
    if isempty(lineh)
        lineh = plot(ax, catalog.Date(idx), -catalog.Depth(idx),linechars,'DisplayName',displayname,'Tag',tag);
    else

        set(lineh,'Xdata',catalog.Date(idx),'YData',-catalog.Depth(idx), 'color',linechars(2),'Marker',linechars(1));
    end
    set(lineh,'MarkerSize',ms6);%,'Marker',ty1);
end


function err = save_nifti(hdr,niftifile)
% err = save_nifti(hdr,niftifile)
%
% Pixel data should be in hdr.vol
%
% Handles data structures with more than 32k cols by setting
% hdr.dim(2) = -1 and hdr.glmin = ncols. This is FreeSurfer specific,
% for handling surfaces. The exception to this is when the total
% number of spatial voxels equals 163842, then the volume is
% reshaped to 27307x1x6xnframes. This is for handling the 7th
% order icosahedron used by FS group analysis.
%

%
% save_nifti.m
%
% Original Author: Doug Greve
%
% Copyright © 2011 The General Hospital Corporation (Boston, MA) "MGH"
%
% Terms and conditions for use, reproduction, distribution and contribution
% are found in the 'FreeSurfer Software License Agreement' contained
% in the file 'LICENSE' found in the FreeSurfer distribution, and here:
%
% https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
%
% Reporting: freesurfer@nmr.mgh.harvard.edu
%

err = 1;
if(nargin ~= 2)
  fprintf('err = save_nifti(hdr,niftifile)\n');
  return;
end

ext = niftifile((strlen(niftifile)-2):strlen(niftifile));
if(strcmpi(ext,'.gz'))
  gzip_needed = 1;
  niftifile = niftifile(1:strlen(niftifile)-3);
  %fprintf('First, saving to %s before compressing\n',niftifile);
else
  gzip_needed = 0;
end

% Check for ico7
sz = size(hdr.vol);
if(sz(1) == 163842)
  %fprintf('save_nifti: ico7 reshaping\n');
  dim = [27307 1 6 size(hdr.vol,4)];
  hdr.vol = reshape(hdr.vol, dim);
end

fp = fopen(niftifile,'w');
if(fp == -1)
  fprintf('ERROR: could not open %s\n',niftifile);
  return;
end

hdr.data_type = [hdr.data_type(:)' repmat(' ',[1 10])];
hdr.data_type = hdr.data_type(1:10);

hdr.db_name = [hdr.db_name(:)' repmat(' ',[1 18])];
hdr.db_name = hdr.db_name(1:18);

hdr.dim = ones(1,8);
if size(hdr.vol,4)>1
  hdr.dim(1) = 4;
else
  hdr.dim(1) = 3;
end
hdr.dim(2) = size(hdr.vol,1);
hdr.dim(3) = size(hdr.vol,2);
hdr.dim(4) = size(hdr.vol,3);
hdr.dim(5) = size(hdr.vol,4);

% This is to accomodate structures with more than 32k cols
% FreeSurfer specific. See also mriio.c.
if(hdr.dim(2) > 2^15)
  hdr.glmin = hdr.dim(2);
  hdr.dim(2) = -1;
end

hdr.pixdim = [hdr.pixdim(:)' repmat(0,[1 8])];
hdr.pixdim = hdr.pixdim(1:8);

hdr.descrip = [hdr.descrip(:)' repmat(' ',[1 80])];
hdr.descrip = hdr.descrip(1:80);

hdr.aux_file = [hdr.aux_file(:)' repmat(' ',[1 24])];
hdr.aux_file = hdr.aux_file(1:24);

hdr.intent_name = [hdr.intent_name(:)' repmat(' ',[1 16])];
hdr.intent_name = hdr.intent_name(1:16);

hdr.magic = [hdr.magic(:)' repmat(0,[1 4])];
hdr.magic = hdr.magic(1:4);

if(isempty(hdr.regular))  hdr.regular  = ' '; end
if(isempty(hdr.dim_info)) hdr.dim_info = ' '; end
if(isempty(hdr.slice_code)) hdr.slice_code = ' '; end
if(isempty(hdr.xyzt_units)) hdr.xyzt_units = ' '; end % should be err

hdr.vox_offset = 352; % not 348
fwrite(fp,348,'int');
fwrite(fp,hdr.data_type,    'char');
fwrite(fp,hdr.db_name,      'char');
fwrite(fp,hdr.extents,      'int');
fwrite(fp,hdr.session_error,'short');
fwrite(fp,hdr.regular,      'char');
fwrite(fp,hdr.dim_info,     'char');
fwrite(fp,hdr.dim,          'short');
fwrite(fp,hdr.intent_p1,    'float');
fwrite(fp,hdr.intent_p2,    'float');
fwrite(fp,hdr.intent_p3,    'float');
fwrite(fp,hdr.intent_code,  'short');
fwrite(fp,hdr.datatype,     'short');
fwrite(fp,hdr.bitpix,       'short');
fwrite(fp,hdr.slice_start,  'short');
fwrite(fp,hdr.pixdim,       'float');
fwrite(fp,hdr.vox_offset,   'float');
fwrite(fp,hdr.scl_slope,    'float');
fwrite(fp,hdr.scl_inter,    'float');
fwrite(fp,hdr.slice_end,    'short');
fwrite(fp,hdr.slice_code,   'char');
fwrite(fp,hdr.xyzt_units,   'char');
fwrite(fp,hdr.cal_max,      'float');
fwrite(fp,hdr.cal_min,      'float');
fwrite(fp,hdr.slice_duration,'float');
fwrite(fp,hdr.toffset,       'float');
fwrite(fp,hdr.glmax,         'int');
fwrite(fp,hdr.glmin,         'int');
fwrite(fp,hdr.descrip,       'char');
fwrite(fp,hdr.aux_file,      'char');
fwrite(fp,hdr.qform_code,    'short');
fwrite(fp,hdr.sform_code,    'short');
fwrite(fp,hdr.quatern_b,     'float');
fwrite(fp,hdr.quatern_c,     'float');
fwrite(fp,hdr.quatern_d,     'float');
fwrite(fp,hdr.quatern_x,     'float');
fwrite(fp,hdr.quatern_y,     'float');
fwrite(fp,hdr.quatern_z,     'float');
fwrite(fp,hdr.srow_x,        'float');
fwrite(fp,hdr.srow_y,        'float');
fwrite(fp,hdr.srow_z,        'float');
fwrite(fp,hdr.intent_name,   'char');
fwrite(fp,hdr.magic,         'char');

% Pad to get to 352 bytes (header size is 348)
fwrite(fp,0,'char');
fwrite(fp,0,'char');
fwrite(fp,0,'char');
fwrite(fp,0,'char');

npix = prod(size(hdr.vol));
switch(hdr.datatype)
 case   2, nitemswritten = fwrite(fp,hdr.vol,'uchar'); % dont use char
 case   4, nitemswritten = fwrite(fp,hdr.vol,'short');
 case   8, nitemswritten = fwrite(fp,hdr.vol,'int');
 case  16, nitemswritten = fwrite(fp,hdr.vol,'float');
 case  64, nitemswritten = fwrite(fp,hdr.vol,'double');
 case 256, nitemswritten = fwrite(fp,hdr.vol,'int8');
 case 512, nitemswritten = fwrite(fp,hdr.vol,'ushort');
 case 768, nitemswritten = fwrite(fp,hdr.vol,'uint');
 otherwise,
  fprintf('WARNING: data type %d not supported, but writing as float',...
	  hdr.datatype);
  nitemswritten = fwrite(fp,hdr.vol,'float');
  return;
end
fclose(fp);

if(npix ~= nitemswritten)
  fprintf('ERROR: tried to write %d, but only wrote %d',npix,nitemswritten);
  return;
end

if(gzip_needed)
  cmd = sprintf('gzip -f %s', niftifile);
  %fprintf('Compressing with\n');
  %fprintf('   %s\n',cmd);
  unix(cmd);
end

err = 0;
return;


function [y,x,x0,eta,e,u] = simulateNLSS(n_t,f_fname,g_fname,theta,phi,u,alpha,sigma,options,x0)
% legacy code
s = warning ('on');
warning ('*** The function `simulateNLSS` is now deprecated. Please use `VBA_simulate` instead (same syntax).')
warning (s);

% fallback
try
    [y,x,x0,eta,e,u] = VBA_simulate (n_t,f_fname,g_fname,theta,phi,u,alpha,sigma,options,x0);
catch
    [y,x,x0,eta,e,u] = VBA_simulate (n_t,f_fname,g_fname,theta,phi,u,alpha,sigma,options);
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% REAL-TIME BCILAB/SIFT INTERFACE DEMO SCRIPT
%
% This script demonstrates a beta interface between BCILAB
% (Christian Kothe: www.sccn.ucsd.edu/wiki/BCILAB) and SIFT (Tim Mullen:
% www.sccn.ucsd.edu/wiki/SIFT) to perform real-time data extraction,
% cleaning, connectivity modeling and visualization.
%
% This script was prepared for the following whitepaper/demonstration:
% [1] Tim Mullen, Christian Kothe, Yu Chi, Tzyy-Ping Jung,
%     and Scott Makeig. "Real-Time Estimation and 3D Visualization of Sparse
%     Multivariate Effective Connectivity Using Wearable EEG." July 15th,
%     IEEE EMB/CAS/SMC Workshop on Brain-Machine-Body Interfaces. 34th
%     Annual International IEEE EMBS Conference of the IEEE Engineering in
%     Medicine and Biology Society (IEEE EMBS).
%
% Please refer to [1] when using any functionality from this demo.
%
% Copyright Tim Mullen, Christian Kothe, July 2012, SCCN/INC/UCSD
%
% Author: Tim Mullen,       July 2012, SCCN/INC/UCSD
%         Christian Kothe,  July 2012, SCCN/INC/UCSD
%
% This function is part of the Source Information Flow Toolbox (SIFT)
%
% This program 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.
%
% This program 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 this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% SET UP CONFIGURATION OPTIONS
% NOTE: all paths are relative to 'datapath' which is a
% platform-independent path which itself can be relative to bcilab root
% folder (i.e. data:/ is the userdata folder in the bcilab root dir)

RUN_LSL          = false;   % if 'online' streaming, RUN_LSL = true, otherwise playback TestingDataFile (below)
COLOR_SOURCE_ROI = false;   % ONLY if using source reconstruction, this will color sources according to ROI
HEAD_MODEL_NAME  = '';      % path to head model object for source reconstruction (relative to 'datapath'). Leave empty if you aren't doing source reconstruction
GUI_CONFIG_NAME  = 'DARPA_DEMO_METACP_CFG_FEWCHANS.mat';    % relative path to a default pipeline configuration
GUI_BRAINMOVIE_CONFIG_NAME = 'DARPA_DEMO_BM_CFG.mat';       % relative path to BrainMovie configuration

% establish where we will read/write prefs, etc from
datapath         = 'data:/';  % this is relative to the BCILAB root dir
TrainingDataFile = 'calibration_mindo.xdf';     % this is the relative path to the
TestingDataFile  = 'calibration_mindo.xdf';

% Set up the name of the stream we will write to in the workspace
streamname              = 'EEGDATA';
LSL_SelectionProperty   = 'type';  % can also be 'name'
LSL_SelectionValue      = 'EEG';

%% load head model object
if ~isempty(HEAD_MODEL_NAME)
    hmObj = headModel.loadFromFile(env_translatepath([datapath HEAD_MODEL_NAME]));
    % load meshes for visualization
    surfData    = load(hmObj.surfaces);
    surfData    = surfData.surfData;
    scalpMesh   = surfData(1);
    csfMesh     = surfData(2);
    cortexMesh  = surfData(3);
end

%% load calibration recording
calibData = exp_eval(io_loadset([datapath TrainingDataFile],'markerchannel',{'remove_eventchns',false}));
flt_pipeline('update');

%% start LSL streaming
if RUN_LSL == true
    run_readlsl('MatlabStream',streamname,'SelectionProperty',LSL_SelectionProperty,'SelectionValue',LSL_SelectionValue);
end
%% ... OR read from datafile
if RUN_LSL == false
    run_readdataset('MatlabStream',streamname,'Dataset',io_loadset([datapath TestingDataFile],'markerchannel',{'remove_eventchns',false}));
end

%% initialize some variables
[benchmarking.preproc     ...
 benchmarking.modeling    ...
 benchmarking.brainmovie] = deal(NaN);

newPipeline     = true;
newBrainmovie   = true;
specOpts        = [];

% create a minimal moving average pipeline...
% noflats = exp_eval_optimized(flt_movavg(flt_selchans(calibData,{'FC3', 'FC4', 'FC2', 'FC1', 'C3', 'C4', 'C2', 'C1', 'CP3', 'CP4', 'CP2', 'CP1', 'P3', 'P4', 'P2', 'P1'})));
noflats = flt_seltypes(calibData,'EEG');
%noflats = exp_eval_optimized(flt_movavg(flt_seltypes(calibData,'EEG')));
highpassed   = exp_eval_optimized(flt_fir(noflats,[0.5 1],'highpass'));
goodchannels = exp_eval_optimized(flt_clean_channels('signal',highpassed,'min_corr',0.35,'ignored_quantile',0.3));

%% initialize options
if ~isempty(GUI_CONFIG_NAME) && exist(env_translatepath([datapath GUI_CONFIG_NAME]),'file')
    % try to load a configuration file
    io_load([datapath GUI_CONFIG_NAME]);
else
    % manually set some defaults
    opts.miscOptCfg.dispBenchmark  = true;
    opts.miscOptCfg.doSIFT         = [];
    opts.holdPipeline              = false;
    opts.exitPipeline              = false;

    opts.siftPipCfg.preproc.verb = 0;

    % set some defaults
    opts.fltPipCfg = ...
        struct('DataCleaning', ...
                struct('RetainPhases',true, ...
                       'HaveBursts', true, ...
                       'HaveChannelDropouts', false, ...
                       'DataSetting', 'drycap'), ...
                'Rereferencing', {{}});

    opts.siftPipCfg = ...
        struct('preproc', ...
                    struct('normalize', ...
                        struct('verb', 0, ...
                               'method', {{'time'}})));

end

% additional options regarding brainmovie node/edge adaptation
opts.adaptation.adaptationHL    = 10;  % HL of exp. win. MA in frames
opts.adaptation.updateInterval  = 1;
opts.adaptation.bufferTime      = 1;

%% initialize the Meta Control Panel
if ~isempty(HEAD_MODEL_NAME)
    calibData.srcpot = 1; % allow sources
end
figHandles.MetaControlPanel = gui_metaControlPanel(calibData,opts);
waitfor(figHandles.MetaControlPanel,'UserData','initialized');

%% Initialize figures
figHandles.specDisplay      = [];
figHandles.BMDisplay        = [];
figHandles.BMControlPanel   = [];

%% try to load a BrainMovie configuration
try
    io_load([datapath GUI_BRAINMOVIE_CONFIG_NAME]);
    BMCFG.BMopts.bmopts_suppl = {'title',{'Multivariate ','Granger Causality  '}};
    BMCFG.BMopts.caption = true;
catch
    BMCFG = struct([]);
end

BMRenderMode = 'init_and_render';

%% Main loop
% -------------------------------------------------------------------------
while ~opts.exitPipeline

    try

        if newPipeline
            % create a new pipeline on training data
            fprintf('Pipeline changed\n');
            cleaned_data = exp_eval(flt_pipeline('signal',calibData,opts.fltPipCfg));
            pipeline     = onl_newpipeline(cleaned_data,streamname);
            newPipeline  = false;
        end

        if opts.holdPipeline
            % pause the pipeline
            pause(1);
            continue;
        end

        % grab a chunk of data from the stream and preprocess it
        % ---------------------------------------------------------------------
        prepbench = tic;
        [eeg_chunk,pipeline] = onl_filtered(pipeline, ...
                                            round(opts.miscOptCfg.winLenSec*cleaned_data.srate), ...
                                            opts.miscOptCfg.suppress_console_output, ...
                                            fastif(opts.fltPipCfg.psourceLocalize.arg_selection,{'srcpot'},{}));
        benchmarking.preproc = toc(prepbench);

        % model the chunk via sift
        % ---------------------------------------------------------------------
        if opts.miscOptCfg.doSIFT.arg_selection
            try
                % force the modeling window length to agree with chunk length
                opts.siftPipCfg.modeling.winlen = opts.miscOptCfg.winLenSec;

                % import ROI Names
                if strcmpi(opts.siftPipCfg.preproc.sigtype.arg_selection,'sources')
                    opts.siftPipCfg.preproc.varnames = eeg_chunk.roiLabels;
                end

                % select a subset of channels
                if ~isempty(opts.miscOptCfg.doSIFT.channelSubset)
                    [dummy eeg_chunk] = evalc('hlp_scope({''disable_expressions'',1},@flt_selchans,''signal'',eeg_chunk,''channels'',opts.miscOptCfg.doSIFT.channelSubset,''arg_direct'',true)');
                end

                % run the SIFT modeling pipeline
                siftbench = tic;
                [eeg_chunk cfg] = hlp_scope({'is_online',1},@onl_siftpipeline,'EEG',eeg_chunk,opts.siftPipCfg);
                benchmarking.modeling = toc(siftbench);

                if eeg_chunk.pnts == 0
                    fprintf('No data!\n');
                    pause(0.01);
                    continue;
                end

            catch err
                hlp_handleerror(err);
                pause(0.1);
                continue;
            end

            % visualize the brainmovie
            % -------------------------------------------------------------
            if opts.miscOptCfg.doSIFT.dispBrainMovie.arg_selection

                if newBrainmovie ...
                    | isempty(ishandle(figHandles.BMDisplay)) ...
                    | ~ishandle(figHandles.BMDisplay)

                    % initialize brainmovie
                    if ~isempty(BMCFG)
                        BMCFG.showNodeLabels.nodelabels = eeg_chunk.CAT.curComponentNames;
                        figHandles.BMControlPanel = gui_causalBrainMovie3D_online(eeg_chunk,eeg_chunk.CAT.Conn,struct('arg_direct',0),BMCFG,'timeRange',[]);
                    else
                        figHandles.BMControlPanel = gui_causalBrainMovie3D_online(eeg_chunk,eeg_chunk.CAT.Conn,struct('arg_direct',0),'showNodeLabels',{'nodelabels',eeg_chunk.CAT.curComponentNames});
                    end
                    waitfor(figHandles.BMControlPanel,'UserData','newBrainmovie');

                    % set the closing behavior
                    set(figHandles.BMControlPanel,'CloseRequestFcn','evalin(''base'',''figHandles.BMControlPanel = [];''); delete(gcbf);');

                    BM_CFG_CHANGED       = true;
                    newBrainmovie        = false;
                    figHandles.BMDisplay = [];
                    BMStateVars          = [];
                end

                if BM_CFG_CHANGED
                    BMRenderMode    = 'init_and_render';
                    BMStateVars     = [];

                    % determine whether to adapt limits
                    adapt_nodeSizeDataRange  = isempty(BMCFG.BMopts.graphColorAndScaling.nodeSizeDataRange)  && opts.miscOptCfg.doSIFT.dispBrainMovie.adaptBrainMovieLimits;
                    adapt_edgeSizeDataRange  = isempty(BMCFG.BMopts.graphColorAndScaling.edgeSizeDataRange)  && opts.miscOptCfg.doSIFT.dispBrainMovie.adaptBrainMovieLimits;
                    adapt_nodeColorDataRange = isempty(BMCFG.BMopts.graphColorAndScaling.nodeColorDataRange) && opts.miscOptCfg.doSIFT.dispBrainMovie.adaptBrainMovieLimits;
                    adapt_edgeColorDataRange = isempty(BMCFG.BMopts.graphColorAndScaling.edgeColorDataRange) && opts.miscOptCfg.doSIFT.dispBrainMovie.adaptBrainMovieLimits;

                    % clear state
                    nodeSizeState   = [];
                    nodeColorState  = [];
                    edgeSizeState   = [];
                    edgeColorState  = [];

                    % reset flag
                    BM_CFG_CHANGED = false;
                end

                % Handle special rendering of source meshes and colors
                % ---------------------------------------------------------
                if COLOR_SOURCE_ROI
                    BG_COLOR = [0.1 0.1 0.1];

                    if BMCFG.BMopts.Layers.custom.arg_selection
                        BMCFG.BMopts.Layers.custom.volumefile = eeg_chunk.dipfit.surfmesh;
                        BMCFG.BMopts.Layers.custom.meshcolor  = hlp_getROIVertexColorTable( ...
                                size(eeg_chunk.dipfit.surfmesh.vertices,1), ...
                                eeg_chunk.roiVertices,BG_COLOR,@(x)distinguishable_colors(x,BG_COLOR));
                    end

                    % if the cortex mesh is a custom mesh with 'constant'
                    % coloring...
                    if strcmpi(BMCFG.BMopts.Layers.cortex.cortexres,'custommesh') ...
                       && strcmp(BMCFG.BMopts.Layers.cortex.cortexcolor.arg_selection,'Constant')
                            % ... replace the colors with ROI coloring
                            BMCFG.BMopts.Layers.cortex.cortexcolor.colormapping = ...
                                hlp_getROIVertexColorTable( ...
                                    size(eeg_chunk.dipfit.surfmesh.vertices,1), ...
                                    eeg_chunk.roiVertices,BG_COLOR,@(x)distinguishable_colors(x,BG_COLOR));
%                         {hmObj.atlas.label, hlp_getROIColorTable(hmObj.atlas.label,eeg_chunk.roiLabels,[0.5 0.5 0.5],[1 0 0])};
                    end
                end

                % Render the Brain Movie
                % ---------------------------------------------------------
                bmbench = tic;
                [BMcfg_tmp BMhandles BMout] = ...
                    vis_causalBrainMovie3D(eeg_chunk,eeg_chunk.CAT.Conn,BMCFG, ...
                        'timeRange',[], ...
                        'BMopts',hlp_mergeVarargin(BMCFG.BMopts, ...
                                    'figurehandle',figHandles.BMDisplay, ...
                                    'RenderMode',BMRenderMode, ...
                                    'speedy',true, ...
                                    'InternalStateVariables',BMStateVars));
                benchmarking.brainmovie = toc(bmbench);

                if isempty(BMStateVars)
                    set(figHandles.BMDisplay, 'MenuBar','figure', ...
                                'CloseRequestFcn','evalin(''base'',''figHandles.BMDisplay = [];''); delete(gcbf);', ...
                                'ToolBar','none', 'Name','BrainMovie3D');
                end

                % save figure handle and state
                figHandles.BMDisplay = BMhandles.figurehandle;
                BMStateVars          = BMcfg_tmp.BMopts.vars;
                BMRenderMode         = 'render';

                % adapt the node and edge color/size limits
                % ---------------------------------------------------------
                if opts.miscOptCfg.doSIFT.dispBrainMovie.arg_selection ...
                   && opts.miscOptCfg.doSIFT.dispBrainMovie.adaptBrainMovieLimits

                    % adapt BrainMovie node/edge limits
                    if adapt_nodeSizeDataRange
                        [BMCFG.BMopts.graphColorAndScaling.nodeSizeDataRange, nodeSizeState] ...
                            = hlp_adaptMinMaxLimits('values',   BMout.NodeSize,     ...
                                                    'state',    nodeSizeState,      ...
                                                    'adaptOpts',opts.adaptation);
                    end
                    if adapt_nodeColorDataRange
                        [BMCFG.BMopts.graphColorAndScaling.nodeColorDataRange, nodeColorState] ...
                            = hlp_adaptMinMaxLimits('values',   BMout.NodeColor,     ...
                                                    'state',    nodeColorState,      ...
                                                    'adaptOpts',opts.adaptation);
                    end
                    if adapt_edgeSizeDataRange
                        [BMCFG.BMopts.graphColorAndScaling.edgeSizeDataRange, edgeSizeState] ...
                            = hlp_adaptMinMaxLimits('values',   BMout.EdgeSize,     ...
                                                    'state',    edgeSizeState,      ...
                                                    'adaptOpts',opts.adaptation);
                    end
                    if adapt_edgeColorDataRange
                        [BMCFG.BMopts.graphColorAndScaling.edgeColorDataRange, edgeColorState] ...
                            = hlp_adaptMinMaxLimits('values',   BMout.EdgeColor,     ...
                                                    'state',    edgeColorState,      ...
                                                    'adaptOpts',opts.adaptation);
                    end

                end % adaptBrainMovieLimits

            else % dispBrainMovie == false
                % close the brainmovie figure if control panel is closed
                if isempty(figHandles.BMControlPanel) ...
                        || ~ishandle(figHandles.BMControlPanel) ...
                        && ishandle(figHandles.BMDisplay)
                    close(figHandles.BMDisplay);
                end
                benchmarking.brainmovie = NaN;
            end

            % display the VAR spectrum
            % -------------------------------------------------------------
            if opts.miscOptCfg.doSIFT.dispSpectrum
                try
                    if ishandle(figHandles.specDisplay)
                        % update the SpecViewer
                        vis_autospectrum(specOpts,'FigureHandle',figHandles.specDisplay,'stream',eeg_chunk);
                    else
                        % generate a GUI and initialize SpecViewer
                        [figHandles.specDisplay specOpts] = arg_guidialog(@vis_autospectrum,'Parameters',{'stream',eeg_chunk});

                        set(figHandles.specDisplay,'CloseRequestFcn','evalin(''base'',''opts.miscOptCfg.dispSpectrum=false; figHandles.specDisplay = [];''); delete(gcbf);');
                        specOpts.arg_direct = 0;
                    end
                catch e
                    disp(e.message);
                    opts.miscOptCfg.doSIFT.dispSpectrum = false;
                end
            else
                if ishandle(figHandles.specDisplay)
                    close(figHandles.specDisplay);
                end
            end

        else
            benchmarking.modeling = NaN;
        end

        if opts.miscOptCfg.dispBenchmark
            % TODO: implement this as a figure
            vis_benchmark(benchmarking);
        end

    catch err
         hlp_handleerror(err);
    end

    pause(0.005);

end

%% all done, close all open figures
fnames = fieldnames(figHandles);
for f=1:length(fnames)
    if ishandle(figHandles.(fnames{f}))
        close(figHandles.(fnames{f}));
    end
end


function au_l_d
%
%  Deletes the global data that has been generated by 'au_l_i'.
%
%  Calling sequence:
%
%    au_l_d
%
%
%  LYAPACK 1.0 (Thilo Penzl, May 1999)

global LP_L LP_U

clear global LP_L LP_U


function vw = rmSelect(vw, loadModel, rmFile)
% rmSelect - select retinotopy model file and put in view struct
%
% vw = rmSelect([vw=current view], [loadModel=0], [rmFile=dialog]);
%
% The loadModel flag indicates whether the model file (a large file)
% should be loaded or not. By default it is 0: don't load it until needed
% (only the path to the selected rmFile file will be stored). If it's 1, it
% goes ahead and loads it.
%
% If the path to the retinotopy model file is provided as a third argument,
% will attempt to load it directly; otherwise, pops up a dialog.  You
% may also provide the string 'mostrecent' as the filename, in which case
% the code will look for the most recently-created model file, and
% select it (producing an error if one is not found).
%
% 2006/02 SOD: wrote it.
% ras 2006/10: added dialog.
% ras, 06/07: added 'mostrecent' flag to find the newest file
if ~exist('vw','var') || isempty(vw), vw = getCurView;  end;
if ~exist('loadModel','var') || isempty(loadModel), loadModel = true;   end;

% choose filename:
if ~exist('rmFile','var') || isempty(rmFile),
    rmFile = getPathStrDialog(dataDir(vw),...
        'Choose retinotopic model file name', ...
        '*.mat');
    drawnow;
elseif iscell(rmFile)
    rmFile = rmFile{1};
end

% if user just wants the newest file, check for it:
if ischar(rmFile) && ismember(lower(rmFile), {'newest' 'mostrecent'})
	pattern = fullfile( dataDir(vw), 'retModel-*.mat' );
	w = dir(pattern);
	if isempty(w)
		error('Most Recent File selected; no retModel-* files found.')
	end
	[dates, order] = sortrows( datevec({w.date}) ); % oldest -> newest
	rmFile = fullfile( dataDir(vw), w(order(end)).name );
end

% Locate rm file
if check4File(fullfile(dataDir(vw), rmFile))
    % first check in appropriate directory
    rmFile = fullfile(dataDir(vw), rmFile);
elseif check4File(fullfile(dataDir(vw), [rmFile '.mat']))
    % if not found, check whether we are missing the extension
    rmFile = fullfile(dataDir(vw), [rmFile '.mat']);
elseif exist(rmFile,'file')
    % if still not found, look on entire path
elseif exist([rmFile '.mat'], 'file')
    % if still not found, look on entire path with '.mat' added
    rmFile = [rmFile '.mat'];
else
    % We could not find rm file anywhere
    fprintf('[%s]:No file: %s\n',mfilename,rmFile);
    return;
end

% if the load model flag is 1, but the file's already selected, just load
% it and return:
if loadModel && checkfields(vw, 'rm' , 'retinotopyModelFile')
    if ~exist(rmFile, 'file')
        error('Model file %s not found.', rmFile);
    end;
    load(rmFile, 'model', 'params');
    vw = viewSet(vw, 'rmFile', rmFile);
    vw = viewSet(vw, 'rmModel', model);
    vw = viewSet(vw, 'rmParams', params);
    vw = viewSet(vw, 'rmModelNum', 1);
    return;
end;

% store rmFile filename:
vw = viewSet(vw,'rmFile',rmFile);

if loadModel==0
    % clear previous models but don't load them untill we need them:
    vw = viewSet(vw, 'rmModel', []);
else
    % go ahead and load
    load(rmFile, 'model', 'params');
    vw = viewSet(vw, 'rmModel', model);
    vw = viewSet(vw, 'rmParams', params);
    vw = viewSet(vw, 'rmModelNum', 1);
end;

return;


function val = dtiGetImageCoordsFromFibers(dt, fg)
%Obsolete
%
%  Returns the image coordinates of the fibers in fg
%
% WARNING:  Doesn't work.  See notes below.  Should be obsolete soon.
%
%  val = dtiGetImageCoordsFromFibers(dt, fg)
%
% The data in val are Nx3
%
% (c) Stanford VISTA Team

% Written by Sherbondy and Dougherty.  It doesn't seem to do what it says.
% It is not called by any other functions. We need a function that does
% just this properly.  It should be inside of dtiGet(), I think.

error('Obsolete %s\n',mfilename)

return

% Here are the coords
coords = horzcat(fg.fibers{:})';
coords = unique(round(mrAnatXformCoords(inv(dt.xformToAcpc),coords)),'rows');

% Here are the tensors as 6-vectors
inds = sub2ind(size(dt.dt6(:,:,:,1)),coords(:,1),coords(:,2),coords(:,3));
vecDt6 = zeros(size(coords,1),6);
for ii=1:6
    temp = dt.dt6(:,:,:,ii);
    vecDt6(:,ii) = temp(inds);
end

% These statistics should be computed based on nargout.
[eigVec, eigVal] = dtiEig(vecDt6);
l2 = eigVal
[fa,md,rd] = dtiComputeFA(eigVal);
[cl, cp, cs] = dtiComputeWestinShapes(eigVal);

return


function axisset(mode)
% AXISSET User axis setting.

% Author: Craig Borghesani <cborg@terasoft.com>
% Date: 1/19/98 10:36PM

% obtain handle information
if mode == 1,
 f = gcf;

else
 f2 = gcf;
 f = get(f2,'userdata');

end

ui_data = get(f,'userdata');
ui_han = ui_data{1};
last_lims = ui_han(36);
ui_han2 = get(ui_han(54),'userdata');

cur_axs = get(ui_han(32),'userdata');

axs_data = get(cur_axs,'userdata');
axs_typ = axs_data(1);

if mode == 1, % axis limit entering

 win_str = get(ui_han(48),'userdata');

% define various shades of grey
 grey = get(0,'defaultuicontrolbackground');
 ltgrey = [0.5,0.5,0.5]*1.5;
 dkgrey = [0.5,0.5,0.5]*0.5;

 f2 = findobj(0,'type','figure','tag','AxisLimits');

 if isempty(f2),
  scrn_size = get(0,'screensize');
  fig_h = 80;
  fig_w = 360;
  fig_lft = (scrn_size(3) - fig_w)/2;
  fig_btm = (scrn_size(4) - (fig_h+20))/2;
  f2 = figure('pos',[fig_lft,fig_btm,fig_w,fig_h],'menubar','none','numbertitle','off',...
              'color',grey,'name',['Axis Limits',win_str],...
              'userdata',f,'defaultuicontrolbackgroundcolor',grey,...
              'tag','AxisLimits');

  lft = 10; btm = fig_h - 25;
  ui_han2(1) = uicontrol('style','text',...
                        'pos',[lft,btm,80,17],...
                        'string','Current Axis:',...
                        'horiz','left');
  ui_han2(2) = uicontrol('style','text',...
                        'pos',[lft+85,btm,150,17],...
                        'string','',...
                        'horiz','left');

  btm = btm - 22;
  ui_han2(3) = uicontrol('style','text',...
                        'pos',[lft,btm,50,17],...
                        'string','X Min',...
                        'horiz','left');
  ui_han2(4) = uicontrol('style','edit',...
                        'pos',[lft+55,btm,60,20],...
                        'string','',...
                        'horiz','right',...
                        'back','w');
  ui_han2(5) = uicontrol('style','text',...
                        'pos',[lft+130,btm,50,17],...
                        'string','X Max',...
                        'horiz','left');
  ui_han2(6) = uicontrol('style','edit',...
                        'pos',[lft+185,btm,60,20],...
                        'string','',...
                        'horiz','right',...
                        'back','w');
  btm = btm - 22;
  ui_han2(7) = uicontrol('style','text',...
                        'pos',[lft,btm,50,17],...
                        'string','Y Min',...
                        'horiz','left');
  ui_han2(8) = uicontrol('style','edit',...
                        'pos',[lft+55,btm,60,20],...
                        'string','',...
                        'horiz','right',...
                        'back','w');
  ui_han2(9) = uicontrol('style','text',...
                        'pos',[lft+130,btm,50,17],...
                        'string','Y Max',...
                        'horiz','left');
  ui_han2(10) = uicontrol('style','edit',...
                        'pos',[lft+185,btm,60,20],...
                        'string','',...
                        'horiz','right',...
                        'back','w');

  btm = fig_h - 25;
  lft = fig_w - 70;
  ui_han2(11) = uicontrol('style','push',...
                         'pos',[lft,btm,60,20],...
                         'string','OK',...
                         'callback','axisset(2)');

  btm = btm - 25;
  ui_han2(12) = uicontrol('style','push',...
                         'pos',[lft,btm,60,20],...
                         'string','Cancel',...
                         'callback','axisset(3)');

  set(ui_han(54),'userdata',ui_han2);
  set(f2,'vis','on');

 end

 figure(f2);

 if axs_data(1) == 1, set(ui_han2(2),'string','Nyquist');
 elseif axs_data(1) == 2, set(ui_han2(2),'string','Bode (Magnitude)');
 elseif axs_data(1) == 3, set(ui_han2(2),'string','Bode (Phase)');
 elseif axs_data(1) == 4, set(ui_han2(2),'string','Nichols');
 elseif axs_data(1) == 5, set(ui_han2(2),'string','Root Locus');
 elseif axs_data(1) == 6, set(ui_han2(2),'string','Gain (Magnitude)');
 elseif axs_data(1) == 7, set(ui_han2(2),'string','Gain (Phase)');
 elseif axs_data(1) == 8, set(ui_han2(2),'string','Time Response'); end

 Xlimits = get(cur_axs,'xlim');
 Ylimits = get(cur_axs,'ylim');
 set(ui_han2(4),'string',Xlimits(1));
 set(ui_han2(6),'string',Xlimits(2));
 set(ui_han2(8),'string',Ylimits(1));
 set(ui_han2(10),'string',Ylimits(2));

elseif mode == 2, % axis limits acceptance

 Xlimits = get(cur_axs,'xlim');
 Ylimits = get(cur_axs,'ylim');
 set(last_lims,'userdata',[cur_axs,Xlimits,Ylimits]);

 Xmin = str2num(get(ui_han2(4),'string'));
 Xmax = str2num(get(ui_han2(6),'string'));
 Ymin = str2num(get(ui_han2(8),'string'));
 Ymax = str2num(get(ui_han2(10),'string'));

 if any(axs_typ == [1, 5]),
  set(cur_axs,{'xlim','ylim'},ctsqaxes(cur_axs,[Xmin,Xmax],[Ymin,Ymax]));
 else
  set(cur_axs,'xlim',[Xmin,Xmax],'ylim',[Ymin,Ymax]);
 end

 set(f2,'vis','off');

elseif mode == 3, % Cancel

  set(f2,'vis','off');

end


%% patchFaceAngles
% Below is a demonstration of the features of the |patchFaceAngles| function

%%
clear; close all; clc;

%% Syntax
% |[betaAngle] = patchFaceAngles(F,V);|

%% Description
% UNDOCUMENTED
%% Examples
%
%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program 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.
%
% This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.


function ok=dfsession(action,fn)
%DFSESSION Clear, load, or save a Distribution Fitting session

%   $Revision: 1.1.6.7 $  $Date: 2004/02/01 22:10:39 $
%   Copyright 2003-2004 The MathWorks, Inc.

% Create a structure with version information
str.ftype = 'Distribution Fitting session';   % type of file
str.version = 1;                              % the most current version
str.allversions = [1];                        % all supported versions
str.properties = {'Color' 'LineStyle' 'LineWidth' 'Marker' 'MarkerSize'};

% Variables we save, and the number required to be in a saved file
varnames = {'ftype' 'version' 'allds' 'dsinfo' 'allfits' ...
            'fitinfo' 'alldists' 'outliers' 'guistate'};
nrequired = 9;

if nargin<2
   fn = '';
end

% Wrap real function with a try/catch block so we can control the legend
oldleg = dfgetset('showlegend');
if isequal(oldleg,'on')
   dfgetset('showlegend','off');
end

ok = true;
%try
   switch(action)
    case 'save'
      ok = savesession(fn,str,varnames);

    case 'load'
      ok = loadsession(fn,str,varnames,nrequired);

    case 'clear'
      ok = clearsession;

    otherwise
      ok = false;
   end
%catch
%end

if isequal(oldleg,'on')
   dfgetset('showlegend','on');
   dfupdatelegend(dfgetset('dffig'));
end

% ----------------------------------------------------------------
function ok=savesession(fn,str,varnames)
%DFSAVESESSION Callback to save a distribution fitting session to a file

% Extract some variables from the input structure
ftype = str.ftype;
version = str.version;
guistate.ftype = dfgetset('ftype');
guistate.dtype = dfgetset('dtype');
guistate.binDlgInfo = dfgetset('binDlgInfo');

% Get all M data set object instances and some properties
dsdb = getdsdb;
allds = find(dsdb);
allds(allds==dsdb) = [];
nds = length(allds);
dsinfo = cell(nds,1);
for j=1:length(allds)
   % Save all datasets
   dj = allds(j);
   dsinfo{j,1} = dj.plot;    % remember this flag separately from object
end

% Get all M fit object instances and some properties
fitdb = getfitdb;
allfits = find(fitdb);
allfits(allfits==fitdb) = [];
nfits = length(allfits);
fitinfo = cell(nfits,1);
for j=1:nfits
   % Save all fit objects separately
   fj = allfits(j);
   fitinfo{j,1} = fj.plot;  % remember this flag separately from object
end

% get the user-defined distributions
alldists = dfgetset('alldistributions');

% Get the outliers (excluded sets)
outdb = getoutlierdb;
outliers = find(outdb);
outliers(outliers==outdb) = [];

% Get file name to use, remember the directory name
olddir = dfgetset('dirname');
filespec = [olddir '*.dfit'];
if isempty(fn)
   [fn,pn] = uiputfile(filespec,'Save Session');
   if isequal(fn,0) || isequal(pn,0)
      ok = false;
      return
   end
   if ~ismember('.',fn)
      fn = [fn '.dfit'];
   end
   dfgetset('dirname',pn);
   fn = [pn fn];
end

% Select a file and save the session variables
le = lasterr;
lasterr('');
try
   save(fn, varnames{:}, '-mat');
catch
   uiwait(errordlg(sprintf('Error saving session file:\n%s', lasterr),...
                   'Save Error','modal'))
   ok = false;
   return
end
lasterr(le);
ok = true;

% ----------------------------------------------------------------
function ok=loadsession(fn,str,varnames,nrequired)
%DFLOADSESSION Callback to load a saved distribution fitting session

import com.mathworks.toolbox.stats.*;

ok = true;
ftype = str.ftype;
version = str.version;
allversions = str.allversions;
properties = str.properties;

% Get file name and load from it, remember the directory name
olddir = dfgetset('dirname');
filespec = [olddir '*.dfit'];

if isempty(fn)
   [fn,pn] = uigetfile(filespec,'Load Session');
   if isequal(fn,0) || isequal(pn,0)
      return
   end
   if ~ismember('.',fn)
      fn = [fn '.cfit'];
   end
   dfgetset('dirname',pn);
   fn = [pn fn];
end

% Clear current session
clearsession;

% Get file contents without adding them to the data bases automatically
dsmgr = DataSetsManager.getDataSetsManager;
fmgr = FitsManager.getFitsManager;
dsmgr.turnOffUDDListener;
fmgr.turnOffUDDListener;
try
   s = load('-mat',fn);
catch
   uiwait(errordlg(sprintf('Error loading session file:\n%s', lasterr),...
                   'Load Error','modal'))
   dsmgr.turnOnUDDListener;
   return
end
dsmgr.turnOnUDDListener;
fmgr.turnOnUDDListener;

for j=1:nrequired
   if ~isfield(s,varnames{j})
      uiwait(errordlg('Not a valid Distribution Fitting session file',...
                   'File Invalid','modal'))
      return
   end
end
if ~isequal(s.ftype,ftype)
   uiwait(errordlg('Not a valid Distribution Fitting session file',...
                   'File Invalid','modal'))
   return
end

if ~ismember(s.version,allversions)
   uiwait(errordlg('Bad version number in Distribution Fitting session file',...
                   'Invalid Version','modal'))
   return
end

% Install the saved distribution definitions
dft = DistributionFitting.getDistributionFitting;
try
   dfsetdistributions(dft,s.alldists);
catch
   uiwait(errordlg(sprintf('Error loading saved session:\n%s',lasterr),...
                   'File Invalid','modal'));
end

% Reset some properties of the gui state
dffig = dfgetset('dffig');
dfsetplottype(dffig, s.guistate.ftype, s.guistate.dtype);
if isfield(s.guistate,'binDlgInfo')
   dfgetset('binDlgInfo',s.guistate.binDlgInfo);
end

hFunctionList = findall(dffig, 'Tag', 'displaylist');
ftypes = getappdata(hFunctionList,'codenames');
value = strmatch(s.guistate.ftype, ftypes, 'exact');
set(hFunctionList, 'Value', value);

isprobplot = isequal(s.guistate.ftype, 'probplot');
if isprobplot
   hDistributionList = findall(dffig, 'Tag', 'typelist');
   dtypes = getappdata(hDistributionList,'okcodenames');
   value = strmatch(s.guistate.dtype, dtypes, 'exact');
   set(hDistributionList, 'Value', value);
end

% Make sure distribution list is accurate
dfupdateppdists(dffig);

% Plot datasets that are flagged for plotting
for j=1:length(s.allds);
   dj = s.allds(j);

   % Now set the plot flag.  Some non-serializable information
   % (line handles, listeners, etc.) will be re-created at this point.
   dj.line = [];
   if s.dsinfo{j}
      dj.plot = 1;
   end
   dsmgr.addDataSet(java(dj), dj.name);
end

% Get exclusion rules (outliers)
omgr = OutliersManager.getOutliersManager;
omgr.init;

% Fix up fit objects
fitdb = getfitdb;
outdb = getoutlierdb;
for j=1:length(s.allfits)
   fj = s.allfits(j);

   % Restore all dataset handles
   dsname = fj.dataset;
   for k=1:length(s.allds)
      if isequal(dsname,s.allds(k).name)
         fj.dshandle = s.allds(k);
         break;
      end
   end

   % Restore all exclusion rule handles
   ername = fj.exclusionrulename;
   if ~isempty(ername)
      erhandle = find(outdb,'name',ername);
      fj.exclusionrule = erhandle;
   end

   % Connect this fit to the fit data base and add to fits manager
   connect(fj,fitdb,'up');

   % Now set the plot flag.  Some non-serializable information
   % (line handles, listeners, etc.) will be re-created at this point.
   fj.line = [];
   if s.fitinfo{j,1}
      fj.plot = 1;
   end
end

% ----------------------------------------------------------------
function ok=clearsession
%DFCLEARSESSION Callback to clear distribution fitting session

ok = true;

% Trigger java listeners to clear all saved java content
import com.mathworks.toolbox.stats.*;
DFToolClearManager.getDFToolClearManager.listenerTrigger;

% Delete all udd fit object instances
fitdb = getfitdb;
ft = down(fitdb);
while(~isempty(ft))
   ftnew = right(ft);
   delete(ft);
   ft = ftnew;
end

% Delete all udd data set object instances
dsdb = getdsdb;
dj = down(dsdb);
while(~isempty(dj))
   if dj.plot
      dj.plot = 0;
   end
   djnew = right(dj);
   delete(dj);
   dj = djnew;
end

% Delete all udd outlier object instances
outdb = getoutlierdb;
outliers = find(outdb);
outliers(outliers==outdb) = [];
delete(outliers);

%init (behind the scenes) analysis and plot


function dtiMrMeshSave(handles)
% Save the dti mesh structure and data required for mrmViewer.
%
%   dtiMrMeshSave(handles)
%
% The mrmViewer code should be:
%
%   load Test
%   msh = dtiGet(handles,'mrMesh');
%   msh.id = 101;   % Set up a number for the window
%   mrmSet(msh,'refresh');
%   msh = dtiInitMrMeshWindow(msh);
%   dtiMrMeshAddROIs(handles,msh);
%   dtiMrMeshAddFGs(handles,msh);
%   dtiMrMeshAddImages(handles,msh,origin,xIm,yIm,zIm);
%
% %Author: Wandell
% (c) Stanford VISTA Team

%   Programming notes.
%   Should we write a dtiLoadMesh, too?  That is not necessary, really,
%   because we should always be able to display from the current
%   data and ....
%

if notDefined('handles'), error('dtiFiberUI handles required.'); end

% Figure out the file
persistent meshPath;
if(isempty(meshPath)), meshPath = fullfile(handles.defaultPath, 'slice'); end
[f, p] = uiputfile({'*.mat';'*.*'}, 'Save current mesh...', meshPath);
if(isnumeric(f)), disp('dtiSaveMesh cancelled.'); return; end
fname = fullfile(p, f);
meshPath = fname;

% Get all of the potential images
anat = dtiGet(handles,'currentanatomydata');
curPosition  = dtiGet(handles,'curposition');
curXform = dtiGet(handles,'curacpcxform');
zIm = dtiGetSlice(curXform, anat, 3, curPosition(3));
yIm = dtiGetSlice(curXform, anat, 2, curPosition(2));
xIm = dtiGetSlice(curXform, anat, 1, curPosition(1));

% Empty out the images not needed for display
[xIm,yIm,zIm] = dtiMrMeshSelectImages(handles,xIm,yIm,zIm); %#ok<NASGU>
origin = dtiGet(handles,'origin'); %#ok<NASGU>

% Make the data size manageable by getting rid of the big variables
handles = rmfield(handles,'dt6');
%handles = rmfield(handles,'vec');
handles = rmfield(handles,'bg');

if isfield(handles,'t1NormParams')
    handles = rmfield(handles,'t1NormParams');
end
handles = rmfield(handles,'brainMask'); %#ok<NASGU>

% Save the file for mrmViewer
save(fname,'handles','origin','xIm','yIm','zIm');

return;


function im2ucms_all(database,gt_set)

if nargin==0
   database = 'pascal2012';
end
if nargin<2
   gt_set = 'train2012';
end

res_id = 'sf_mUCM';

% Multiple scales to work on, finest first
scales = [2, 1, 0.5];

% Result dir
res_dir = fullfile(root_dir,'datasets',database,res_id);

% Check that results dir exist
if ~exist(fullfile(res_dir,'multi'),'dir')
    mkdir(fullfile(res_dir,'multi'))
end
for ii=1:length(scales)
    if ~exist(fullfile(res_dir,['scale_',sprintf('%1.2f',scales(ii))]),'dir')
        mkdir(fullfile(res_dir,['scale_',sprintf('%1.2f',scales(ii))]))
    end
end

% Which images to process
im_ids = database_ids(database,gt_set);

% Load pre-trained model for contour detector
model = loadvar(fullfile(root_dir, 'datasets', 'models', 'sf_modelFinal.mat'),'model');

% Sweep all images in parallel
num_workers = 32;
if verLessThan('matlab','8.3') %Pre-2014A code
    if matlabpool('size') == 0
        matlabpool(num_workers)
    end
    parfor ii=1:length(im_ids)
        im = get_image(database,im_ids{ii});

        % Check if it is not computed already
        if ~exist(fullfile(res_dir,'multi',[im_ids{ii} '.mat']),'file')

            % Call the actual code
            [ucm2,ucms] = img2ucms(im, model, scales);

            % Store ucms at each scale separately
            parsave(fullfile(res_dir,'multi',[im_ids{ii} '.mat']),ucm2)
            for jj=1:length(scales)
                parsave(fullfile(res_dir,['scale_',sprintf('%1.2f',scales(jj))],[im_ids{ii} '.mat']),ucms(:,:,jj))
            end
        end
    end
    matlabpool close
else                    %2015A or later
    if isempty(gcp('nocreate'))
        parpool('local', num_workers)
    end
    parfor ii=1:length(im_ids)
        im = get_image(database,im_ids{ii});

        % Check if it is not computed already
        if ~exist(fullfile(res_dir,'multi',[im_ids{ii} '.mat']),'file')

            % Call the actual code
            [ucm2,ucms] = img2ucms(im, model, scales);

            % Store ucms at each scale separately
            parsave(fullfile(res_dir,'multi',[im_ids{ii} '.mat']),ucm2)
            for jj=1:length(scales)
                parsave(fullfile(res_dir,['scale_',sprintf('%1.2f',scales(jj))],[im_ids{ii} '.mat']),ucms(:,:,jj))
            end
        end
    end
    delete(gcp('nocreate'))
end
end

function parsave(res_file, ucm2) %#ok<INUSD>
    save(res_file,'ucm2');
end


function varargout = bdfVisualizer(varargin)
% BDFVISUALIZER MATLAB code for bdfVisualizer.fig
%      BDFVISUALIZER, by itself, creates a new BDFVISUALIZER or raises the existing
%      singleton*.
%
%      H = BDFVISUALIZER returns the handle to a new BDFVISUALIZER or the handle to
%      the existing singleton*.
%
%      BDFVISUALIZER('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in BDFVISUALIZER.M with the given input arguments.
%
%      BDFVISUALIZER('Property','Value',...) creates a new BDFVISUALIZER or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before bdfVisualizer_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to bdfVisualizer_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 bdfVisualizer

% Last Modified by GUIDE v2.5 15-Jan-2015 15:52:48

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @bdfVisualizer_OpeningFcn, ...
    'gui_OutputFcn',  @bdfVisualizer_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 bdfVisualizer is made visible.
function bdfVisualizer_OpeningFcn(hObject, ~, handles, varargin) %#ok<*DEFNU>
% 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 bdfVisualizer (see VARARGIN)

if(verLessThan('matlab', '8.2'))
    err_msg   = sprintf('Upgrade to Matlab 8.2 (2013b) or higher.\n\n BDF Visualizer will not run correctly for this Matlab version: %s.', version);
    err_title = 'Matlab Version Incompatibility';
    errorfound(err_msg, err_title);
    return;
end

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

% Update handles structure
guidata(hObject, handles);

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

%% Load default ELIST
handles.EEG                  = struct();
handles.EEG.EVENTLIST        = generateDefaultEventlistStruct();                      % nested function within BDFVISUALIZER.M
guidata(hObject, handles);                                                            % save EVENTLIST to HANDLES

% UPDATE GUI: ELIST Window
% tableEventList                    = struct2table(handles.EEG.EVENTLIST.eventinfo);
% handles.numBits                   = 16;
% tableEventList.bini               = [];
%
% % Convert the flag variable into its binary representation and split into
% % its user-flag and artifact-flag
% binaryFlag                        = dec2bin(tableEventList.flag, handles.numBits);    % Convert artifact flags & user flags to binary
% tableEventList.artifactFlag       = binaryFlag(:, 1:handles.numBits/2);
% tableEventList.userFlag           = binaryFlag(:, handles.numBits/2+1:end);
%
%
% % Rearrange the event list table so that the bin label is a the end
% tableEventList                    = tableEventList(:,[1:9 11:12 10]);

% Save the event-list table to the UI-table
tableEventList                    = eventlist2table(handles.EEG.EVENTLIST.eventinfo);
hUITableELIST                     = handle(handles.uitableELIST);
hUITableELIST.Data                = table2cell(tableEventList);
hUITableELIST.ColumnName          = tableEventList.Properties.VariableNames';

% UPDATE GUI: Eventlist Max window
hEditEventlistMax                 = handle(handles.editTxtEventlistMax);              % Retrieve data from the GUI
hEditEventlistMax.String          = num2str(length(hUITableELIST.Data));

%% Load default BDF
handles.bdf                     = generateDefaultBDFStruct();                         % load the text-string into HANDLES

hEditBDF                        = handle(handles.editBDF);
hEditBDF.String                 = handles.bdf;                                        % Display BDF to GUI

%% Initiate default BDF Feedback Window
hUITableBinlisterFeedback         = handle(handles.uitableBinlisterFeedback);
hUITableBinlisterFeedback.Data    = {'Total Event Codes', 'Bin 1'; 0         , 0        };

handles.lastPath = pwd;
% handles.EEG      = [];
% Update handles structure
guidata(hObject, handles);                                                          % save HANDLES structure to GUI

% --- Outputs from this function are returned to the command line.
function varargout = bdfVisualizer_OutputFcn(~, ~, 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
varargout{1} = handles.output;

function editBDF_Callback(~, ~, ~)
% hObject    handle to editBDF (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 editBDF as text
%        str2double(get(hObject,'String')) returns contents of editBDF as a double

% --- Executes during object creation, after setting all properties.
function editBDF_CreateFcn(hObject, ~, ~)
% hObject    handle to editBDF (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 pushbuttonAnalyzeBDF.
function pushbuttonAnalyzeBDF_Callback(~, ~, handles)
% hObject    handle to pushbuttonAnalyzeBDF (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

try
    % Turn the interface off for processing.
    InterfaceObj=findobj(handle(handles.windowBDFVisualizer),'Enable','on');
    set(InterfaceObj,'Enable','off');
    drawnow;

    hEditEventlistMax   = handle(handles.editTxtEventlistMax);              % Retrieve BDF data from the GUI
    eventlistMax        = str2double(hEditEventlistMax.String);

    % Load BDF
    hEditBDF        = handle(handles.editBDF);              % Retrieve BDF data from the GUI
    BDFfilename     = fullfile(pwd,'BDF-tmp.txt');          % Create temporary BDF-file
    fileID          = fopen(BDFfilename, 'wt');             %
    fprintf(fileID,'%s\n', hEditBDF.String{:});             %
    fclose( fileID);

    % Load ELIST
    objELIST                    = handle(handles.uitableELIST);                         % Get the current Event List from the GUI

    handles.EEG.EVENTLIST.eventinfo = cell2struct(objELIST.Data(1:eventlistMax,:), objELIST.ColumnName', 2);  %

    %% RUN BINLISTER
    [handles.EEG, handles.EEG.EVENTLIST]  = binlister( handles.EEG ... % emptyEEG
        , BDFfilename       ...         % inputBinDescriptorFile
        , 'none'            ...         % inputEventList
        , 'none'            ...         % outputEventList
        , []                ...         % forbiddenCodeArray
        , []                ...         % ignoreCodeArray
        , 0                 );          % reportable

    if(isempty(handles.EEG.EVENTLIST));
        % Turn the interface back on
        set(InterfaceObj,'Enable','on');
        drawnow;
        return;
    end

    %% Display updated ELIST-struct to GUI
    %     tableEventList                    = struct2table(handles.EEG.EVENTLIST.eventinfo);
    %     tableEventList.binaryFlag         = dec2bin(tableEventList.flag, handles.numBits);                % Convert artifact flags & user flags to binary
    %
    % convert each numeric column to a string in order to save to
    % UITABLE.DATA
    %     for col_index = 1:width(tableEventList)
    %         if(isnumeric(tableEventList.(col_index)))
    %             tableEventList.(col_index) = num2str(tableEventList.(col_index));
    %         end
    %     end

    %     for col_index = 1:width(tableEventList)
    %         if(isnumeric(tableEventList.(col_index)))
    %             columnSize = size(tableEventList.(col_index), 2);
    %             if(columnSize > 1)
    %                 tableEventList.(col_index) = num2str(tableEventList.(col_index));
    %             end
    %         end
    %     end

    %     tableEventList.bini = [];

    tableEventList                    = eventlist2table(handles.EEG.EVENTLIST.eventinfo);
    hUITableELIST                     = handle(handles.uitableELIST);
    hUITableELIST.Data                = table2cell(tableEventList);
    hUITableELIST.ColumnName          = tableEventList.Properties.VariableNames';

    drawnow;

    % hUITableELIST.columnWidth         = 'auto';
    % hUITableELIST.columnName          = fieldnames(handles.EEG.EVENTLIST.eventinfo);

    %% Display updated BDF Feedback window
    totalEvents                       = length(handles.EEG.EVENTLIST.eventinfo);
    hUITableBinlisterFeedback         = handle(handles.uitableBinlisterFeedback);
    %     hUITableBinlisterFeedback.rowName = { 'Total Event Codes', handles.EEG.EVENTLIST.bdf.namebin };
    hUITableBinlisterFeedback.Data    = [{'Total Event Codes' handles.EEG.EVENTLIST.bdf.namebin}', num2cell([totalEvents handles.EEG.EVENTLIST.trialsperbin])'];
    %% Cleanup
    delete(BDFfilename);                                    % Delete temporary BDF-file
    %     delete(ELISTfilename);                                  % Delete temporary ELIST-file
    %     set( findall(handles.windowBDFVisualizer, '-property', 'Enable'), 'Enable', 'on')

    % Turn the interface back on
    set(InterfaceObj,'Enable','on');
    drawnow;

catch errorObj
    % If there is a problem, display the error message
    display(getReport(errorObj,'extended','hyperlinks','on'),'Error');
    %     set(InterfaceObj,'Enable','on');

    if(strcmpi(errorObj.stack(1).name, 'binlister') && errorObj.stack(1).line == 706)
        errordlg(sprintf('\n\n\tCannot analyze a BDF file containing RT-flags without an EEG dataset.\n\n\tRemove exist RT-flags from the BDF-file or load an existing EEG dataset.\n\n'), 'RT-Flag Error');
    elseif(strcmpi(errorObj.stack(1).name, 'pushbuttonAnalyzeBDF_Callback') && errorObj.stack(1).line == 171)
        errordlg(sprintf('\n\n\tBin numbers must be in sequential order.\n\n\tFix your bin numbers.\n\n'), 'BDF - Bin Number Error');
    else
        errordlg(getReport(errorObj,'extended','hyperlinks','off'),'Error');
    end

    % Turn the interface back on
    set(InterfaceObj,'Enable','on');
    drawnow;

end

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

try

    [fileName, pathName, filterIndex] = uigetfile(              ...
        {'*.txt', 'Select a bin descriptor file (BDF)'   ...
        ; '*.*'  , 'All files (*.*)'                   } ...
        , 'Select BDF File' ...
        , handles.lastPath);
    if(pathName)
        handles.lastPath = pathName;                                             % Update the last directory in HANDLES
        guidata(hObject,handles);                                                % Update the HANDLES data-structure
    end

    switch(filterIndex)
        case 0
            % User-selected Cancel
            display('User selected cancel');
        otherwise
            % Load file into ELIST-structure via READEVENTLIST
            BDFfilename                 = fullfile(pathName,fileName);
            fileID                      = fopen(BDFfilename);
            fileString                  = textscan(fileID, '%s', 'Delimiter','\n');
            fclose(fileID);

            handles.bdf                 = fileString{1};    % Update the BDF variable in HANDLES
            handles.lastPath            = pathName;         % Update the last directory in HANDLES
            guidata(hObject,handles);                       % Update the HANDLES data-structure

            %% DISPLAY LOADED BDF TO GUI
            hEditBDF               = handle(handles.editBDF);
            hEditBDF.String        = handles.bdf;
    end

catch errorObj
    % If there is a problem, display the error message
    display(getReport(errorObj,'extended','hyperlinks','on'),'Error');
    %     set(InterfaceObj,'Enable','on');

    if(strcmpi(errorObj.stack(1).name, 'readeventlist') && errorObj.stack(1).line == 140)
        errordlg(sprintf('\n\nIncorrect File Type:\tFile is not an acceptable BIN DESCRIPTOR FILE.\n\nSelect another BDF0file\n\n'), 'Incorrect File Type Error');
    else
        errordlg(getReport(errorObj,'extended','hyperlinks','off'),'Error');
    end

end

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

try
    % Turn the interface off for processing.
    InterfaceObj=findobj(handle(handles.windowBDFVisualizer),'Enable','on');
    set(InterfaceObj,'Enable','off');
    drawnow;

    [fileName, pathName]        = uigetfile(               ...
        {'*.txt;*.set', 'ELIST (*.txt) or EEG file (*.set)';            ...
        '*.*','All Files (*.*)'                                }        ...
        , 'MultiSelect', 'off'                                          ...
        , 'Select Event List Source'                                    ...
        , handles.lastPath);   % Get filename/filepath

    if(pathName)
        % Clear the Binlister Feedback uiTable
        hUITableBinlisterFeedback         = handle(handles.uitableBinlisterFeedback);
        hUITableBinlisterFeedback.Data    = {'Total Event Codes', 'Bin 1'; 0         , 0         };

        [~,~,fileExtension] = fileparts(fileName);
        handles.lastPath    = pathName;                                                             % Update the last directory in HANDLES
        guidata(hObject,handles);                                                                   % Update the HANDLES data-structure
    else
        fileExtension       = 'cancel';
    end

    % Check if FILE SELECTED or if CANCEL is selected

    switch(fileExtension)
        case 'cancel'  % CANCEL
            display('User selected cancel');                                                    % User-selected Cancel
        case '.txt'  % ELIST-TXT file

            ELISTfilename               = fullfile(pathName,fileName);                          % Load file into ELIST-structure via READEVENTLIST
            [~, handles.EEG.EVENTLIST]  = readeventlist([], ELISTfilename);

            %% !!!!!!!!!!!!!!!!!!!!!!!!!!!
            % Display updated ELIST-struct to GUI
            tableEventList                    = eventlist2table(handles.EEG.EVENTLIST.eventinfo);
            hUITableELIST                     = handle(handles.uitableELIST);
            hUITableELIST.Data                = table2cell(tableEventList);
            hUITableELIST.ColumnName          = tableEventList.Properties.VariableNames';

            % UPDATE GUI: Eventlist Max window
            hEditEventlistMax                 = handle(handles.editTxtEventlistMax);              % Retrieve data from the GUI
            hEditEventlistMax.String          = num2str(length(hUITableELIST.Data));

        case '.set' % EEG-SET file
            handles.EEG = pop_loadset('filename',fileName,'filepath',pathName);
            handles.EEG = eeg_checkset( handles.EEG );

            % If EEG.EVENTLIST does not exist
            if(~isfield(handles.EEG, 'EVENTLIST'))
                % Create EVENTLIST from EEG dataset
                handles.EEG  = pop_creabasiceventlist( handles.EEG ...
                    ... %         , 'Eventlist','/Users/etfoo/Documents/MATLAB/Eventlist.txt' ...
                    , 'AlphanumericCleaning'    , 'on'              ...
                    , 'BoundaryNumeric'         , { -99 }           ...
                    , 'BoundaryString'          , { 'boundary' }    ...
                    , 'Warning'                 , 'off'              ...
                    );
            end

            %% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            % Update the GUI ELIST uiTable
            tableEventList                    = eventlist2table(handles.EEG.EVENTLIST.eventinfo);
            hUITableELIST                     = handle(handles.uitableELIST);
            hUITableELIST.Data                = table2cell(tableEventList);
            hUITableELIST.ColumnName          = tableEventList.Properties.VariableNames';

            % UPDATE GUI: Eventlist Max window
            hEditEventlistMax                 = handle(handles.editTxtEventlistMax);              % Retrieve data from the GUI
            hEditEventlistMax.String          = num2str(length(hUITableELIST.Data));

        otherwise
    end

    guidata(hObject,handles);                                                                   % Update the HANDLES data-structure

    % Turn the interface back on
    set(InterfaceObj,'Enable','on');
    drawnow;

catch errorObj
    % If there is a problem, display the error message
    display(getReport(errorObj,'extended','hyperlinks','on'),'Error');
    %     set(InterfaceObj,'Enable','on');

    if(strcmpi(errorObj.stack(1).name, 'readeventlist') && errorObj.stack(1).line == 140)
        errordlg(sprintf('\n\nIncorrect File Type:\tFile does not contain an acceptable EVENT LIST FILE.\n\nSelect another file\n\n'), 'Incorrect File Type Error');
    else
        errordlg(getReport(errorObj,'extended','hyperlinks','off'),'Error');
    end

    % Turn the interface back on
    set(InterfaceObj,'Enable','on');
    drawnow;

end

function editTxtEventlistMax_Callback(~, ~, ~)
% hObject    handle to editTxtEventlistMax (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 editTxtEventlistMax as text
%        str2double(get(hObject,'String')) returns contents of editTxtEventlistMax as a double

% --- Executes during object creation, after setting all properties.
function editTxtEventlistMax_CreateFcn(hObject, ~, ~)
% hObject    handle to editTxtEventlistMax (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 pushbuttonBDFManualLink.
function pushbuttonBDFManualLink_Callback(hObject, eventdata, handles)
% hObject    handle to pushbuttonBDFManualLink (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
web('https://github.com/lucklab/erplab/wiki/Assigning-Events-to-Bins-with-BINLISTER','-browser');

% --- Executes on button press in pushbuttonBDFTutorialLink.
function pushbuttonBDFTutorialLink_Callback(hObject, eventdata, handles)
% hObject    handle to pushbuttonBDFTutorialLink (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
web('https://github.com/lucklab/erplab/wiki/BDF-Library','-browser');

%% Nested functions

function eventlist = generateDefaultEventlistStruct()

eventlist                   = struct;
eventlist.setname           = 'none_specified';
eventlist.report            = '';
eventlist.bdfname           = '';
eventlist.nbin              = 0;
eventlist.version           = '4.0.3.1';
eventlist.account           = '';
eventlist.username          = '';
eventlist.trialsperbin      = 0;
eventlist.elname            = 'default eventlist';
eventlist.bdf               = struct;
eventlist.bdf.expression    = [];
eventlist.bdf.description   = [];
eventlist.bdf.prehome       = [];
eventlist.bdf.athome        = [];
eventlist.bdf.posthome      = [];
eventlist.bdf.namebin       = [];
eventlist.bdf.rtname        = [];
eventlist.bdf.rtindex       = [];
eventlist.bdf.rt            = [];
eventlist.eldate            = '14-Jan-2015 15:24:22';
eventlist.eventinfo                 = struct;

for x = 1:100
    eventlist.eventinfo(x).item         = 1;
    eventlist.eventinfo(x).bepoch       = 0;
    eventlist.eventinfo(x).code         = 256;
    eventlist.eventinfo(x).codelabel    = '"EMPTY"';
    eventlist.eventinfo(x).time         = single(x/10);
    eventlist.eventinfo(x).spoint       = single(x);
    eventlist.eventinfo(x).dura         = single(x);
    eventlist.eventinfo(x).flag         = 0;
    eventlist.eventinfo(x).enable       = 1;
    eventlist.eventinfo(x).bini         = -1;
    eventlist.eventinfo(x).binlabel     = '""';
end

function bdfFile = generateDefaultBDFStruct()

bdfFile      = cell(3, 1);
bdfFile{1,1} = 'bin 1';
bdfFile{2,1} = 'Empty trials';
bdfFile{3,1} = '.{256}';

function eventlistTable = eventlist2table(eventlistStruct)

% UPDATE GUI: ELIST Window
eventlistTable                    = struct2table(eventlistStruct);
handles.numBits                   = 16;
eventlistTable.bini               = [];

% Convert the flag variable into its binary representation and split into
% its user-flag and artifact-flag
mybinaryFlag                      = dec2bin(eventlistTable.flag, handles.numBits);    % Convert artifact flags & user flags to binary
eventlistTable.artifactFlag       = mybinaryFlag(:, handles.numBits/2+1:end);
eventlistTable.userFlag           = mybinaryFlag(:, 1:handles.numBits/2);

% Rearrange the event list table so that the bin label is a the end
varnames = eventlistTable.Properties.VariableNames;
others = ~strcmp('binlabel',varnames);
varnames = [varnames(others) 'binlabel'];
eventlistTable = eventlistTable(:,varnames);


%FbaLPWriter test
%
% Author: Jonathan Karr, jkarr@stanford.edu
% Affiliation: Covert Lab, Department of Bioengineering, Stanford University
% Last updaetd 2/3/2011
classdef FbaLPWriter_Test < TestCase
    methods
        function this = FbaLPWriter_Test(name)
            this = this@TestCase(name);
        end
    end

    methods
        %checks for run time errors
        function testWriter(~)
            sim = edu.stanford.covert.cell.sim.SimulationFixture.load([], true);
            edu.stanford.covert.cell.sim.util.FbaLPWriter.write(sim, 'output/runSmallTests');
        end
    end
end


function [paramList, paramPath, addCur] = getParamList(param, bottomFlag)
% Get all the end parameters and their paths for matching CPLEX parameters appropriately
% (e.g., if param.simplex.display is a parameter, then we will have 'display'
% in paramList and 'param.simplex' in paramPath)
%
% USAGE:
%
%    [paramList, paramPath, addCur] = getParamList(param, bottomFlag)
%
% INPUTS:
%    param:           existing structure with parameters for Cplex
%    bottomFlag:      boolean switch to extract parameters based on 'Cur' at the
%                     bottom level in the user-supplied parameter structure
%
% OUTPUTS:
%    paramList:       Cell with proper parameter names
%    paramPath:       Cell with superseeding parameter structure
%    addCur:          Structure with booleans whether or not `.Cur` has been
%                     added to the `paramPath` for user-supplied parameters
%

structCur = param;  % current structure
lv = 1;  % current level of the structure
% use a stack structure to store the found parameters
lvFieldN = zeros(10,1);
lvFieldN(1) = 1;  % the number of fields being checked at the current level
lvField = cell(10, 1);
lvField{lv} = fieldnames(structCur);  % all fields in the current level
paramPath = {};
paramList = {};
addCur = [];
while lv > 0
    if isstruct(structCur.(lvField{lv}{lvFieldN(lv)}))
        % if the current level is still a structure
        if ~isempty(fieldnames(structCur.(lvField{lv}{lvFieldN(lv)})))
            % if it is not an empty structure, go into that structure
            structCur = structCur.(lvField{lv}{lvFieldN(lv)});
            lv = lv + 1;  % level + 1
            % start checking from the first field in the next level of structure
            lvFieldN(lv) = 1;
            % get all fields for the next structure
            lvField{lv} = fieldnames(structCur);
        else
            % an empty structure, go back to the closest level with any unchecked structures
            while lvFieldN(lv) == numel(lvField{lv})
                lv = lv - 1;
                if lv == 0
                    % finish if level = 0
                    break
                end
            end
            if lv > 0
                % check the next structure in the current level
                lvFieldN(lv) = lvFieldN(lv) + 1;
                structCur = param;
                for j = 1:lv-1
                    structCur = structCur.(lvField{j}{lvFieldN(j)});
                end
            end
        end
    else
        addCurLv = false;
        if ~bottomFlag || strcmpi(lvField{lv}{lvFieldN(lv)}, 'Cur')
            % if the current level is not a structure, with the bottomFlag off
            % (not going to the bottom level, for LP.Param), or if the current level
            % is named 'Cur' (may happen in the user-supplied parameter structure),
            % decrease one level since the bottom level of all parameters is either
            % 'Min', 'Max', 'Cur', 'Def', 'Name', 'Help' containing the information
            % for the parameter, which is the name for the structure immediately on
            % top of the current level
            lv = lv - 1;
            if bottomFlag  % 'Cur' at the bottom level in the user-supplied parameters
                addCurLv = true;
            end
        end
        if lv > 0
            % get the path for the current parameter
            c = {};
            for j = 1:lv
                c = [c lvField{j}(lvFieldN(j))];
            end
            paramPath = [paramPath; strjoin(c,'.')];
            % whether or not need to add back .Cur to the path for user-supplied parameters
            if addCurLv
                addCur = [addCur; true];
            else
                addCur = [addCur; false];
            end
            paramList = [paramList; c(end)];
            % go back to the closest level with any unchecked structures
            while lvFieldN(lv) == numel(lvField{lv})
                lv = lv - 1;
                if lv == 0
                    % finish if level = 0
                    break
                end
            end
            if lv > 0
                % check the next structure in the current level
                lvFieldN(lv) = lvFieldN(lv) + 1;
                structCur = param;
                for j = 1:lv-1
                    structCur = structCur.(lvField{j}{lvFieldN(j)});
                end
            end
        else
            % if lv = 0 because of bottomFlag, continue at lv = 1
            lv = 1;
            if lvFieldN(lv) == numel(lvField{lv})
                break
            else
                lvFieldN(1) = lvFieldN(1) + 1;
            end
        end
    end
end
end