function [cfg] = ft_topoplotTFR(cfg, varargin)

% FT_TOPOPLOTTFR plots the topographic distribution over the head
% of a 3-dimensional data representations such as time-frequency
% representation of the power or coherence spectrum.
%
% Use as
%   ft_topoplotTFR(cfg, freq)
%
% The input freq structrure should contain a time-resolved power or
% coherence spectrum from FT_FREQANALYSIS or FT_FREQDESCRIPTIVES.
%
% The configuration can have the following parameters
%   cfg.parameter          = field that contains the data to be plotted as color, for example 'avg', 'powspctrm' or 'cohspctrm' (default is automatic)
%   cfg.maskparameter      = field in the data to be used for masking of data. It should have alues between 0 and 1, where 0 corresponds to transparent.
%   cfg.xlim               = limit for 1st dimension in data (e.g., time), can be 'maxmin' or [xmin xmax] (default = 'maxmin')
%   cfg.ylim               = limit for 2nd dimension in data (e.g., freq), can be 'maxmin' or [ymin ymax] (default = 'maxmin')
%   cfg.zlim               = limits for color dimension, 'maxmin', 'maxabs', 'zeromax', 'minzero', or [zmin zmax] (default = 'maxmin')
%   cfg.channel            = Nx1 cell-array with selection of channels (default = 'all'), see FT_CHANNELSELECTION for details
%   cfg.refchannel         = name of reference channel for visualising connectivity, can be 'gui'
%   cfg.baseline           = 'yes','no' or [time1 time2] (default = 'no'), see FT_TIMELOCKBASELINE or FT_FREQBASELINE
%   cfg.baselinetype       = 'absolute' or 'relative' (default = 'absolute')
%   cfg.trials             = 'all' or a selection given as a 1xN vector (default = 'all')
%   cfg.colormap           = string, or Nx3 matrix, see FT_COLORMAP
%   cfg.marker             = 'on', 'labels', 'numbers', 'off'
%   cfg.markersymbol       = channel marker symbol (default = 'o')
%   cfg.markercolor        = channel marker color (default = [0 0 0] (black))
%   cfg.markersize         = channel marker size (default = 2)
%   cfg.markerfontsize     = font size of channel labels (default = 8 pt)
%   cfg.highlight          = 'off', 'on', 'labels', 'numbers'
%   cfg.highlightchannel   =  Nx1 cell-array with selection of channels, or vector containing channel indices see FT_CHANNELSELECTION
%   cfg.highlightsymbol    = highlight marker symbol (default = 'o')
%   cfg.highlightcolor     = highlight marker color (default = [0 0 0] (black))
%   cfg.highlightsize      = highlight marker size (default = 6)
%   cfg.highlightfontsize  = highlight marker size (default = 8)
%   cfg.hotkeys            = enables hotkeys (pageup/pagedown/m) for dynamic zoom and translation (ctrl+) of the color limits
%   cfg.colorbar           = 'yes'
%                            'no' (default)
%                            'North'              inside plot box near top
%                            'South'              inside bottom
%                            'East'               inside right
%                            'West'               inside left
%                            'NorthOutside'       outside plot box near top
%                            'SouthOutside'       outside bottom
%                            'EastOutside'        outside right
%                            'WestOutside'        outside left
%   cfg.colorbartext       =  string indicating the text next to colorbar
%   cfg.interplimits       = limits for interpolation (default = 'head')
%                            'electrodes' to furthest electrode
%                            'head' to edge of head
%   cfg.interpolation      = 'linear','cubic','nearest','v4' (default = 'v4') see GRIDDATA
%   cfg.style              = plot style (default = 'both')
%                            'straight' colormap only
%                            'contour' contour lines only
%                            'both' (default) both colormap and contour lines
%                            'fill' constant color between lines
%                            'blank' only the head shape
%   cfg.gridscale          = scaling grid size (default = 67)
%                            determines resolution of figure
%   cfg.shading            = 'flat' or 'interp' (default = 'flat')
%   cfg.comment            = 'no', 'auto' or 'xlim' (default = 'auto')
%                            'auto': date, xparam, yparam and parameter limits are printed
%                            'xlim': only xparam limits are printed
%                            'ylim': only yparam limits are printed
%   cfg.commentpos         = string or two numbers, position of the comment (default = 'leftbottom')
%                            'lefttop' 'leftbottom' 'middletop' 'middlebottom' 'righttop' 'rightbottom'
%                            'title' to place comment as title
%                            'layout' to place comment as specified for COMNT in layout
%                            [x y] coordinates
%   cfg.interactive        = Interactive plot 'yes' or 'no' (default = 'yes')
%                            In a interactive plot you can select areas and produce a new
%                            interactive plot when a selected area is clicked. Multiple areas
%                            can be selected by holding down the SHIFT key.
%   cfg.directionality     = '', 'inflow' or 'outflow' specifies for
%                            connectivity measures whether the inflow into a
%                            node, or the outflow from a node is plotted. The
%                            (default) behavior of this option depends on the dimor
%                            of the input data (see below).
%   cfg.layout             = specify the channel layout for plotting using one of
%                            the supported ways (see below).
%   cfg.interpolatenan     = string 'yes', 'no' (default = 'yes')
%                            interpolate over channels containing NaNs
%
% For the plotting of directional connectivity data the cfg.directionality
% option determines what is plotted. The default value and the supported
% functionality depend on the dimord of the input data. If the input data
% is of dimord 'chan_chan_XXX', the value of directionality determines
% whether, given the reference channel(s), the columns (inflow), or rows
% (outflow) are selected for plotting. In this situation the default is
% 'inflow'. Note that for undirected measures, inflow and outflow should
% give the same output. If the input data is of dimord 'chancmb_XXX', the
% value of directionality determines whether the rows in data.labelcmb are
% selected. With 'inflow' the rows are selected if the refchannel(s) occur in
% the right column, with 'outflow' the rows are selected if the
% refchannel(s) occur in the left column of the labelcmb-field. Default in
% this case is '', which means that all rows are selected in which the
% refchannel(s) occur. This is to robustly support linearly indexed
% undirected connectivity metrics. In the situation where undirected
% connectivity measures are linearly indexed, specifying 'inflow' or
% 'outflow' can result in unexpected behavior.
%
% The layout defines how the channels are arranged. You can specify the
% layout in a variety of ways:
%  - you can provide a pre-computed layout structure (see prepare_layout)
%  - you can give the name of an ascii layout file with extension *.lay
%  - you can give the name of an electrode file
%  - you can give an electrode definition, i.e. "elec" structure
%  - you can give a gradiometer definition, i.e. "grad" structure
% If you do not specify any of these and the data structure contains an
% electrode or gradiometer structure, that will be used for creating a
% layout. If you want to have more fine-grained control over the layout
% of the subplots, you should create your own layout file.
%
% To facilitate data-handling and distributed computing you can use
%   cfg.inputfile   =  ...
%   cfg.inputfile   =  ...
% If you specify this option the input data will be read from a *.mat
% file on disk. This mat files should contain only a single variable named 'data',
% corresponding to the input structure. For this particular function, the input should be
% structured as a cell-array.
%
% See also FT_TOPOPLOTER, FT_TOPOPLOTIC, FT_SINGLEPLOTTFR, FT_MULTIPLOTTFR, FT_PREPARE_LAYOUT

% Undocumented options:
%
% It is possible to use multiple highlight-selections (e.g.: multiple
% statistical clusters of channels) To do this, all the content of
% the highlight-options (including cfg.highlight) should be placed
% in a cell-array (even if the normal content was already in a
% cell-array). Specific marker settings (e.g. color, size) are defaulted
% when not present.
%
% Example (3 selections):
% cfg.highlight          = {'labels', 'labels', 'numbers'}
% cfg.highlightchannel   = {{'MZF03','MZC01','MRT54'}, [1:5], 'C*'}
% cfg.highlightsymbol    = {'o',[],'+'}        % the empty option will be defaulted
% cfg.highlightcolor     = {'r',[0 0 1]};      % the missing option will be defaulted
% cfg.highlightsize      = [];                 % will be set to default, as will the missing cfg.highlightfontsize
%
% Other options:
% cfg.labeloffset (offset of labels to their marker, default = 0.005)

% Copyright (C) 2005-2017, F.C. Donders Centre
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

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

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

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

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

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

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

% make sure figure window titles are labeled appropriately, pass this onto the actual plotting function
cfg.funcname = mfilename;
cfg.dataname = dataname;

% prepare the layout, this should be done only once
tmpcfg = keepfields(cfg, {'layout', 'channel', 'rows', 'columns', 'commentpos', 'skipcomnt', 'scalepos', 'skipscale', 'projection', 'viewpoint', 'rotate', 'width', 'height', 'elec', 'grad', 'opto', 'showcallinfo', 'trackcallinfo', 'trackusage', 'trackdatainfo', 'trackmeminfo', 'tracktimeinfo', 'checksize'});
cfg.layout = ft_prepare_layout(tmpcfg, varargin{1});

% call the common function that is shared between ft_topoplotER and ft_topoplotTFR
[cfg] = topoplot_common(cfg, varargin{:});

% remove this field again, it is only used for figure labels
cfg = removefields(cfg, 'funcname');

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

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

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


function [feat] = batch_feature(filelist, imgset, feature, c)
%
% Copyright Aditya Khosla http://mit.edu/khosla
%
% Please cite this paper if you use this code in your publication:
%   A. Khosla, J. Xiao, A. Torralba, A. Oliva
%   Memorability of Image Regions
%   Advances in Neural Information Processing Systems (NIPS) 2012
%

if(~exist('c', 'var'))
  c = conf();
end

p = c.feature_config.(feature);
if(isfield(p, 'dictionary_size') && isfield(p, 'dictionary_file'))
	feature_file = sprintf(p.([imgset '_file']), c.cache, p.dictionary_size);
	batch_folder = [c.cache '/' imgset '_' feature '_' num2str(p.dictionary_size) '/'];
else
  feature_file = sprintf(p.([imgset '_file']), c.cache);
	batch_folder = [c.cache '/' imgset '_' feature '_' num2str(p.feature_size) '/'];
end

if(exist(feature_file, 'file'))
  load(feature_file);
  return;
end

num_batches = ceil(length(filelist)/c.batch_size);
batch_idx = arrayfun(@(x) (x-1)*c.batch_size+1:min(x*c.batch_size, length(filelist)), 1:num_batches, 'UniformOutput', false);
batch_order = randperm(num_batches);
batch_files = cell(num_batches, 1);

vprintf(c.verbosity, 0, 'Processing filelist (%s, %s): batch %d of %d\r', imgset, feature, 0, num_batches);
for b=1:num_batches
    this_batch = batch_idx{batch_order(b)};
    batch_file = [batch_folder num2str(batch_order(b)) '.mat'];
    batch_files{batch_order(b)} = batch_file;
    vprintf(c.verbosity, 0, 'Processing filelist (%s, %s): batch %d of %d\r', imgset, feature, b, num_batches);
    if(~exist(batch_file, 'file'))
        parsaveFeat(batch_file, [], []);
        poolfeat = filelist_feature('', filelist(this_batch), feature, c);
        parsaveFeat(batch_file, poolfeat, this_batch);
    end
end
vprintf(c.verbosity, 0, '\n');

if(nargout>0)
    feat = cell(num_batches, 1);
    for i=1:num_batches
        tmp = load(batch_files{i});
        feat{i} = tmp.poolfeat;
    end
    feat = cell2mat(feat);
else
    feat = {};
end

if exist('OCTAVE_VERSION','builtin')
    save(feature_file, 'feat', 'batch_files', '-v7');
else
    % -v7.3 is used for storing large files
    save(feature_file, 'feat', 'batch_files', '-v7.3');
end


function el = export_CT_image_module_field(args)
%"export_CT_image_module_field"
%   Given a single scan, return a properly populated CT_image module tag
%   for use with any Composite Image IOD.  See CT_image_module_tags.m.
%
%   For speed, tag must be a decimal representation of the 8 digit
%   hexidecimal DICOM tag desired, ie instead of '00100010', pass
%   hex2dec('00100010');
%
%   Arguments are passed in a structure, arg:
%       arg.tag         = decimal tag of field to fill
%       arg.data        = CERR structure(s) to fill from
%       arg.template    = an empty template of the module created by the
%                         function build_module_template.m
%
%   This function requires arg.data = {scanInfoS, scanS};
%
%JRA 06/19/06
%NAV 07/19/16 updated to dcm4che3
%   replaced ml2dcm_Element to data2dcmElement
%
%Usage:
%   el = export_CT_image_module_field(args)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

%Init output element to empty.
el = [];

%Unpack input parameters.
tag         = args.tag;
scanInfoS   = args.data{1};
scanS       = args.data{2};
template    = args.template;

switch tag
    %Class 1 Tags -- Required, must have data.
    case 524296     %0008,0008 Image Type
        data = {'ORIGINAL', 'PRIMARY', 'AXIAL'};
        el = data2dcmElement(data, tag);

    case 2621442    %0028,0002 Samples per Pixel
        data = 1;               %1 image plane in all CT/MR images.
        el = data2dcmElement(data, tag);

    case 2621444    %0028,0004 Photometric Interpretation
        data = 'MONOCHROME2';   %CT/MR have 0 black, maxVal white.
        el = data2dcmElement(data, tag);

    case 2621456    %0028,0010 Rows
        data = scanInfoS.sizeOfDimension1;
        el = data2dcmElement(data, tag);

    case 2621457    %0028,0011 Columns
        data = scanInfoS.sizeOfDimension2;
        el = data2dcmElement(data, tag);

    case 2621696    %0028,0100 Bits Allocated
        data = 16;              %C.8.2.1.1.4 of PS 3.3 - 2006
        el = data2dcmElement(data, tag);

    case 2621697    %0028,0101 Bits Stored
                                %C.8.2.1.1.4 of PS 3.3 - 2006
                                %Sloppy, consider revising.
        bools = [scanS.scanInfo.zValue] == scanInfoS.zValue;
        vals = scanS.scanArray(:,:,bools);
        maxV = max(vals(:));
        log2s = log2(double(maxV));
        mostSignificantBit = floor(max(log2s)) + 1;
        data = max(mostSignificantBit, 12);
        data = min(data, 16);
        el = data2dcmElement(data, tag);

    case 2621698    %0028,0102 High Bit
                                %C.8.2.1.1.4 of PS 3.3 - 2006
                                %Sloppy, consider revising.
        bools = [scanS.scanInfo.zValue] == scanInfoS.zValue;
        vals = scanS.scanArray(:,:,bools);
        maxV = max(vals(:));
        log2s = log2(double(maxV));
        mostSignificantBit = floor(max(log2s)) + 1;
        data = max(mostSignificantBit, 12);
        data = min(data, 16);
        data = data - 1;
        el = data2dcmElement(data, tag);

    case 2625618    %0028,1052 Rescale Intercept
        ctO = scanInfoS.CTOffset;
        data = -ctO;           %CERR exports stored values as 1*HU + CTOffset.
        el = data2dcmElement(data, tag);

    case 2625619    %0028,1053 Rescale Slope
        %data = 1;
        %data = scanInfoS.rescaleSlope;
        data = args.data{3}; %APA: factor for conversion to uint16 for modalities other than CT
        bools = [scanS.scanInfo.zValue] == scanInfoS.zValue;
        data = data(bools);
        data = data(1); % handle multiple slices at same z-location
        el = data2dcmElement(data, tag);

    %Class 2 Tags -- Must be present, can be NULL.
    case 1572960    %0018,0060 KVP

        %el = org.dcm4che3.data.Attributes;
        %el.setString(tag, template.getVR(tag), template.getString(tag));
        %data = args.data{1};
        data = [];
        el = data2dcmElement(data, tag);

    case 2097170    %0020,0012 Acqusition Number

        %el = org.dcm4che3.data.Attributes;
        %el.setString(tag, template.getVR(tag), template.getString(tag));
        %data = args.data{1};
        data = [];
        el = data2dcmElement(data, tag);

    %Class 3 Tags -- presence is optional, currently undefined.
    case 1572898    %0018,0022 Scan Options
    case 1573008    %0018,0090 Data Collection Diameter
    case 1577216    %0018,1100 Reconstruction Diameter
    case 1577232    %0018,1110 Distance Source to Detector
    case 1577233    %0018,1111 Distance Source to Patient
    case 1577248    %0018,1120 Gantry/Detector Tilt
    case 1577264    %0018,1130 Table Height
    case 1577280    %0018,1140 Rotation Direction
    case 1577296    %0018,1150 Exposure Time
    case 1577297    %0018,1151 X-ray Tube Current
    case 1577298    %0018,1152 Exposure
    case 1577299    %0018,1153 Exposure in microAs
    case 1577312    %0018,1160 Filter Type
    case 1577328    %0018,1170 Generator Power
    case 1577360    %0018,1190 Focal Spot
    case 1577488    %0018,1210 Convolution Kernal
    case 1610501    %0018,9305 Revolution Time
    case 1610502    %0018,9306 Single Collimation Width
    case 1610503    %0018,9307 Total Collimation Width
    case 1610505    %0018,9309 Table Speed
    case 1610512    %0018,9310 Table Feed per Rotation
    case 1610513    %0018,9311 CT Pitch Factor
    case 1610531    %0018,9323 Exposure Modulation Type
    case 1610532    %0018,9324 Estimated Dose Saving
    case 1610565    %0018,9345 CTDIvol

    %Class 1C Tags

    %Class 2C Tags

    otherwise
        warning(['No methods exist to populate DICOM image_pixel module field ' dec2hex(tag,8) '.']);
        return;
end


function [orig, data] = load_curry_data_file(datafile)

[PathName, FileName, Extension] = fileparts(datafile);

if isempty(PathName)
  % the dataset is in the current working directory, refer to this with a .
  % to ensure proper path detection later on
  PathName = '.';
end

FileName = [FileName, Extension];
PathName = [PathName filesep]; % add the / or \

% loads Curry dat/dap/rs3 files into MATLAB and displays their waveforms
%{
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ask user to specify file
Title = 'Open Curry Data File';

[FileName,PathName,FilterIndex] = uigetfile({'*.cdt;*.dat' 'All Curry Data Files';'*.cdt' 'Curry 8 Data Files'; '*.dat' 'Curry 7 Data Files'},Title,pwd);

if ( FilterIndex == 0 )
    return;
end

if ( FileName == 0 )
    msgbox('Invalid File Name',Title,'error');
    return;
end
%}

Length = size(FileName,2);
DataFile = [PathName,FileName];
Extension = FileName(Length-2:Length);

if ( strcmpi ( Extension,'dat' ) )
    BaseName = [PathName,FileName(1:Length-4)];
    ParameterFile = [BaseName,'.dap'];
    LabelFile = [BaseName,'.rs3'];
    EventFile = [BaseName,'.cef'];
    EventFile2 = [BaseName,'.ceo'];
elseif ( strcmpi ( Extension,'cdt' ) )
    ParameterFile = [PathName,FileName,'.dpa'];
    LabelFile = [PathName,FileName,'.dpa'];
    EventFile = [PathName,FileName,'.cef'];
    EventFile2 = [PathName,FileName,'.ceo'];
else
    %msgbox('Unsupported File Name (choose a .cdt or .dat file)',Title,'error');
    error('Unsupported File Name (choose a .cdt or .dat file)');
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% open parameter file
fid = fopen_or_error(ParameterFile,'rt');
cell = textscan(fid,'%s','whitespace','','endofline',char(167));
fclose(fid);
cont = cell2mat(cell{1});

% check for compressed file format
ctok = 'DataGuid';
ix = strfind(cont,ctok);
if ~isempty ( ix )
    text = sscanf(cont(ix+numel(ctok):end),' = %s');
    if (strcmp(text, '{2912E8D8-F5C8-4E25-A8E7-A1385967DA09}') == 1)
        msgbox('Unsupported data format (compressed). Use Curry to convert this file to Raw Float format.',Title, 'error')
        return;
    end
end

% read parameters from parameter file
% tokens (second line is for Curry 6 notation)
tok = { 'NumSamples'; 'NumChannels'; 'NumTrials'; 'SampleFreqHz';  'TriggerOffsetUsec';  'DataFormat'; 'DataSampOrder';   'SampleTimeUsec';
        'NUM_SAMPLES';'NUM_CHANNELS';'NUM_TRIALS';'SAMPLE_FREQ_HZ';'TRIGGER_OFFSET_USEC';'DATA_FORMAT';'DATA_SAMP_ORDER'; 'SAMPLE_TIME_USEC'};

% scan in cell 1 for keywords - all keywords must exist!
nt = size(tok,1);
a = zeros(nt,1);
for i = 1:nt
     ctok = tok{i,1};
     ix = strfind(cont,ctok);
     if ~isempty ( ix )
         text = sscanf(cont(ix+numel(ctok):end),' = %s');     % skip =
         if strcmp ( text,'ASCII' ) || strcmp ( text,'CHAN' ) % test for alphanumeric values
             a(i) = 1;
         else
             c = sscanf(text,'%f');         % try to read a number
             if ~isempty ( c )
                 a(i) = c;                  % assign if it was a number
             end
         end
     end
end

% derived variables. numbers (1) (2) etc are the token numbers
nSamples    = a(1)+a(1+nt/2);
nChannels   = a(2)+a(2+nt/2);
nTrials     = a(3)+a(3+nt/2);
fFrequency  = a(4)+a(4+nt/2);
fOffsetUsec = a(5)+a(5+nt/2);
nASCII      = a(6)+a(6+nt/2);
nMultiplex  = a(7)+a(7+nt/2);
fSampleTime = a(8)+a(8+nt/2);

if ( fFrequency == 0 && fSampleTime ~= 0 )
    fFrequency = 1000000 / fSampleTime;
end

% try to guess number of samples based on datafile size
if nSamples < 0
    if nASCII == 1
        msgbox('Number of samples cannot be guessed from ASCII data file. Use Curry to convert this file to Raw Float format.',Title,'error');
        return;
    else
        fileInfo = dir(DataFile);
        fileSize = fileInfo.bytes;
        nSamples = fileSize / (4 * nChannels * nTrials);
    end
end

%Search for Impedance Values
tixstar = strfind(cont,'IMPEDANCE_VALUES START_LIST');
tixstop = strfind(cont,'IMPEDANCE_VALUES END_LIST');

impedancelist = [];
impedancematrix = [];

if (~isempty(tixstar)) && (~isempty(tixstop))
    text = cont(tixstar:tixstop-1);
    tcell = textscan(text,'%s');
    tcell = tcell{1,1};
    for tcC = 1:size(tcell,1)
       tcell{tcC} = str2num(tcell{tcC}); % data was read in as strings - force to numbers
       if ~isempty(tcell{tcC}) % skip if it is not a number
           impedancelist(end+1) = tcell{tcC};
       end
    end

    % Curry records last 10 impedances
    impedancematrix = reshape(impedancelist,[(size(impedancelist,2)/10),10])';
    impedancematrix(impedancematrix == -1) = NaN; % screen for missing
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% open label file
fid = fopen_or_error(LabelFile,'rt');
cell = textscan(fid,'%s','whitespace','','endofline',char(167));
fclose(fid);
cont = cell2mat(cell{1});

% read labels from label file
% initialize labels
labels = num2cell(1:nChannels);

for i = 1:nChannels
    text = sprintf('EEG%d',i);
    labels(i) = cellstr(text);
end

% scan in cell 1 for LABELS (occurs four times per channel group)
ix = strfind(cont,[char(10),'LABELS']);
nt = size(ix,2);
nc = 0;

for i = 4:4:nt                                                      % loop over channel groups
    newlines = ix(i-1) + strfind(cont(ix(i-1)+1:ix(i)),char(10));   % newline
    last = nChannels - nc;
    for j = 1:min(last,size(newlines,2)-1)                          % loop over labels
        text = cont(newlines(j)+1:newlines(j+1)-1);
        if isempty(strfind(text,'END_LIST'))
            nc = nc + 1;
            labels(nc) = cellstr(text);
        else
            break
        end
    end
end

% read sensor locations from label file
% initialize sensor locations
sensorpos = zeros(3,0);

% scan in cell 1 for SENSORS (occurs four times per channel group)
ix = strfind(cont,[char(10),'SENSORS']);
nt = size(ix,2);
nc = 0;

for i = 4:4:nt                                                      % loop over channel groups
    newlines = ix(i-1) + strfind(cont(ix(i-1)+1:ix(i)),char(10));   % newline
    last = nChannels - nc;
    for j = 1:min(last,size(newlines,2)-1)                          % loop over labels
        text = cont(newlines(j)+1:newlines(j+1)-1);
        if isempty(strfind(text,'END_LIST'))
            nc = nc + 1;
            tcell = textscan(text,'%f');
            posx = tcell{1}(1);
            posy = tcell{1}(2);
            posz = tcell{1}(3);
            sensorpos = cat ( 2, sensorpos, [ posx; posy; posz ] );
        else
            break
        end
    end
end

%Search for Epoch Labels
tixstar = strfind(cont,'EPOCH_LABELS START_LIST');
tixstop = strfind(cont,'EPOCH_LABELS END_LIST');

epochlabelslist = [];

if (~isempty(tixstar)) && (~isempty(tixstop))
    text = cont(tixstar:tixstop-1);
    tcell = textscan(text,'%s', 'delimiter','\n','whitespace','', 'headerlines', 1);
    epochlabelslist = tcell{1,1};
end

%Search for Epoch Information
tixstar = strfind(cont,'EPOCH_INFORMATION START_LIST');
tixstop = strfind(cont,'EPOCH_INFORMATION END_LIST');

epochinformationlist = [];

if (~isempty(tixstar)) && (~isempty(tixstop))
    text = cont(tixstar:tixstop-1);
    tcell = textscan(text,'%d%d%d%d%d%d%d', 'delimiter','\n','headerlines', 1);
    epochinformationlist = cell2mat(tcell);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% read events from event file
% initialize events
ne = 0;                                                             % number of events
events = zeros(4,0);
annotations = cellstr('empty');

% find appropriate file
fid = fopen(EventFile,'rt');

if fid < 0
    fid = fopen(EventFile2,'rt');
end

if fid >= 0
    cell = textscan(fid,'%s','whitespace','','endofline',char(167));
    fclose(fid);
    cont = cell2mat(cell{1});

    % scan in cell 1 for NUMBER_LIST (occurs five times)
    ix = strfind(cont,'NUMBER_LIST');

    newlines = ix(4) - 1 + strfind(cont(ix(4):ix(5)),char(10));     % newline
    last = size(newlines,2)-1;
    for j = 1:last                                                  % loop over labels
        text = cont(newlines(j)+1:newlines(j+1)-1);
        tcell = textscan(text,'%d');
        sample = tcell{1}(1);                                       % access more content using different columns
        type = tcell{1}(3);
        startsample = tcell{1}(5);
        endsample = tcell{1}(6);
        ne = ne + 1;
        events = cat ( 2, events, [ sample; type; startsample; endsample ] );
    end

    % scan in cell 1 for REMARK_LIST (occurs five times)
    ix = strfind(cont,'REMARK_LIST');
    na = 0;

    newlines = ix(4) - 1 + strfind(cont(ix(4):ix(5)),char(10));     % newline
    last = size(newlines,2)-1;
    for j = 1:last                                                  % loop over labels
        text = cont(newlines(j)+1:newlines(j+1)-1);
        na = na + 1;
        annotations(na) = cellstr(text);
    end
end

if nargout>1

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % read data file
    if nASCII == 1
        fid = fopen_or_error(DataFile,'rt');
        cell = textscan(fid,'%f',nChannels*nSamples*nTrials);
        fclose(fid);
        data = reshape([cell{1}],nChannels,nSamples*nTrials);
    else
        fid = fopen_or_error(DataFile,'rb');
        data = fread(fid,[nChannels,nSamples*nTrials],'float32');
        fclose(fid);
    end

    if nSamples*nTrials ~= size(data,2)
        msgbox('Inconsistent number of samples. File may be displayed incompletely.', 'WARNING', 'warn')
        nSamples = size(data,2)/nTrials;
    end
    % transpose?
    if nMultiplex == 1
        data = data';
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% time axis
time = linspace(fOffsetUsec/1000,fOffsetUsec/1000+(nSamples*nTrials-1)*1000/fFrequency,nSamples*nTrials);

%{
% simple plot
subplot(2,1,1);
plot(time,data);

% stacked plot
subplot(2,1,2);
range = max([abs(min(min(data))) abs(max(max(data)))]);
shift = linspace((nChannels-1)*range*0.3,0,nChannels);
plot(time,data+repmat(shift,nSamples*nTrials,1)');
set(gca,'ytick',flip(shift),'yticklabel',flip(labels),'GridLineStyle',':','XGrid','on','YGrid','off');
ylim([min(min(data+repmat(shift,nSamples*nTrials,1)')) max(max(data+repmat(shift,nSamples*nTrials,1)'))]);
%}

orig = [];
orig.nSamples    = nSamples;
orig.nChannels   = nChannels;
orig.nTrials     = nTrials;
orig.fFrequency  = fFrequency;
orig.fOffsetUsec = fOffsetUsec;
orig.nASCII      = nASCII;
orig.nMultiplex  = nMultiplex;
orig.fSampleTime = fSampleTime;
orig.events      = events;
orig.labels      = labels;
orig.time        = time;
orig.impedancematrix = impedancematrix;
orig.sensorpos       = sensorpos;
orig.epochlabelslist = epochlabelslist;
orig.epochinformationlist = epochinformationlist;
orig.ne          = ne;
orig.events      = events;
orig.annotations = annotations;


classdef PTKDicomImage < PTKImage
    % PTKDicomImage. A class for holding a 3D medical image volume.
    %
    %     PTKDicomImage is inherited from the fundamental PTKImage image class
    %     used by the TD MIM Toolkit. It provides additional routines and
    %     metadata associated with medical imaging data, most commonly imported
    %     from the DICOM standard.
    %
    %     In general, you do not need to create PTKDicomImages using the
    %     constructor. You should import data using function such as
    %     MimLoadImageFromDicomFiles() which correctly set the metadata.
    %     Thereafter, use .Copy() to make copies of the image, and .BlankCopy()
    %     followed by .ChangeRawImage() to create derived images. See PTKImage.m
    %     for an example of creating functions which modify images contained in
    %     PTKImage classes.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (SetAccess = private)
        Modality
        RescaleSlope
        RescaleIntercept
        RescaleUnits = ''
        IsCT = false
        IsMR = false
        MetaHeader
        StudyUid
    end

    methods (Static)
        function new_dicom_image = CreateDicomImageFromMetadata(original_image, metadata, slice_thickness, global_origin_mm, padding_value, reporting)

            % Our voxel size should be equal to SpacingBetweenSlices. However,
            % some scanners incorrectly set SpacingBetweenSlices as the
            % gap between slices, instead of the centre-to-centre distance.
            % To ensure correct reconstruction interval, should really use
            % patient image Position tag (0020,0032)
            % http://www.itk.org/pipermail/insight-users/2005-September/014
            % 711.html
            voxelsize_z = slice_thickness;

            if ndims(original_image.RawImage) > 3
                reporting.ShowWarning('PTKDicomImage:ColourDicomImageNotSupported', 'Colour Dicom images are not supported. Converting to greyscale', []);
                original_image.RawImage = mean(original_image.RawImage, 4);
            end

            if isfield(metadata, 'PixelSpacing')
                voxel_size = [metadata.PixelSpacing' voxelsize_z];
            else
                reporting.ShowWarning('PTKDicomImage:NoPixelSpacing', 'Could not determine the pixel size from the image. I am assuming 1x1mm');
                voxel_size = [1 1 voxelsize_z];
            end

            if isfield(metadata, 'ImageOrientationPatient')
                [new_dimension_order, flip] = MimImageCoordinateUtilities.GetDimensionPermutationVectorFromDicomOrientation(metadata.ImageOrientationPatient, reporting);
                if isa(original_image, 'CoreWrapper')
                    original_image.RawImage = permute(original_image.RawImage, new_dimension_order);
                    for dimension_index = 1 : 3
                        if flip(dimension_index)
                            original_image.RawImage = flipdim(original_image.RawImage, dimension_index);
                        end
                    end
                else
                    original_image = permute(original_image, new_dimension_order);
                    for dimension_index = 1 : 3
                        if flip(dimension_index)
                            original_image = flipdim(original_image, dimension_index);
                        end
                    end
                end
                voxel_size = voxel_size(new_dimension_order);
            end
            if ~isempty(global_origin_mm)
                global_origin_mm = global_origin_mm([2 1 3]);
            end

            if isfield(metadata, 'RescaleSlope')
                rescale_slope = metadata.RescaleSlope;
            else
                rescale_slope = [];
            end

            if isfield(metadata, 'RescaleIntercept')
                rescale_intercept = metadata.RescaleIntercept;
            else
                rescale_intercept = [];
            end

            if isa(original_image, 'CoreWrapper')
                new_dicom_image = PTKDicomImage( ...
                    original_image.RawImage, rescale_slope, rescale_intercept, voxel_size, metadata.Modality, metadata.StudyInstanceUID, metadata ...
                    );
            else
                new_dicom_image = PTKDicomImage( ...
                    original_image, rescale_slope, rescale_intercept, voxel_size, metadata.Modality, metadata.StudyInstanceUID, metadata ...
                    );
            end
            patient_name = '';
            study_description = '';
            series_description = '';
            if isfield(metadata, 'PatientName')
                if isfield(metadata.PatientName, 'FamilyName')
                    patient_name = ['', metadata.PatientName.FamilyName, ' '];
                end
            end
            if isfield(metadata, 'StudyDescription')
                study_description = ['/ ', metadata.StudyDescription, ' '];
            end
            if isfield(metadata, 'SeriesDescription')
                series_description = ['/ ', metadata.SeriesDescription, ' '];
            end

            new_dicom_image.Title = [patient_name, study_description, series_description];
            new_dicom_image.GlobalOrigin = global_origin_mm;
            new_dicom_image.PaddingValue = padding_value;
        end
    end

    methods
        % The meta_data argument is optional, and is only used for saving DICOM
        % files. Other arguments are compulsory
        function obj = PTKDicomImage(original_image, rescale_slope, rescale_intercept, voxel_size, modality, study_uid, meta_data)

            obj = obj@PTKImage(original_image, PTKImageType.Grayscale, voxel_size);

            obj.StudyUid = study_uid;
            obj.Modality = modality;

            if exist('meta_data', 'var')
                obj.MetaHeader = meta_data;
            end

            if strcmp(modality, 'CT')
                obj.IsCT = true;
                obj.RescaleSlope = rescale_slope;
                obj.RescaleIntercept = rescale_intercept;
                obj.RescaleUnits = 'HU';
            elseif strcmp(modality, 'MR')
                obj.IsMR = true;
                obj.RescaleSlope = [];
                obj.RescaleIntercept = [];
            end
        end

        function [value, units] = GetRescaledValue(obj, global_coords)
            if obj.IsCT && CoreCompareUtilities.CompareEnumName(obj.ImageType, PTKImageType.Grayscale)
                value = obj.GreyscaleToHounsfield(obj.GetVoxel(global_coords));
                units = obj.RescaleUnits;
            else
                [value, units] = GetRescaledValue@PTKImage(obj, global_coords);
            end
        end

        function units_rescaled = GrayscaleToRescaled(obj, units_greyscale)
            if obj.IsCT
                units_rescaled = obj.GreyscaleToHounsfield(units_greyscale);
            else
                units_rescaled = units_greyscale;
            end
        end

        function units_greyscale = RescaledToGrayscale(obj, units_rescaled)
            if obj.IsCT
                units_greyscale = obj.HounsfieldToGreyscale(units_rescaled);
            else
                units_greyscale = units_rescaled;
            end
        end

        function units_greyscale = HounsfieldToGreyscale(obj, units_hu)
            % Conversion from Hounsfield units to image raw intensity values:
            if obj.IsCT
                if isempty(obj.RescaleIntercept) || isempty(obj.RescaleSlope)
                    units_greyscale = units_hu;
                else
                    units_greyscale = (units_hu - cast(obj.RescaleIntercept, 'like', units_hu)/cast(obj.RescaleSlope, 'like', units_hu));
                end
            else
               error('The HounsfieldToGreyscale() method was called, but this is not a CT image');
            end
        end

        function units_hu = GreyscaleToHounsfield(obj, units_greyscale)
            if isempty(obj.RescaleSlope) || isempty(obj.RescaleIntercept)
                units_hu = units_greyscale;
                return;
            end
            % Conversion from image raw intensity values to Hounsfield units:
            if obj.IsCT
                units_hu = int16(units_greyscale)*obj.RescaleSlope + obj.RescaleIntercept;
            else
               error('The HounsfieldToGreyscale() method was called, but this is not a CT image');
            end
        end

        function units_rescaled = RescaledToGreyscale(obj, units_rescaled)
            if obj.IsCT || obj.IsMR
                units_rescaled = obj.HounsfieldToGreyscale(units_rescaled);
            else
                error('The RescaledToGreyscale() method was called, but this is not a CT or MR image');
            end

        end

        function copy = Copy(obj)
            copy = PTKDicomImage(obj.RawImage, obj.RescaleSlope, obj.RescaleIntercept, obj.VoxelSize, obj.Modality, obj.StudyUid, obj.MetaHeader);
            metaclass = ?PTKDicomImage;
            property_list = metaclass.Properties;
            for i = 1 : length(property_list)
                property = property_list{i};
                if (~property.Dependent) && (~property.Constant)
                    copy.(property.Name) = obj.(property.Name);
                end
            end
        end

        function copy = BlankCopy(obj)
            copy = PTKDicomImage([], obj.RescaleSlope, obj.RescaleIntercept, obj.VoxelSize, obj.Modality, obj.StudyUid, obj.MetaHeader);
            metaclass = ?PTKDicomImage;
            property_list = metaclass.Properties;
            for i = 1 : length(property_list)
                property = property_list{i};
                if (~property.Dependent) && (~property.Constant) && (~strcmp(property.Name, 'RawImage'))
                    copy.(property.Name) = obj.(property.Name);
                end
            end
        end

        function is_equal = eq(obj, other)
            metaclass = ?PTKImage;
            property_list = metaclass.Properties;
            for i = 1 : length(property_list)
                property = property_list{i};
                if (~property.Dependent) && (~ismember(property.Name, obj.PropertiesToIgnoreOnComparison))
                    if ~isequal(other.(property.Name), obj.(property.Name))
                        is_equal = false;
                        return;
                    end
                end
            end
            is_equal = true;
        end
    end
end


function [bbci, data]= bbci_calibrate_NIRS(bbci, data)
%BBCI_CALIBRATE_NIRS - Calibrate for ERP-design with NIRS
%
%This function is called by bbci_calibrate
%(if BBCI.calibate.analyze_fcn is set to @bbci_calibrate_NIRS_ERP).
%Via BBCI.calibrate.settings, the details can be specified, se below.
%
%Synopsis:
% [BBCI, DATA]= bbci_calibrate_NIRS_ERP(BBCI, DATA)
%
%Arguments:
%  BBCI -  the field 'calibrate.settings' holds parameters specific to
%          calibrate CSP-based BCI processing.
%  DATA -  holds the calibration data
%
%Output:
%  BBCI - Updated BBCI structure in which all necessary fields for
%     online operation are set, see bbci_apply_structures.
%  DATA - As input but added some information of the analysis that might
%     be reused in a second run
%
%BBCI.calibrate.settings may include the following parameters:
%  visu_clab:   Clab used for visualization
%  lp:          butterworth lowpass filter frequency
%  derivative   use derivative (slope) of signal as feature
%  classes: [1x2 CELL of CHAR] Names of the two classes, which are to be
%     discriminated. For classes = 'auto', all pairs of available classes
%     are investigated, and the one with best xvalidation performance is
%     chosen. Default is 'auto'.   **** TO BE IMPLEMENTED ****
% Display options:
%  zscore:      (for display purposes) channels are normalized to zero mean
%               and unit variance
%  grid:        provide a string specifying the grid layout for grid_plot
%
% ------------
%  ival: [1x2 DOUBLE] interval on which CSP is performed, 'auto' means
%     automatic selection. Default is 'auto'.
%  band: [1x2 DOUBLE] frequency band on which CSP is performed, 'auto' means
%     automatic selection. Default is 'auto'.
%  clab: [CELL] Labels of the channels that are used for classification,
%     default {'*'}.
%  nPatters: [INT>0] number of CSP patterns which are considered from each
%     side of the eigenvalue spectrum. Note, that not neccessarily all of
%     these are used for classification, see settings.pattern.
%     Default is 3.
%  patterns: [1xN DOUBLE or 'auto'] vector specifying the indices of the
%     CSP filters that should be used for classification; 'auto' means
%     automatic selection. Default is 'auto'.
%  model: [CHAR or CELL] Classification model.
%     Default {'RLDAshrink', 'gamma',0, store_means',1, 'scaling',1}.
%  reject_artifacts:
%  reject_channels:
%  reject_artifacts_opts: cell array of options which are passed to
%     reject_varEventsAndChannels.
%  check_ival: interval which is checked for artifacts
%  do_laplace: do Laplace spatial filtering for automatic selection
%     of ival/band. If opt.do_laplace is set to 0, the default value of
%     will also be set to opt.visu_laplace 0 (but can be overwritten).
%  visu_laplace: do Laplace filtering for grid plots of Spectra/ERDs.
%     If visu_laplace is a string, it is passed to proc_laplace. This
%     can be used to use alternative geometries, like 'vertical'.
%  visu_band: Frequency range for which spectrum is shown.
%  visu_ival: Time interval for which ERD/ERS curves are shown.
%  grd: grid to be used in the grid plots of spectra and ERDs.
%
%Only the figures of the chosen class combination are visible, while the
%others are hidden. In order to make them visible, type
%>> set(cat(2, data.all_results.figure_handles), 'Visible','on')
%
%You might like to modify bbci.feature.ival after running this function.

calibrate = bbci.calibrate;
opt= calibrate.settings;
[opt, isdefault]= ...
    set_defaults(opt, ...
                 'classes', 'auto', ...
                 'clab', {'*'}, ...
                 'classifier','RLDAshrink',...
                 'ref_ival',[-2000 0], ...
                 'ival',[-2000,10000], ...
                 'nIvals', 5, ...
                 'signal','both', ...
                 'doLowpass', 1, ...
                 'derivative', 0, ...
                 'baseline',1, ...
                 'zscore',1, ...
                 'grid',[] , ...
                 'spectra', 1, ...
                 'plot',1 ...
                 );

opt_grid = {'scaleGroup' 'all'};
opt_tit = {'Fontsize' 10 'Fontweight' 'bold'};

%% Build dummy grid for grid_plot
clab = strhead(data.cnt.clab(1:end/2));
clab = {'scale',clab{:},'legend'};
ii=1;
grd = '';
for r=1:ceil(sqrt(numel(clab)-2)) % nr of rows
  for c=1:ceil(sqrt(numel(clab)-2))
    if ii<=numel(clab)
      grd = [grd clab{ii} ','];
    else
      grd = [grd '_,'];
    end
    ii=ii+1;
  end
  grd= [grd(1:end-1) '\n'];
end
grd = sprintf(grd);
mnt= mnt_setGrid(data.mnt, grd);

%% *** Preprocessing ***
if ~isempty(opt.clab)
  data.cnt= proc_selectChannels(data.cnt,opt.clab);
end

% LP filter data [IS IT POSSIBLE TO SET BBCI.SIGNAL AND DO THIS
% AUTOMATICALLY?]
if opt.doLowpass
  fprintf('Lowpass filtering signal\n')
  [filt_b,filt_a]=butter(3, opt.lp*2/data.cnt.fs,'low');
  data.cnt = proc_filtfilt(data.cnt,filt_b,filt_a);
end

% oxy = dat;
% oxy.x = oxy.x(:,1:end/2);
% oxy.clab = oxy.clab(:,1:end/2);
% deoxy = dat;
% deoxy.x = dat.x(:,end/2+1:end);
% deoxy.clab = deoxy.clab(:,end/2+1:end);

if opt.spectra
  % Spectra
  spec_band = [0.01 3];     % Frequency band for spectrum plot
  spec_win = kaiser(250,2);   % window for proc_spectrumspecoxy = proc_spectrum(oxy, spec_band,spec_win);
  spec = proc_spectrum(data.cnt, spec_band,spec_win);
end

% derivative feat?
if opt.derivative
   fprintf('Calculating derivative of NIRS signal\n')

   data.cnt.x=diff(data.cnt.x);
%    deoxy.x=diff(deoxy.x); %*data.cnt.fs;
%    oxy.x=diff(oxy.x);
end

%% Epoch data
data.cnt = cntToEpo(data.cnt,data.mrk,opt.ival);

% baseline
if opt.baseline
  fprintf('Performing baseline correction\n')
  data.cnt = proc_baseline(data.cnt,opt.ref_ival);
end

% oxy.clab = untex(oxy.clab);
% deoxy.clab = untex(deoxy.clab);
%
%% *** Neurophysiology ***
% Split in oxy/deoxy or WL1/WL2
% oxy = data.cnt;
% oxy.x = oxy.x(:,1:end/2,:);
% oxy.clab = oxy.clab(:,1:end/2);
% deoxy = data.cnt;
% deoxy.x = data.cnt.x(:,end/2+1:end,:);
% deoxy.clab = deoxy.clab(:,end/2+1:end);

opt_tit = {'Fontsize' 10 'Fontweight' 'bold'};

%% make plots
if opt.plot
    %% Power spectrum of CNT data
    if opt.spectra
      fig_set(2),clf
      subplot(2,1,1)
      plot(spec.t,spec.x(:,1:end/2)), title(strtail(spec.clab{1}),opt_tit{:})
      xlabel(sprintf('Frequency [%s]',spec.xUnit)),ylabel(sprintf('Power [%s]',spec.yUnit))
      subplot(2,1,2)
      plot(spec.t,spec.x(:,1:end/2)), title(strtail(spec.clab{1}),opt_tit{:})
      xlabel(sprintf('Frequency [%s]',spec.xUnit)),ylabel(sprintf('Power [%s]',spec.yUnit))
      annotation('textbox',[.01 .9 .1 .1 ],'String','Power spectra of CNT data ');
    end

    %% z-score normalization
    if opt.zscore
      fprintf('Calculating z-scores\n')
      m= mean(data.cnt.x,1);   % mean
      s= std(data.cnt.x,1);    % std
      len_x = length(data.cnt.x);
      data.cnt.x= (data.cnt.x - repmat(m,[len_x 1])) ./ repmat(s,[len_x 1]);
      clear m s
    end

    %% Grid plot -- signal
    fig_set(1),clf
    H = grid_plot(proc_selectChannels(data.cnt,1:numel(data.cnt.clab)/2), mnt, defopt_scalp_power,opt_grid{:});
    set(gcf,'Name',['Epoched signal ' strtail(data.cnt.clab{1})])
    % printFigure(['grid_oxy' saveapp], [36 20], opt_fig);

    fig_set(2),clf
    H = grid_plot(proc_selectChannels(data.cnt,(numel(data.cnt.clab)/2)+1:numel(data.cnt.clab)), mnt, defopt_scalp_power,opt_grid{:});
    set(gcf,'Name',['Epoched signal ' strtail(data.cnt.clab{end})])
    % printFigure(['grid_deoxy' saveapp], [36 20], opt_fig);

    %% R-Square plots
    dat_r = proc_r_square_signed(data.cnt,'multiclass_policy','pairwise');
    npairs = size(dat_r.y,1);
    nclab = numel(data.cnt.clab)/2;
    for ii=1:npairs
    for od=[1 2]   %oxy-deoxy
      figure
      imagesc(dat_r.x(:,(od-1)*nclab+1:od*nclab,ii)')
      title([dat_r.className{ii} ' ' strtail(dat_r.clab{od*nclab})],opt_tit{:})
      ylabel('Channel',opt_tit{:}),xlabel('Time',opt_tit{:})
      xt=  str2num(get(gca,'XTickLabel'));
    %   yt=  str2num(get(gca,'YTickLabel'));
      set(gca,'XTickLabel',dat_r.t(xt))
    %   set(gca,'YTickLabel',strhead(oxy_r.clab))
      colorbar
    end
    end
    clear dat_r

    %% Wavelets
    spec = proc_selectChannels(data.cnt,1:nclab);
    spec = proc_specgram(spec, [0.01 3]);

    % data.cnt = proc_selectChannels(data.cnt,1:nclab);
    % wave_band = [.01:.4:3];
    % for w=wave_band
    %   if w==wave_band(1)
    %     wave = proc_wavelets(data.cnt,w,'vectorize',1);
    %   else
    %     w1 = proc_wavelets(data.cnt,w,'vectorize',1);
    %   end
    % end
end
%% *** Classification ***
% BBCI.FEATURE selection
bbci.feature.fcn = {@proc_jumpingMeans};

% class combination
if isequal(opt.classes, 'auto'),
  class_combination= nchoosek(1:size(data.mrk.y,1), 2);
else
  class_combination= find(ismember(data.mrk_all.className, opt.classes,'legacy'));
  if length(class_combination) < length(opt.classes),
    error('Not all specified classes were found.');
  end
  if length(class_combination) ~= 2,
    error('This calibration is only for binary classification.');
  end
end

ival_cfy={};

for ci= 1:size(class_combination,1)

    fv=proc_selectClasses(data.cnt,class_combination(ci,:));
    fprintf('\nComparing classes %s vs %s.',fv.className{1},fv.className{2})

    % find the feature/time intervals
    fvr = proc_r_square_signed(fv);
    [ival_cfy{ci},nfo]= select_time_intervals(fvr,'nIvals',opt.nIvals,'clab_pick_peak', fv.clab,...
      'visualize',0,'intersample_timing',1);

    bbci.feature.param = { {ival_cfy{ci}} };
    % Get feature vector ans train classifier
    fv = bbci_calibrate_evalFeature(fv, bbci.feature);

    bbci.classifier.C= trainClassifier(fv, opt.classifier);

%     % Xvalidation
%     [loss, loss_std]= xvalidation(fv, opt.classifier, ...
%        'sample_fcn', {'divisions', [opt.nShuffles opt.nFolds]},'save_classifier',0);
%
%     mean_loss(ci)= loss;
%     std_loss(ci)= loss_std;

    cfy_fields= {'signal', 'feature', 'classifier', 'quit_condition'};
    bbci_all(ci)= struct_copyFields(bbci, cfy_fields);

    clear fv*
end

%% Choose best binary combination of classes
% Copy parameters into BBCI struct

nComb= size(class_combination,1);
if nComb > 1,
%   [dummy, bi]= min(mean_loss + 0.1*std_loss);
bi=2;
  bbci= struct_copyFields(bbci, bbci_all(bi), cfy_fields);
%     bbci.feature.param = { {ival_cfy{ci}} };
end

comb = class_combination(bi,:);
fprintf('Chosen (best) combination: classes %s vs %s.\n',data.cnt.className{comb(1)},data.cnt.className{comb(2)})
bbci.classifier.classes=data.cnt.className(comb);
%% Set the BBCI struct

% BBCI.SIGNAL preprocessing (really just for online data?)
% bbci.signal.clab = opt.clab;
bbci.signal.clab = data.cnt.clab;

% data.signal.clab = opt.clab;
bbci.signal.proc = {};
% if ~isempty(opt.clab)
%   bbci.signal.proc = {bbci.signal.proc{:} {@proc_selectChannels,opt.clab}};
% end
if opt.doLowpass
  bbci.signal.proc = {bbci.signal.proc{:} {@proc_filtfilt,filt_b,filt_a}};
end
if opt.derivative
  bbci.signal.proc = {bbci.signal.proc{:} {@diff}};
end

% SOMEWHERE: proc_baseline ?

% BBCI.FEATURE selection
bbci.feature.ival = opt.ival;


function events = in_events_bids(sFile, EventFile)
% IN_EVENTS_BIDS: Read a BIDS _events.tsv file (columns "onset", "duration", "trial_type").
%
% OUTPUT:
%    - events(i): array of structures with following fields (one structure per event type)
%        |- label   : Identifier of event #i
%        |- samples : Array of unique time indices for event #i in the corresponding raw file
%        |- times   : Array of unique time latencies (in seconds) for event #i in the corresponding raw file

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

% Read tsv file
% https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/05-task-events.html
% trial_type would be a subset of possible events that identify trial category.
% value can be numbers or strings identifying the event.
% Only 'onset' and 'duration' are required.
Markers = in_tsv(EventFile, {'onset', 'duration', 'trial_type', 'channel', 'value'}, 0);
if isempty(Markers) || isempty(Markers{1,1})
    events = [];
    return;
end
% Standardize empty/missing values to empty char.
Markers(cellfun(@(c) (isequal(c,'n/a') || isequal(c,'N/A') || isempty(c)), Markers(:))) = {''};
% If there is no trial_type and no value information: use the filename as the event name
if all(cellfun(@isempty, Markers(:,3)) & cellfun(@isempty, Markers(:,5)))
    [fPath, fbase, fExt] = bst_fileparts(EventFile);
    Markers(:,3) = repmat({fbase}, size(Markers(:,3)));
elseif all(cellfun(@isempty, Markers(:,3)))
    Markers(:,3) = Markers(:,5);
elseif ~all(cellfun(@isempty, Markers(:,5)))
    % Both columns contain data
    for iM = 1:size(Markers, 1)
        if isempty(Markers{iM,3})
            Markers{iM,3} = Markers{iM,5};
        elseif ~isempty(Markers{iM,5})
            % Merge
            Markers{iM,3} = [Markers{iM,3} '-' Markers{iM,5}];
        end
    end
end
% List of events from trial_type and/or value
uniqueEvt = unique(Markers(:,3)');

% Initialize returned structure
events = repmat(db_template('event'), [1, length(uniqueEvt)]);
% Create events list
for iEvt = 1:length(uniqueEvt)
    % Find all the occurrences of event #iEvt
    iMrk = find(strcmpi(Markers(:,3)', uniqueEvt{iEvt}));
    % Get event onsets and durations
    onsets = cellfun(@(c)sscanf(c,'%f',1), Markers(iMrk,1), 'UniformOutput', 0);
    durations = cellfun(@(c)sscanf(c,'%f',1), Markers(iMrk,2), 'UniformOutput', 0);
    channels = Markers(iMrk,4)';
    % Find and reject events with no latency
    iEmpty = find(cellfun(@isempty, onsets));
    if ~isempty(iEmpty)
        iMrk(iEmpty) = [];
        onsets(iEmpty) = [];
        durations(iEmpty) = [];
        channels(iEmpty) = [];
    end
    % Channel names
    for iOcc = 1:length(channels)
        if (isempty(channels{iOcc}) || strcmpi(channels{iOcc}, 'n/a'))
            channels{iOcc} = [];
        else
            channels{iOcc} = {channels{iOcc}};
        end
    end
    % Add event structure
    events(iEvt).label  = uniqueEvt{iEvt};
    events(iEvt).epochs = ones(1, length(iMrk));
    events(iEvt).times  = [onsets{:}];
    % Convert latencies from the first sample in the file to the real timing
    % See specs: https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/05-task-events.html
    events(iEvt).times = events(iEvt).times + sFile.prop.times(1);
    % Extended events if durations are defined for all the markers
    if all(~cellfun(@isempty, durations)) && all(~cellfun(@(c)isequal(c,0), durations))
        events(iEvt).times(2,:) = events(iEvt).times + [durations{:}];
    end
    % Make the function independent of sFile
    if ~isempty(sFile)
        events(iEvt).times  = round(events(iEvt).times .* sFile.prop.sfreq) ./ sFile.prop.sfreq;
    end
    events(iEvt).reactTimes = [];
    events(iEvt).select     = 1;
    events(iEvt).channels   = channels;
    events(iEvt).notes      = [];
end


function view_varmap(lab1,valueMap, newgri, sor)
    % view_maxz plots the maxz LTA values calculated
    % with maxzlta.m or other similar values as a color map
    % needs valueMap, gx, gy, stri
    %
    % define size of the plot etc.
    %
    ZG=ZmapGlobal.Data;
    % Prmap = nan(size(valueMap));

    % Find out if figure already exists
    %
    bmap=findobj('Type','Figure','-and','Name','variance-value-map');

    % Set up the Seismicity Map window Enviroment
    %
    if isempty(bmap)
        bmap = figure_w_normalized_uicontrolunits( ...
            'Name','variance-value-map',...
            'NumberTitle','off', ...
            'NextPlot','new', ...
            'backingstore','on',...
            'Visible','off', ...
            'Position',position_in_current_monitor(ZG.map_len(1), ZG.map_len(2)));

        lab1 = 'b-value:';

        create_my_menu();

        re4 = valueMap;

        colormap(jet)
        ZG.tresh_km = nan;
        minpe = nan;
        Mmin = nan;

    end   % This is the end of the figure setup

    % Now lets plot the color-map of the z-value
    %
    figure(bmap);
    delete(findobj(bmap,'Type','axes'));
    % delete(sizmap);
    ax = reset(gca);
    cla(ax)
    set(ax,'NextPlot','replace')
    watchon;
    set(ax,'visible','off',...
        'FontSize',ZmapGlobal.Data.fontsz.s,...
        'FontWeight','normal',...
        'LineWidth',1,...
        'Box','on','SortMethod','childorder')

    % find max and min of data for automatic scaling
    ZG.maxc = fix(max(valueMap(:))+1);
    ZG.minc = fix(min(valueMap(:)))-1;

    % set values gretaer ZG.tresh_km = nan
    %
    re4 = valueMap;

    % plot image
    %
    orient(ax,'landscape')

    ax.Position = [0.12,  0.10, 0.8, 0.8];
    set(gca,'NextPlot','add')
    pcolor(ax, gx,gy,re4);

    axis(ax, [min(gx) max(gx) min(gy) max(gy)])
    axis(ax,'image')
    set(gca,'NextPlot','add')

    shading(ax, ZG.shading_style);

    % make the scaling for the recurrence time map reasonable

    fix_caxis.ApplyIfFrozen(ax);

    title(ax, sprintf('%s ;  %g to %g',name, t0b, teb),...
        'FontSize',ZmapGlobal.Data.fontsz.s,...
        'Color','k',...
        'FontWeight','normal')

    xlabel(ax, 'Longitude [deg]','FontWeight','normal','FontSize',ZmapGlobal.Data.fontsz.s)
    ylabel(ax, 'Latitude [deg]','FontWeight','normal','FontSize',ZmapGlobal.Data.fontsz.s)

    % plot overlay
    %
    set(ax,'NextPlot','add')
    zmap_update_displays();

    set(ax,'NextPlot','add')
    quiver(ax, newgri(:,1),newgri(:,2), -cos(sor(:,SA*2)*pi/180), sin(sor(:,SA*2)*pi/180),0.8,'.', ...
        'LineWidth',1, 'Color','k')

    set(ax,'visible','on','FontSize',ZmapGlobal.Data.fontsz.s,...
        'FontWeight','normal',...
        'LineWidth',1,...
        'Box','on',...
        'TickDir','out');

    h1 = ax;
    hzma = ax;

    % Create a colorbar
    %
    h5 = colorbar('horiz');
    set(h5,'Pos',[0.35 0.06 0.4 0.02],...
        'FontWeight','normal',...
        'FontSize',ZmapGlobal.Data.fontsz.s,...
        'TickDir','out')

    axes('position', [0.00,  0.0, 1 1])
    axis('off')
    %  Text Object Creation
    text(...
        'Units','normalized',...
        'Position',[ 0.33 0.06 0 ],...
        'HorizontalAlignment','right',...
        'FontSize',ZmapGlobal.Data.fontsz.s,....
        'FontWeight','normal',...
        'String','Variance');

    % Make the figure visible
    %
    set(gca,'FontSize',ZmapGlobal.Data.fontsz.s,...
        'FontWeight','normal','LineWidth',1,...
        'Box','on','TickDir','out');
    set(gcf,'color','w');
    figure(bmap);
    axes(h1)
    watchoff(bmap)

    %% ui functions
    function create_my_menu()
        add_menu_divider();

        options = uimenu('Label',' Select ');
        uimenu(options,'Label','Refresh ','MenuSelectedFcn',@cb_refresh)
        uimenu(options,'Label','Select EQ in Circle',...
            'MenuSelectedFcn',@select_in_circle)
        uimenu(options,'Label','Select EQ in Circle - Constant R',...
            'MenuSelectedFcn',@cb_select_in_constr)

        uimenu(options,'Label','Select EQ in Polygon -new ',...
            'MenuSelectedFcn',@cb_select_in_polygon_new)

        op1 = uimenu('Label',' Maps ');

        uimenu(op1,'Label','Variance map',...
            'MenuSelectedFcn',@cb_variancemap)
        uimenu(op1,'Label','Resolution map',...
            'MenuSelectedFcn',@cb_resolutionmap)
        uimenu(op1,'Label','Plot map on top of topography ',...
            'MenuSelectedFcn',@cb_plot_on_topography)

        uimenu(op1,'Label','Histogram ','MenuSelectedFcn',@(~,~)zhist())

        add_display_menu(1)
    end

    %% callback functions

    function cb_refresh(~,~)
        view_varmap(lab1, re4);
    end

    function select_in_circle(~,~)
        h1 = gca;
        met = 'ni';
        ZG=ZmapGlobal.Data;
        ZG.hold_state=false;
        circle;
        watchon;
        doinvers_michael;
        watchoff;
    end

    function cb_select_in_constr(~,~)
        h1 = gca;
        met = 'ra';
        ZG=ZmapGlobal.Data;
        ZG.hold_state=false;
        circle;
        watchon;
        doinvers_michael;
        watchoff;
    end

    function cb_select_in_polygon_new(~,~)
        cufi = gcf;
        ZG=ZmapGlobal.Data;
        ZG.hold_state=false;
        selectp;
        watchon;
        doinvers_michael;
        watchoff;
    end

    function cb_variancemap(~,~)
        view_varmap('b-value',r);
    end

    function cb_resolutionmap(~,~)
        view_varmap('Radius', rama);
    end

    function cb_plot_on_topography(~,~)
        dramap_z('stress2','w',valueMap);
    end

end


%%% test the model performance

% clear; clc;
format compact;

addpath(fullfile('data','utilities'));
% folderTest  = fullfile('data','Test','Set12'); %%% test dataset
folderTest  = fullfile('data','Test','Set68'); %%% test dataset

showResult  = 1;
useGPU      = 1;
pauseTime   = 0;

modelName   = 'model_64_25_Res_Bnorm_Adam';
epoch       = 1;
noiseSigma  = 25;  %%% image noise level

%%% load Gaussian denoising model
load(fullfile('data',modelName,[modelName,'-epoch-',num2str(epoch),'.mat']));
net = vl_simplenn_tidy(net);
net.layers = net.layers(1:end-1);

%%%
net = vl_simplenn_tidy(net);

% for i = 1:size(net.layers,2)
%     net.layers{i}.precious = 1;
% end

%%% move to gpu
if useGPU
    net = vl_simplenn_move(net, 'gpu') ;
end

%%% read images
ext         =  {'*.jpg','*.png','*.bmp'};
filePaths   =  [];
for i = 1 : length(ext)
    filePaths = cat(1,filePaths, dir(fullfile(folderTest,ext{i})));
end

%%% PSNR and SSIM
PSNRs = zeros(1,length(filePaths));
SSIMs = zeros(1,length(filePaths));

for i = 1:length(filePaths)

    %%% read images
    label = imread(fullfile(folderTest,filePaths(i).name));
    [~,nameCur,extCur] = fileparts(filePaths(i).name);
    label = im2double(label);

    randn('seed',0);
    input = single(label + noiseSigma/255*randn(size(label)));

    %%% convert to GPU
    if useGPU
        input = gpuArray(input);
    end

    res    = vl_simplenn(net,input,[],[],'conserveMemory',true,'mode','test');
    output = input - res(end).x;

    %%% convert to CPU
    if useGPU
        output = gather(output);
        input  = gather(input);
    end

    %%% calculate PSNR and SSIM
    [PSNRCur, SSIMCur] = Cal_PSNRSSIM(im2uint8(label),im2uint8(output),0,0);
    if showResult
        imshow(cat(2,im2uint8(label),im2uint8(input),im2uint8(output)));
        title([filePaths(i).name,'    ',num2str(PSNRCur,'%2.2f'),'dB','    ',num2str(SSIMCur,'%2.4f')])
        drawnow;
        pause(pauseTime)
    end
    PSNRs(i) = PSNRCur;
    SSIMs(i) = SSIMCur;
end

disp([mean(PSNRs),mean(SSIMs)]);


function [ir,x0,delay] = ir_nfchoa(X,head_orientation,xs,src,sofa,conf)
%IR_NFCHOA binaural simulation of NFCHOA
%
%   Usage: [ir,x0,delay] = ir_nfchoa(X,head_orientation,xs,src,sofa,conf)
%
%   Input parameters:
%       X                - listener position / m
%       head_orientation - orientation of the listener with [phi theta] /
%                          (rad, rad)
%       xs               - virtual source position / m
%       src              - source type: 'pw' -plane wave
%                                       'ps' - point source
%       sofa             - impulse response data set for the secondary sources
%       conf             - configuration struct (see SFS_config)
%
%   Output parameters:
%       ir               - impulse response for the desired HOA synthesis
%                          (nx2 matrix)
%       x0               - secondary sources
%       delay            - delay added by driving function / s
%
%   IR_NFCHOA(X,head_orientation,xs,src,L,sofa,conf) calculates a binaural room
%   impulse response for a virtual source at xs for a virtual NFCHOA array and
%   a listener located at X.
%
%   See also: ssr_brs_nfchoa, ir_nfchoa, ir_point_source, auralize_ir

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ==================================
nargmin = 6;
nargmax = 6;
narginchk(nargmin,nargmax);
if conf.debug
    isargposition(X);
    isargxs(xs);
    isargvector(head_orientation);
    isargpositivescalar(L);
    isargchar(src);
    isargstruct(config);
end

%% ===== Variables ======================================================
% Loudspeaker positions
x0 = secondary_source_positions(conf);

%% ===== BRIR ===========================================================
% Calculate driving function
[d,~,delay] = driving_function_imp_nfchoa(x0,xs,src,conf);
% Generate the impulse response for NFCHOA
ir = ir_generic(X,head_orientation,x0,d,sofa,conf);