function D = spm_eeg_prep(S)
% Prepare converted M/EEG data for further analysis
% FORMAT D = spm_eeg_prep(S)
% S                 - configuration structure (optional)
% (optional) fields of S:
%   S.D             - MEEG object or filename of M/EEG mat-file
%   S.task          - action string. One of 'settype', 'defaulttype',
%                     'loadtemplate','setcoor2d', 'project3d', 'loadeegsens',
%                     'defaulteegsens', 'sens2chan', 'headshape',
%                     'coregister', 'sortconditions'
%
%   S.updatehistory - update history information [default: true]
%   S.save          - save MEEG object [default: false]
%
% D                 - MEEG object
%__________________________________________________________________________
% Copyright (C) 2008-2019 Wellcome Trust Centre for Neuroimaging

% Vladimir Litvak
% $Id: spm_eeg_prep.m 7586 2019-05-03 14:57:34Z guillaume $

D = spm_eeg_load(S.D);

switch lower(S.task)
    %----------------------------------------------------------------------
    case 'setbadchan'
        %----------------------------------------------------------------------
        D = badchannels(D, D.selectchannels(S.channels), S.status);
        %----------------------------------------------------------------------
    case 'settype'
        %----------------------------------------------------------------------
        D = chantype(D, S.ind, S.type);

        %----------------------------------------------------------------------
    case 'defaulttype'
        %----------------------------------------------------------------------
        if isfield(S, 'ind')
            ind = S.ind;
        else
            ind = 1:D.nchannels;
        end

        dictionary = {
            'eog',           'EOG';
            'eeg',           'EEG';
            'ecg',           'ECG';
            'lfp',           'LFP';
            'emg',           'EMG';
            'meg',           'MEG';
            'ref',           'REF';
            'megref'         'REF';
            'megmag',        'MEGMAG';
            'megplanar',     'MEGPLANAR';
            'meggrad',       'MEGGRAD';
            'refmag',        'REFMAG';
            'refgrad',       'REFGRAD'
            'refplanar'      'REFPLANAR'
            };

        D = chantype(D, ind, 'Other');

        type = ft_chantype(D.chanlabels);

        % If there is useful information in the original types it
        % overwrites the default assignment
        if isfield(D, 'origchantypes')
            [sel1, sel2] = spm_match_str(chanlabels(D, ind), D.origchantypes.label);

            type(ind(sel1)) = D.origchantypes.type(sel2);
        end

        spmtype = repmat({'Other'}, 1, length(ind));

        [sel1, sel2] = spm_match_str(type(ind), dictionary(:, 1));

        spmtype(sel1) = dictionary(sel2, 2);

        D = chantype(D, ind, spmtype);

        %----------------------------------------------------------------------

    case 'bidschantype'

        dictionary = { % Should be updates with updates to BIDS specification
            'MEGMAG'   'MEGMAG'
            'MEGGRAD'  'MEGPLANAR'
            'MEG'      'MEG'
            'MEGREF'   'REF'
            'EEG'      'EEG'
            'EOG'      'EOG'
            'ECG'      'ECG'
            'EMG'      'EMG'
            'TRIG'     'Other'
            'AUDIO'    'Other'
            'PD'       'Other'
            'ET'       'Other'
            'MISC'     'Other'
            };

        bids_chan = spm_load(S.filename);

        [sel1, sel2] = spm_match_str(D.chanlabels, bids_chan.name);

        type = bids_chan.type(sel2);

        [sel3, sel4] = spm_match_str(type, dictionary(:, 1));

        type(sel3) = dictionary(sel4, 2);

        D = chantype(D, sel1, type);

    case 'bidschanstatus'
        bids_chan = spm_load(S.filename);

        [sel1, sel2] = spm_match_str(D.chanlabels, bids_chan.name);

        sel3 = strmatch('bad', bids_chan.status(sel2));

        D = badchannels(D, sel1, 0);

        D = badchannels(D, sel1(sel3), 1);

    case {'loadtemplate', 'setcoor2d', 'project3d'}
        %----------------------------------------------------------------------
        chanind = 1:D.nchannels;

        switch lower(S.task)
            case 'loadtemplate'
                template    = load(S.P); % must contain Cpos, Cnames
                xy          = template.Cpos;
                label       = template.Cnames;
            case 'setcoor2d'
                xy          = S.xy;
                label       = S.label;
            case 'project3d'
                if ~isfield(D, 'val')
                    D.val = 1;
                end
                if isfield(D, 'inv') && isfield(D.inv{D.val}, 'datareg')
                    datareg = D.inv{D.val}.datareg;
                    ind     = strmatch(S.modality, {datareg(:).modality}, 'exact');
                    sens    = datareg(ind).sensors;
                else
                    sens    = D.sensors(S.modality);
                end
                [xy, label] = spm_eeg_project3D(sens, S.modality);

                switch S.modality
                    case 'EEG'
                        chanind  = D.indchantype('EEG');
                    case 'MEG'
                        chanind  = D.indchantype('MEGANY');
                    case 'MEGCOMB'
                        chanind  = D.indchantype('MEGCOMB');
                end
        end

        megcombind   = D.indchantype('MEGCOMB');

        if ~isempty(megcombind)
            chanset = spm_eeg_planarchannelset(D.chanlabels);
            [sel1, sel2] = spm_match_str(lower(chanset(:, 1)), lower(label));
            [sel3, sel4] = spm_match_str(lower(chanset(:, 2)), lower(label));

            [sel5, sel6, sel7] = intersect(sel1, sel3);

            label = [label(:); chanset(sel5, 3)];

            xy    = [xy 0.5*(xy(:, sel2(sel6)) + xy(:, sel4(sel7)))];
        end

        [sel1, sel2] = spm_match_str(lower(D.chanlabels(chanind)), lower(label));
        sel1         = chanind(sel1);

        if ~isempty(sel1)

            megind = D.indchantype('MEG');
            eegind = D.indchantype('EEG');

            if ~isempty(intersect(megind, sel1)) && ~isempty(setdiff(megind, sel1))
                error('2D locations not found for all MEG channels');
            end

            if ~isempty(intersect(megcombind, sel1)) && ~isempty(setdiff(megcombind, sel1))
                error('2D locations not found for all MEGCOMB channels');
            end

            if ~isempty(intersect(eegind, sel1)) && ~isempty(setdiff(eegind, sel1))
                warning(['2D locations not found for all EEG channels, changing type of channels', ...
                    num2str(setdiff(eegind, sel1)) ' to ''Other''']);

                D = chantype(D, setdiff(eegind, sel1), 'Other');
            end

            D = coor2D(D, sel1, num2cell(xy(:, sel2)));
        end

        %----------------------------------------------------------------------
    case 'loadeegsens'
        %----------------------------------------------------------------------
        switch S.source
            case 'mat'
                senspos = load(S.sensfile);
                name    = fieldnames(senspos);
                senspos = getfield(senspos,name{1});

                label = chanlabels(D, D.indchantype('EEG'));

                if size(senspos, 1) ~= length(label)
                    error('To read sensor positions without labels the numbers of sensors and EEG channels should match.');
                end

                elec = [];
                elec.chanpos = senspos;
                elec.elecpos = senspos;
                elec.label = label;

                headshape = load(S.headshapefile);
                name    = fieldnames(headshape);
                headshape = getfield(headshape,name{1});

                shape = [];

                fidnum = 0;
                while ~all(isspace(S.fidlabel))
                    fidnum = fidnum+1;
                    [shape.fid.label{fidnum},S.fidlabel] = strtok(S.fidlabel);
                end

                if (fidnum < 3)  || (size(headshape, 1) < fidnum)
                    error('At least 3 labeled fiducials are necessary');
                end

                shape.fid.pnt = headshape(1:fidnum, :);

                if size(headshape, 1) > fidnum
                    shape.pnt = headshape((fidnum+1):end, :);
                else
                    shape.pnt = [];
                end
            case 'locfile'
                label = chanlabels(D, D.indchantype('EEG'));

                elec = ft_read_sens(S.sensfile);

                % Remove headshape points
                hspind = strmatch('headshape', elec.label);
                elec.chanpos(hspind, :) = [];
                elec.elecpos(hspind, :) = [];
                elec.chantype(hspind, :) = [];
                elec.chanunit(hspind, :) = [];
                elec.label(hspind)  = [];

                % This handles FIL Polhemus case and other possible cases
                % when no proper labels are available.
                if isempty(intersect(label, elec.label))
                    ind = str2num(strvcat(elec.label));
                    if length(ind) == length(label)
                        elec.label = label(ind);
                    else
                        error('To read sensor positions without labels the numbers of sensors and EEG channels should match.');
                    end
                end

                shape = spm_eeg_fixpnt(ft_read_headshape(S.sensfile));

                % In case electrode file is used for fiducials, the
                % electrodes can be used as headshape
                if ~isfield(shape, 'pnt') || isempty(shape.pnt) && ...
                        size(shape.fid.pnt, 1) > 3
                    shape.pnt = shape.fid.pnt;
                end

        end

        elec = ft_convert_units(elec, 'mm');
        shape= ft_convert_units(shape, 'mm');

        if isequal(D.modality(1, 0), 'Multimodal')
            if ~isempty(D.fiducials) && isfield(S, 'regfid') && ~isempty(S.regfid)
                M1 = coreg(D.fiducials, shape, S.regfid);
                elec = ft_transform_geometry(M1, elec);
            else
                error(['MEG fiducials matched to EEG fiducials are required '...
                    'to add EEG sensors to a multimodal dataset.']);
            end
        else
            D = fiducials(D, shape);
        end

        D = sensors(D, 'EEG', elec);

        %----------------------------------------------------------------------
    case 'defaulteegsens'
        %----------------------------------------------------------------------

        template_sfp = dir(fullfile(spm('dir'), 'EEGtemplates', '*.sfp'));
        template_sfp = {template_sfp.name};

        if ft_senstype(D.chanlabels(D.indchantype('EEG')), 'ext1020')
            ind = strmatch('ext1020.sfp', template_sfp, 'exact');
        else
            ind = strmatch([ft_senstype(D.chanlabels(D.indchantype('EEG'))) '.sfp'], template_sfp, 'exact');
        end

        if ~isempty(ind)
            fid = D.fiducials;

            if isequal(D.modality(1, 0), 'Multimodal') && ~isempty(fid)

                nzlbl = {'fidnz', 'nz', 'nas', 'nasion', 'spmnas'};
                lelbl = {'fidle', 'fidt9', 'lpa', 'lear', 'earl', 'le', 'l', 't9', 'spmlpa'};
                relbl = {'fidre', 'fidt10', 'rpa', 'rear', 'earr', 're', 'r', 't10', 'spmrpa'};

                [sel1, nzind] = spm_match_str(nzlbl, lower(fid.fid.label));
                if ~isempty(nzind)
                    nzind = nzind(1);
                end
                [sel1, leind] = spm_match_str(lelbl, lower(fid.fid.label));
                if ~isempty(leind)
                    leind = leind(1);
                end
                [sel1, reind] = spm_match_str(relbl, lower(fid.fid.label));
                if ~isempty(reind)
                    reind = reind(1);
                end

                regfid = fid.fid.label([nzind, leind, reind]);
                if numel(regfid) < 3
                    error('Could not automatically understand the MEG fiducial labels. Please use the GUI.');
                else
                    regfid = [regfid(:) {'spmnas'; 'spmlpa'; 'spmrpa'}];
                end

                S1 = [];
                S1.D = D;
                S1.task = 'loadeegsens';
                S1.source = 'locfile';
                S1.regfid = regfid;
                S1.sensfile = fullfile(spm('dir'), 'EEGtemplates', template_sfp{ind});
                S1.updatehistory = 0;
                D = spm_eeg_prep(S1);
            else
                elec = ft_read_sens(fullfile(spm('dir'), 'EEGtemplates', template_sfp{ind}));

                [sel1, sel2] = spm_match_str(lower(D.chanlabels), lower(elec.label));

                sens = elec;
                sens.chanpos  = sens.chanpos(sel2, :);
                sens.elecpos  = sens.elecpos(sel2, :);
                sens.chantype = sens.chantype(sel2, :);
                sens.chanunit = sens.chanunit(sel2, :);

                % This takes care of possible case mismatch
                sens.label = D.chanlabels(sel1);

                sens.label = sens.label(:);

                D = sensors(D, 'EEG', sens);

                % Assumes that the first 3 points in standard location files
                % are the 3 fiducials (nas, lpa, rpa)
                fid = [];
                fid.pnt = elec.elecpos;
                fid.fid.pnt = elec.elecpos(1:3, :);
                fid.fid.label = elec.label(1:3);

                [xy, label] = spm_eeg_project3D(D.sensors('EEG'), 'EEG');

                [sel1, sel2] = spm_match_str(lower(D.chanlabels), lower(label));

                if ~isempty(sel1)

                    eegind = strmatch('EEG', chantype(D), 'exact');

                    if ~isempty(intersect(eegind, sel1)) && ~isempty(setdiff(eegind, sel1))
                        warning(['2D locations not found for all EEG channels, changing type of channels ', ...
                            num2str(setdiff(eegind(:)', sel1(:)')) ' to ''Other''']);

                        D = chantype(D, setdiff(eegind, sel1), 'Other');
                    end

                    if any(any(coor2D(D, sel1) - xy(:, sel2)))
                        D = coor2D(D, sel1, num2cell(xy(:, sel2)));
                    end
                end

                if strcmp(D.modality(1, 0), 'Multimodal') && ~isempty(D.fiducials)...
                        && isfield(S, 'regfid') && ~isempty(S.regfid)
                    M1 = coreg(D.fiducials, fid, S.regfid);
                    D = sensors(D, 'EEG', ft_transform_geometry(M1, D.sensors('EEG')));
                else
                    D = fiducials(D, fid);
                end
            end
        end

        %----------------------------------------------------------------------
    case 'loadmegsens'
        %----------------------------------------------------------------------
        hdr  = ft_read_header(S.source);
        D = sensors(D, 'MEG', hdr.grad);
        D = fiducials(D, ft_convert_units(ft_read_headshape(S.source), 'mm'));

        if ~isempty(D.indchantype('MEG')) && ~isempty(D.sensors('MEG'))

            S1 = [];
            S1.task = 'project3D';
            S1.modality = 'MEG';
            S1.updatehistory = 0;
            S1.D = D;

            D = spm_eeg_prep(S1);
        end

        %----------------------------------------------------------------------
    case 'sens2chan'
        %----------------------------------------------------------------------
        if isfield(S, 'montage')
            montage = S.montage;
            if ischar(montage)
                montage = getfield(load(montage), 'montage');
            end
        elseif isfield(S, 'refelec');
            sens = sensors(D, 'EEG');
            if isempty(sens)
                error('The montage cannod be applied - no EEG sensors specified');
            end
            if ismember('all', S.refelec)
                refind = 1:numel(sens.label);
            else
                refind = spm_match_str(sens.label, S.refelec);
            end

            tra            = eye(numel(sens.label));
            tra(:, refind) = tra(:, refind) - 1/length(refind);

            montage.tra = tra;
            montage.labelorg = sens.label;
            montage.labelnew = sens.label;
        else
            error('Montage or list of reference sensors should be specified');
        end

        modalities = {'EEG', 'MEG'};
        for m = 1:numel(modalities)
            sens = sensors(D, modalities{m});
            if ~isempty(sens) && ~isempty(intersect(sens.label, montage.labelorg))
                sens = sensors(D, 'EEG');
                sens = ft_apply_montage(sens, montage, 'keepunused', 'no');
                D = sensors(D, modalities{m}, sens);
            end
        end

        %----------------------------------------------------------------------
    case 'headshape'
        %----------------------------------------------------------------------
        switch S.source
            case 'mat'
                headshape = load(S.headshapefile);
                name    = fieldnames(headshape);
                headshape = getfield(headshape,name{1});

                shape = [];

                fidnum = 0;
                while ~all(isspace(S.fidlabel))
                    fidnum = fidnum+1;
                    [shape.fid.label{fidnum},S.fidlabel] = strtok(S.fidlabel);
                end

                if (fidnum < 3)  || (size(headshape, 1) < fidnum)
                    error('At least 3 labeled fiducials are necessary');
                end

                shape.fid.pnt = headshape(1:fidnum, :);

                if size(headshape, 1) > fidnum
                    shape.pnt = headshape((fidnum+1):end, :);
                else
                    shape.pnt = [];
                end
            otherwise
                shape = spm_eeg_fixpnt(ft_read_headshape(S.headshapefile));

                % In case electrode file is used for fiducials, the
                % electrodes can be used as headshape
                if ~isfield(shape, 'pnt') || isempty(shape.pnt) && ...
                        size(shape.fid.pnt, 1) > 3
                    shape.pnt = shape.fid.pnt;
                end
        end

        shape = ft_convert_units(shape, 'mm');

        fid = D.fiducials;

        if ~isempty(fid) && isfield(S, 'regfid') && ~isempty(S.regfid)
            M1 = coreg(fid, shape, S.regfid);
            shape = ft_transform_geometry(M1, shape);
        end

        D = fiducials(D, shape);
        %----------------------------------------------------------------------
    case 'coregister'
        %----------------------------------------------------------------------
        [D, ok] = check(D, '3d');

        if ~ok
            error('Coregistration cannot be performed due to missing data');
        end

        try
            val = D.val;
            Msize = D.inv{val}.mesh.Msize;
        catch
            val = 1;
            Msize = 1;
        end

        D = spm_eeg_inv_mesh_ui(D, val, 1, Msize);
        D = spm_eeg_inv_datareg_ui(D, val);

    case 'sortconditions'
        if ischar(S.condlist)
            cl = getfield(load(S.condlist), 'condlist');
        else
            cl = S.condlist;
        end

        D = condlist(D, cl);
        %----------------------------------------------------------------------
    case 'loadbidsevents'
        if ~isequal(D.type, 'continuous')
            error('This operation can only be applied to continuous datasets');
        end

        ev_bids = spm_load(S.filename);

        if isfield(ev_bids,'trial_type')
            trial_type = 'trial_type';
        else
            % Compatibility with old BIDS-formatted datasets
            trial_type = 'stim_type';
        end
        ev_spm = struct(...
            'type',     repmat({'BIDS'}, length(ev_bids.onset), 1),...
            'value',    ev_bids.(trial_type),...
            'time',     num2cell(ev_bids.onset),...
            'duration', num2cell(ev_bids.duration));

        if S.replace
            D = events(D, 1, ev_spm);
        else
            D = events(D, 1, spm_cat_struct(D.events(1), ev_spm));
        end

        D = D.check;

    otherwise
        %----------------------------------------------------------------------
        fprintf('Unknown task ''%s'' to perform: Nothing done.\n',S.task);
end

% When prep is called from other functions with history, history should be
% disabled
if ~isfield(S, 'updatehistory') || S.updatehistory
    Stemp = S;
    Stemp.D = fullfile(D.path,D.fname);
    Stemp.save = 1;
    D = D.history('spm_eeg_prep', Stemp);
end

if isfield(S, 'save') && S.save
    save(D);
end

%==========================================================================
% function coreg
%==========================================================================
function M1 = coreg(fid, shape, regfid)
[junk, sel1] = spm_match_str(regfid(:, 1), fid.fid.label);
[junk, sel2] = spm_match_str(regfid(:, 2), shape.fid.label);

S = [];
S.targetfid = fid;
S.targetfid.fid.pnt = S.targetfid.fid.pnt(sel1, :);

S.sourcefid = shape;
S.sourcefid.fid.pnt = S.sourcefid.fid.pnt(sel2, :);
S.sourcefid.fid.label = S.sourcefid.fid.label(sel2);

S.targetfid.fid.label = S.sourcefid.fid.label;

S.template = 1;
S.useheadshape = 0;

M1 = spm_eeg_inv_datareg(S);


function my_imshow(img_data)

try
    imshow(img_data);
catch err_info
    disp('image cannot display!');
end

end


function GE_dumpHeader(IFileName, OutFile)
%
% GE_dumpHeader(IFileName,OutFile)
% Dumps much of the header from a GE lx2 or 5.X file to
% OutFile.  If OutFile is not specified, the output goes
% to stdout.
%
% Souheil J. Inati, PhD
% Dartmouth College
% May 2000
% souheil.inati@dartmouth.edu
%

%%%% Call GE_readHeader %%%%
[su_hdr,ex_hdr,se_hdr,im_hdr,pix_hdr] = GE_readHeader(IFileName);

% Open the output file
if nargin == 2
  outid = fopen(OutFile,'w');
else
  outid = 1;  % stdout
end

%%%% Exam Header %%%%
fprintf(outid,'Exam Header Section:\n');
fprintf(outid,GE_dumpExamHeader(ex_hdr));
fprintf(outid,'\n\n');

%%%% Series Header %%%%
fprintf(outid,'Series Header Section:\n');
fprintf(outid,GE_dumpSeriesHeader(se_hdr));
fprintf(outid,'\n\n');

%%%% Image Header %%%%
fprintf(outid,'Image Header Section:\n');
fprintf(outid,GE_dumpImageHeader(im_hdr));

% Close the File if not stdout
if outid ~= 1
  fclose(outid);
end

return


function volume = checkSelectedVolume
% volume = checkSelectedVolume;
%
% checks for a selected volume view. If one exists, returns it;
% otherwise, initializes an empty volume view.
mrGlobals;
volume = getSelectedVolume;
if isempty(volume)
    % open a hidden view, but warn that you're doing this
    warning('No  VOLUME view found. Initializing a hidden volume view.')
    inplane = initHiddenVolume;
end
return


% The COBRAToolbox: testReactionEq.m
%
% Purpose:
%     - testReactionEq tests the functionality of ReactionEq in the
%     rBioNet extension
%
% Authors:
%     - Stefania Magnusdottir April 2017
%

% save the current path
currentDir = pwd;

% initialize the test
fileDir = fileparts(which('testReactionEq'));
cd(fileDir);

% load the reaction database
load([fileDir, filesep 'rxn.mat'])

% check match for made up reaction
matched = ReactionEq('etoh[e] + 2pg[c] -> atp[c] + h[e]', rxn);

% test that no reaction was matched
assert(isempty(matched))

% check match for existing reaction
matched = ReactionEq(rxn{1, 3}, rxn);

% test that reaction was matched
assert(~isempty(matched))

% change the directory
cd(currentDir)


classdef (HandleCompatible) DisplayNonScalarObjectAsTable < matlab.mixin.CustomDisplay
    % DisplayNonScalarObjectAsTable -
    % ---------------------------------------------------------------------
    % Abstract: This mixin class overrides displayNonScalarObject() to
    % display an array of objects as a table.
    %

    %   Copyright 2018-2019 The MathWorks, Inc.
    %
    % Auth/Revision:
    %   MathWorks Consulting
    %   $Author: rjackey $
    %   $Revision: 348 $  $Date: 2018-03-02 15:51:54 -0500 (Fri, 02 Mar 2018) $
    % ---------------------------------------------------------------------

    %% Public Methods
    methods (Sealed)

        function t = toDisplayTable(obj)
            % Convert the object to a table

            % Prepare indices as row names
            numObj = numel(obj);
            if isrow(obj)
                indices = string(1:numObj)';
            else
                varargout = cell(1,ndims(obj));
                [varargout{:}] = ind2sub(size(obj),1:numObj);
                indices = string(vertcat(varargout{:})');
                indices = join(indices,',',2);
            end
            rowNames = "(" + indices + ")";

            % Check for deleted handle objects
            if isa(obj,'handle')
                isDeleted = ~isvalid(obj);
                obj(isDeleted) = [];
                rowNames(isDeleted) = [];
            end

            % Gather property info
            props = string( properties(obj) )';

            % Preallocate a cell to store values
            numProps = numel(props);
            numObj = numel(obj);
            values = cell(numObj,numProps);

            % Populate cell with property values
            for pIdx = 1:numProps
                thisProp = props(pIdx);
                values(:,pIdx) = {obj.(thisProp)}';
            end %for

            % Convert to table
            t = cell2table(values,'VariableNames',props,'RowNames',rowNames);

        end %function

    end %methods

    %% Protected Methods
    methods (Sealed, Access=protected)

        function displayNonScalarObject(obj)

            % Format text to display
            className = matlab.mixin.CustomDisplay.getClassNameForHeader(obj);
            dimStr = matlab.mixin.CustomDisplay.convertDimensionsToString(obj);

            % Display the header
            if isa(obj,'matlab.mixin.Heterogeneous')
                fprintf('  %s Heterogeneous %s with common properties:\n\n',dimStr,className);
            else
                fprintf('  %s %s with properties:\n\n',dimStr,className);
            end

            % Show the group list in a table
            disp( obj.toDisplayTable() );

            if isa(obj,'handle') && any(~isvalid(obj))
               fprintf('  Object array contains deleted handles.\n');
            end

        end %function

    end %methods

end % classdef


function varargout = panel_eeglab_cond(varargin)
% PANEL_EEGLAB_COND: Selection of conditions from EegLab .set files.
%
% USAGE:  bstPanelNew = panel_eeglab_cond('CreatePanel', panelName)
%           selParams = panel_eeglab_cond('GetSelectedParameters')
%        selectedCond = panel_eeglab_cond('GetPanelContents')

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

eval(macro_method);
end

%% ===== CREATE PANEL =====
function [bstPanelNew, panelName] = CreatePanel(paramNames, paramValues) %#ok<DEFNU>
    % Java initializations
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.table.*;
    import org.brainstorm.table.*;
    panelName = 'EeglabConditions';

    % Create panel
    jPanelNew = gui_component('Panel');

    % ===== PARAMETERS LIST =====
    jPanelParams = gui_component('Panel');
    jBorder = java_scaled('titledborder', 'Parameters');
    jPanelParams.setBorder(jBorder);

    jPanelParams.setPreferredSize(java_scaled('dimension', 110, 200));
        % JList
        jListParams = JList(paramNames);
        jListParams.setFont(bst_get('Font'));
        java_setcb(jListParams, 'ValueChangedCallback', @ParamSelectionChanged_Callback);
        % Create scroll panel
        jScrollPanelParams = JScrollPane(jListParams);
        jScrollPanelParams.setBorder([]);
        jPanelParams.add(jScrollPanelParams, BorderLayout.CENTER);
    jPanelNew.add(jPanelParams, BorderLayout.WEST);

    % ===== CONDITIONS NAMES =====
    jPanelCond = gui_component('Panel');
    jBorder = java_scaled('titledborder', 'Conditions');
    jPanelCond.setBorder(jBorder);
    jPanelCond.setPreferredSize(java_scaled('dimension', 400, 200));
        % JTable
        jTableCond = JTable(DefaultTableModel({'Parameters', 'Condition name'}, 0));
        jTableCond.setFont(bst_get('Font'));
        jTableCond.getColumnModel.getColumn(0).setCellEditor(DisabledCellEditor());
        % Create scroll panel
        jScrollPanelCond = JScrollPane(jTableCond);
        jScrollPanelCond.setBorder([]);
        jPanelCond.add(jScrollPanelCond, BorderLayout.CENTER);
    jPanelNew.add(jPanelCond, BorderLayout.CENTER);

    % ===== VALIDATION BUTTONS =====
    jPanelValidation = gui_river([5,5], [0,5,12,5]);
        % Cancel
        jButtonCancel = JButton('Cancel');
        java_setcb(jButtonCancel, 'ActionPerformedCallback', @ButtonCancel_Callback);
        jPanelValidation.add('br right', jButtonCancel);
        % Ok
        jButtonOk = JButton('OK');
        java_setcb(jButtonOk, 'ActionPerformedCallback', @ButtonOk_Callback);
        jPanelValidation.add(jButtonOk);
    jPanelNew.add(jPanelValidation, BorderLayout.SOUTH);

    % Return a mutex to wait for panel close
    bst_mutex('create', panelName);

    % Create the BstPanel object that is returned by the function
    % => constructor BstPanel(jHandle, panelName, sControls)
    bstPanelNew = BstPanel(panelName, ...
                           jPanelNew, ...
                           struct('jListParams', jListParams, ...
                                  'jTableCond',  jTableCond));

%% =================================================================================
%  === LOCAL CALLBACKS =============================================================
%  =================================================================================
%% ===== CANCEL =====
    function ButtonCancel_Callback(varargin)
        % Close panel
        gui_hide(panelName);
    end

%% ===== OK =====
    function ButtonOk_Callback(varargin)
        % Close cell editor (validate last edited string)
        cellEditor = jTableCond.getCellEditor();
        if ~isempty(cellEditor)
        	cellEditor.stopCellEditing();
        end
        % Release mutex and keep the panel opened
        bst_mutex('release', panelName);
    end

%% ===== SELECTION CHANGED =====
    function ParamSelectionChanged_Callback(hObject, ev)
        global combinCond;
        if ~ev.getValueIsAdjusting()
            % Get selected items
            iSel = double(jListParams.getSelectedIndices());
            % Update JList conditions list
            tableModel = jTableCond.getModel();
            tableModel.setRowCount(0);
            % Check number of final combinations
            nbCond = prod(cellfun(@length, paramValues(iSel+1)));
%             % Too many combinations
%             if (nbCond > 500)
%                 combinCond = [];
%                 tableModel.addRow({'(Error: too many combinations)', ''});
%             else
                % Compute a structure that describes all the combinations
                combinCond = GetConditionCombinations(paramNames(iSel+1), paramValues(iSel+1));
                % Process all the combinations
                params = paramNames(iSel+1);
                for iCond = 1:length(combinCond)
                    strCondName = '';
                    strParamList = '';
                    for iParam = 1:length(params)
                        if (iParam ~= 1)
                            strCondName = [strCondName '_'];
                            strParamList = [strParamList, ', '];
                        end
                        if ischar(combinCond(iCond).(params{iParam}))
                            tmpStr = strrep(file_standardize(combinCond(iCond).(params{iParam})), '_', '-');
                            strCondName  = [strCondName, params{iParam}, tmpStr];
                            strParamList = [strParamList, params{iParam}, '=', combinCond(iCond).(params{iParam})];
                        else
                            strCondName  = [strCondName, params{iParam}, sprintf('%d', combinCond(iCond).(params{iParam}))];
                            strParamList = [strParamList, params{iParam}, sprintf('=%d', combinCond(iCond).(params{iParam}))];
                        end
                    end
                    tableModel.addRow({strParamList, strCondName});
                end
%             end
        end
    end
end

%% =================================================================================
%  === EXTERNAL CALLBACKS ==========================================================
%  =================================================================================
%% ===== GET SELECTED PARAMETERS =====
function selParams = GetSelectedParameters() %#ok<DEFNU>
    ctrl = bst_get('PanelControls', 'EeglabConditions');
    selObj = ctrl.jListParams.getSelectedValues();
    selParams = cell(1, length(selObj));
    for i = 1:length(selObj)
        selParams{i} = char(selObj(i));
    end
end

%% ===== GET PANEL RESULTS =====
function selectedCond = GetPanelContents(varargin) %#ok<DEFNU>
    % Get panel controls
    ctrl = bst_get('PanelControls', 'EeglabConditions');
    if isempty(ctrl)
        selectedCond = [];
        return
    end
    % Get current combination description
    global combinCond;
    selectedCond = combinCond;
    combinCond = [];
    clear global combinCond;
    % If nothing is available
    if (length(selectedCond) < 2)
        selectedCond = [];
    else
        % Get selected indices
        iCondSel = ctrl.jTableCond.getSelectedRows();
        if ~isempty(iCondSel)
            iCondSel = double(iCondSel(:))' + 1;
        else
            iCondSel = 1:length(selectedCond);
        end
        % Read new conditions names
        for iCond = iCondSel
            selectedCond(iCond).Name = file_standardize(char(ctrl.jTableCond.getModel.getValueAt(iCond-1, 1)));
        end
        selectedCond = selectedCond(iCondSel);
    end
end

%% =================================================================================
%  === HELPERS =====================================================================
%  =================================================================================
function combinCond = GetConditionCombinations(paramName, paramValues)
    % Get final number of conditions
    nbValues = cellfun(@length, paramValues);
    nbCond = prod(nbValues);
    % Build structure returned for each conditions
    structCond = struct('Name', '');
    for iField = 1:length(paramName)
        structCond.(paramName{iField}) = [];
    end
    combinCond = repmat(structCond, 1, nbCond);
    % Process each condition
    for iCond = 1:nbCond
        iValues = my_ind2sub(nbValues, iCond);
        % Process each parameter
        for iParam = 1:length(paramValues)
            % Get the value for parameter
            if iscell(paramValues{iParam})
                combinCond(iCond).(paramName{iParam}) = paramValues{iParam}{(iValues(iParam))};
            else
                combinCond(iCond).(paramName{iParam}) = paramValues{iParam}((iValues(iParam)));
            end
        end
    end
end

%% ===== CONVERT INDICES TO SUBINDICES =====
function loc = my_ind2sub(siz, ndx)
    n = length(siz);
    k = [1 cumprod(siz(1:end-1))];
    loc = zeros(size(siz));
    for i = n:-1:1,
      vi = rem(ndx-1, k(i)) + 1;
      vj = (ndx - vi)/k(i) + 1;
      loc(i) = vj;
      ndx = vi;
    end
end


classdef Tonemap < handle
    %TONEMAP  Tonemapping algorithm used to map HDR image to 8-bit range
    %
    % See also: cv.TonemapDrago, cv.TonemapDurand, cv.TonemapReinhard,
    %  cv.TonemapMantiuk, tonemap
    %

    properties (SetAccess = private)
        % Object ID
        id
    end

    properties (Dependent)
        % positive value for gamma correction.
        %
        % Gamma value of 1.0 implies no correction, gamma equal to 2.2 is
        % suitable for most displays. Generally gamma > 1 brightens the image
        % and gamma < 1 darkens it.
        Gamma
    end

    %% Tonemap
    methods
        function this = Tonemap(varargin)
            %TONEMAP  Creates simple linear mapper with gamma correction
            %
            %     obj = cv.Tonemap()
            %     obj = cv.Tonemap('OptionName',optionValue, ...)
            %
            % ## Options
            % * __Gamma__ default 1.0
            %
            % See also: cv.Tonemap.process
            %
            this.id = Tonemap_(0, 'new', varargin{:});
        end

        function delete(this)
            %DELETE  Destructor
            %
            %     obj.delete()
            %
            % See also: cv.Tonemap
            %
            if isempty(this.id), return; end
            Tonemap_(this.id, 'delete');
        end
    end

    %% Tonemap
    methods
        function dst = process(this, src)
            %PROCESS  Tonemaps image
            %
            %     dst = obj.process(src)
            %
            % ## Input
            % * __src__ source RGB image, 32-bit `single` 3-channel array.
            %
            % ## Output
            % * __dst__ destination image of same size as `src`, 32-bit
            %   `single` 3-channel array with values in [0,1] range.
            %
            % See also: cv.Tonemap.Tonemap
            %
            dst = Tonemap_(this.id, 'process', src);
        end
    end

    %% Algorithm
    methods (Hidden)
        function clear(this)
            %CLEAR  Clears the algorithm state
            %
            %     obj.clear()
            %
            % See also: cv.Tonemap.empty, cv.Tonemap.load
            %
            Tonemap_(this.id, 'clear');
        end

        function b = empty(this)
            %EMPTY  Returns true if the algorithm is empty
            %
            %     b = obj.empty()
            %
            % ## Output
            % * __b__ Returns true if the object is empty (e.g in the
            %   very beginning or after unsuccessful read).
            %
            % See also: cv.Tonemap.clear, cv.Tonemap.load
            %
            b = Tonemap_(this.id, 'empty');
        end

        function name = getDefaultName(this)
            %GETDEFAULTNAME  Returns the algorithm string identifier
            %
            %     name = obj.getDefaultName()
            %
            % ## Output
            % * __name__ This string is used as top level XML/YML node tag
            %   when the object is saved to a file or string.
            %
            % See also: cv.Tonemap.save, cv.Tonemap.load
            %
            name = Tonemap_(this.id, 'getDefaultName');
        end

        function save(this, filename)
            %SAVE  Saves the algorithm parameters to a file
            %
            %     obj.save(filename)
            %
            % ## Input
            % * __filename__ Name of the file to save to.
            %
            % This method stores the algorithm parameters in the specified
            % XML or YAML file.
            %
            % See also: cv.Tonemap.load
            %
            Tonemap_(this.id, 'save', filename);
        end

        function load(this, fname_or_str, varargin)
            %LOAD  Loads algorithm from a file or a string
            %
            %     obj.load(fname)
            %     obj.load(str, 'FromString',true)
            %     obj.load(..., 'OptionName',optionValue, ...)
            %
            % ## Input
            % * __fname__ Name of the file to read.
            % * __str__ String containing the serialized model you want to
            %   load.
            %
            % ## Options
            % * __ObjName__ The optional name of the node to read (if empty,
            %   the first top-level node will be used). default empty
            % * __FromString__ Logical flag to indicate whether the input is a
            %   filename or a string containing the serialized model.
            %   default false
            %
            % This method reads algorithm parameters from the specified XML or
            % YAML file (either from disk or serialized string). The previous
            % algorithm state is discarded.
            %
            % See also: cv.Tonemap.save
            %
            Tonemap_(this.id, 'load', fname_or_str, varargin{:});
        end
    end

    %% Getters/Setters
    methods
        function value = get.Gamma(this)
            value = Tonemap_(this.id, 'get', 'Gamma');
        end
        function set.Gamma(this, value)
            Tonemap_(this.id, 'set', 'Gamma', value);
        end
    end

end


function doseViewer3D(command, varargin);
%"doseFigure3D"
%   Creates a figure containing a 3D dose browser for plancheck.
%
%JRA 07/13/05
%
% 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/>.
%
%Usage:
%   3DDoseViewer

global planC;
global stateS;
indexS = planC{end};

if ~exist('command')
    command = 'init';
end

hFig = findobj('Tag', 'CERR_3DDoseViewer');

switch upper(command)
    case 'INIT'
        if ~isempty(hFig)
            delete(hFig);
        end

        % check if atleast one dose exists
        if length(planC{indexS.dose})<1
            msgbox('No dose exist. Please calculate and store dose first')
            return;
        else
            doseSet=1;
        end

        screenSize = get(0,'ScreenSize');
        units = 'pixels';
        y = 480;
        x = 640;

        dy = floor((y-30)/2);
        dx = floor((x-30)/2);

        %Create figure and UI controls.
        hFig = figure('Name','3D Viewer', 'units', 'pixels', 'position',[(screenSize(3)-x)/2 (screenSize(4)-y)/2 x y], 'MenuBar', 'none', 'NumberTitle', 'off', 'resize', 'off', 'Tag', 'CERR_3DDoseViewer', 'color', [0 0 0]);

        hAxis = axes('position', [0 0 .7 1], 'color', [0 0 0]);

        hFrame = uicontrol('style', 'frame', 'units', 'normalized', 'position', [.7 .65 .28 .33]);

        %Create controls for structure selection
        structures = {'Select...' planC{indexS.structures}.structureName};
        nStructs = length(structures);
        uicontrol('style', 'text', 'units', 'normalized', 'position', [.71 .90 .1 .05], 'string', 'Structure:');
        uicontrol('style', 'popupmenu', 'units', 'normalized', 'position', [.82 .90 .15 .05], 'string', structures, 'value', 1, 'callback', 'doseViewer3D(''struct_dropdown'')');

        ud.surfaceHandles = cell(nStructs,1);
        ud.surfaceVisible = zeros(nStructs,1);

        doses = {planC{indexS.dose}.fractionGroupID};
        %doses = {doses{:} 'DoseDiff', 'DTA'};
        uicontrol('style', 'text', 'units', 'normalized', 'position', [.71 .84 .1 .05], 'string', 'Dose:');
        uicontrol('style', 'popupmenu', 'units', 'normalized', 'position', [.82 .84 .15 .05], 'string', doses, 'value', 1, 'callback', 'doseViewer3D(''dose_dropdown'')');

        %Alpha Controls

        %Colorbar

        %Snap view:
        views = {'Transverse', 'Sagittal', 'Coronal'};
        uicontrol('style', 'pushbutton', 'units', 'normalized', 'position', [.735 .78 .1 .05], 'string', 'Trans', 'callback', 'doseViewer3D(''view_trans'')');
        uicontrol('style', 'pushbutton', 'units', 'normalized', 'position', [.735 .72 .1 .05], 'string', 'Sag', 'callback', 'doseViewer3D(''view_sag'')');
        uicontrol('style', 'pushbutton', 'units', 'normalized', 'position', [.845 .78 .1 .05], 'string', 'Cor', 'callback', 'doseViewer3D(''view_cor'')');

        %Coordinate info.
        ud.handle.xPos = uicontrol('style', 'text', 'units', 'normalized', 'position', [.71 .66 .09 .05], 'string', 'x=', 'horizontalAlignment', 'left');
        ud.handle.yPos = uicontrol('style', 'text', 'units', 'normalized', 'position', [.80 .66 .09 .05], 'string', 'y=', 'horizontalAlignment', 'left');
        ud.handle.zPos = uicontrol('style', 'text', 'units', 'normalized', 'position', [.89 .66 .09 .05], 'string', 'z=', 'horizontalAlignment', 'left');

        %         uicontrol('style', 'text', 'units', 'normalized', 'position', [.71 .78 .1 .05], 'string', 'View');
        %         uicontrol('style', 'popupmenu', 'units', 'normalized', 'position', [.82 .78 .15 .05], 'string', views, 'value', 1, 'callback', 'doseViewer3D(''view_dropdown'')');
        %
        %Default to doseSet 1.
        %doseSet = 1;

        [xV, yV, zV] = getDoseXYZVals(planC{indexS.dose}(doseSet));
        dA = getDoseArray(doseSet);
        doseBrowser3D('init', hAxis, dA, xV, yV, zV);

        doseBrowser3D('SETPLANEMOTIONCALLBACK', hAxis, 'doseViewer3D(''PLANE_MOVED'')');
        doseBrowser3D('SETPLANEMOTIONDONECALLBACK', hAxis, 'doseViewer3D(''PLANE_MOTION_DONE'')');

        ud.hAxis = hAxis;
        colormap(hAxis, CERRColorMap(stateS.optS.doseColormap));
        set(hFig, 'userdata', ud);

        doseViewer3D('PLANE_MOVED');

    case 'PLANE_MOVED'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;
        [x,y,z] = doseBrowser3D('GETPLANECOORDINATES', hAxis);
        set(ud.handle.zPos, 'String', ['z=' num2str(z, 3)]);
        set(ud.handle.xPos, 'String', ['x=' num2str(x, 3)]);
        set(ud.handle.yPos, 'String', ['y=' num2str(y, 3)]);

    case 'PLANE_MOTION_DONE'
%         ud = get(hFig, 'userdata');
%         hAxis = ud.hAxis;
%         [x,y,z] = doseBrowser3D('GETPLANECOORDINATES', hAxis);

%         setAxisInfo(stateS.handle.CERRAxis(1), 'coord', z);
%         setAxisInfo(stateS.handle.CERRAxis(4), 'coord', x);
%         setAxisInfo(stateS.handle.CERRAxis(6), 'coord', y);
%         plancheckCallback('refresh');

%         for i=1:length(stateS.handle.CERRAxis)
%             viewAx = getAxisInfo(stateS.handle.CERRAxis(i),'view');
%             if strcmpi('transverse',viewAx)
%                 setAxisInfo(stateS.handle.CERRAxis(i), 'coord', z);
%             elseif strcmpi('sagittal',viewAx)
%                 setAxisInfo(stateS.handle.CERRAxis(i), 'coord', x);
%             elseif strcmpi('coronal',viewAx)
%                 setAxisInfo(stateS.handle.CERRAxis(i), 'coord', y);
%             end
%         end
%
%         sliceCallback('refresh')

    case 'VIEW_DROPDOWN'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;

        viewNum = get(gcbo, 'value');
        switch viewNum
            case 1
                view(hAxis, 0, 90);
            case 2
                view(hAxis, -90, 0);
            case 3
                view(hAxis, 0, 0);
            case 4
                %Do nothing: floating view.
        end

    case 'VIEW_TRANS'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;
        view(hAxis, 0, 90);

    case 'VIEW_SAG'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;
        view(hAxis, -90, 0);

    case 'VIEW_COR'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;
        view(hAxis, 0, 0);

    case 'STRUCT_DROPDOWN'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;

        %Get selected struct.
        structNum = get(gcbo, 'value') - 1;

        if structNum == 0
            return;
        end

        %Toggle surface visible.
        ud.surfaceVisible(structNum) = xor(ud.surfaceVisible(structNum),1);

        %Draw surface if necessary.
        if isempty(ud.surfaceHandles{structNum})
            p = isoStruct(structNum);
            ud.surfaceHandles{structNum} = p;
        else
            p = ud.surfaceHandles{structNum};
        end

        %Add/remove star to denote struct is on/off
        structList = get(gcbo, 'string');
        switch ud.surfaceVisible(structNum);
            case 0
                structList{structNum+1} = [planC{indexS.structures}(structNum).structureName];
                set(p, 'visible', 'off');
            case 1
                structList{structNum+1} = ['*' planC{indexS.structures}(structNum).structureName];
                set(p, 'visible', 'on');
        end
        set(gcbo, 'string', structList);
        set(hFig, 'userdata', ud);

    case 'DOSE_DROPDOWN'
        ud = get(hFig, 'userdata');
        hAxis = ud.hAxis;

        doseNum = get(gcbo, 'value');
        strings = get(gcbo, 'string');

        switch strings{doseNum}
            case 'DTA'
                dS = [getAxisInfo(stateS.handle.CERRAxis(1), 'doseSets') ...
                    getAxisInfo(stateS.handle.CERRAxis(2), 'doseSets')];
                if length(dS) == 2
                    [xV1, yV1, zV1] = getDoseXYZVals(planC{indexS.dose}(dS(1)));
                    [xV, yV, zV] = getDoseXYZVals(planC{indexS.dose}(dS(2)));
                    dose3M1 = getDoseArray(dS(1));
                    dose3M2 = getDoseArray(dS(2));
                    [dA, ptc] = calculateGammaFcn1(dose3M1, dose3M2, [abs(yV1(2)-yV1(1)) abs(xV1(2)-xV1(1)) abs(zV1(2)-zV1(1))]);
                    colormap(hAxis, CERRColorMap('DTA'));
                else
                    return;
                end
            case 'DoseDiff'
                if doseNum == 0
                    dS = [];
                else
                    dS = [getAxisInfo(stateS.handle.CERRAxis(1), 'doseSets') ...
                    getAxisInfo(stateS.handle.CERRAxis(2), 'doseSets')];
                end
                [xV1, yV1, zV1] = getDoseXYZVals(planC{indexS.dose}(dS(1)));
                [xV, yV, zV] = getDoseXYZVals(planC{indexS.dose}(dS(2)));
                dose3M1 = getDoseArray(dS(1));
                dose3M2 = getDoseArray(dS(2));
                dA = dose3M1 - dose3M2;

            otherwise
                dA = getDoseArray(doseNum, planC);
                [xV, yV, zV] = getDoseXYZVals(planC{indexS.dose}(doseNum));
                colormap(hAxis, CERRColorMap(stateS.optS.doseColormap));
        end
        doseBrowser3D('NEWDOSE', hAxis, dA, xV, yV, zV);
end


%% S2FunHandle


function bvhPlayFile(fileName)

% BVHPLAYFILE Play motion capture data from a bvh file.
% FORMAT
% DESC plays motion capture data by reading in a bvh file from disk.
% ARG fileName : the name of the file to read in, in bvh format.
%
% COPYRIGHT : Neil D. Lawrence, 2005
%
% SEEALSO : acclaimPlayFile, bvhReadFile, skelPlayData

% MOCAP

[skel, channels, frameLength] = bvhReadFile(fileName);
skelPlayData(skel, channels, frameLength);


function GUI = sessionGUI_loadROI(rois, viewer);
% Load a saved ROI into a mrViewer UI.
%
% GUI = sessionGUI_loadROI(<rois=get from GUI>, <mrViewer handle>);
%
% rois can be specified as the name of an ROI in the relevant ROI dir
% (inplane or volume, depending on the GUI's roi type), a path to an
% ROI file, an index into the ROI list being displayed, a handle
% to a uicontrol with the ROI list, or a cell array of several of these
% specifications. By default, it uses the GUI.controls.roi listbox.
%
% This function will load the ROIs into the current mrViewer UI specified
% by GUI.settings.viewer. An alternate viewer can be specified by passing
% the handle to the main UI figure. If no viewer is open, this will open
% one.
%
%
% ras, 07/06.
mrGlobals2;

if notDefined('rois'), rois = GUI.controls.roi; end
if notDefined('viewer')
    if isempty(GUI.viewers)
        viewer = sessionGUI_viewInplane;
	else
	    viewer = GUI.viewers(GUI.settings.viewer);
	end
end

% parse the format of the rois arg, getting it into the format
% of a cell array of file paths
if iscell(rois)
    % check that each entry is a path
    for i = 1:length(rois)
        rois{i} = sessionGUI_roiPath(rois{i});
    end

elseif isnumeric(rois) & all(mod(rois, 1)==0)
    % index into ROIs list
    for i = 1:length(rois)
        roiList{i} = sessionGUI_roiPath(rois(i));
    end
    rois = roiList;

elseif ishandle(rois)
    % get from uicontrol
    rois = get(rois, 'Value');
    for i = 1:length(rois)
        roiList{i} = sessionGUI_roiPath(rois(i));
    end
    rois = roiList;

elseif ischar(rois)
    rois = {sessionGUI_roiPath(rois)};

else
    error('Invalid ROI specification. ')

end

% Now that we have a cell array of paths, load each one into the current
% viewer:
ui = get(viewer, 'UserData');
for i = 1:length(rois)
    ui = mrViewLoad(ui, rois{i}, 'roi');
end

% select the last one in the list
mrViewROI('select', ui, length(ui.rois));

return


classdef SmoothingExponentComputerFactory < handle

    methods (Access = public, Static)

        function obj = create(cParams)
            switch cParams.type
                case 'Optimal'
                   obj = SmoothingExponentComputerOptimal(cParams);
                case 'Given'
                   obj = SmoothingExponentComputerGiven(cParams);
            end
        end

    end

end


function [curCosts] = updateCosts(curCosts, costs)
  fieldNames = fields(curCosts);
  for ii=1:length(fieldNames)
    field = fieldNames{ii};
    curCosts.(field) = curCosts.(field) + costs.(field);
  end
end


classdef MimEditBlue < MimGuiPlugin
    % MimEditBlue. Gui Plugin for setting paint colour
    %
    %     You should not use this class within your own code. It is intended to
    %     be used by the gui of the TD MIM Toolkit.
    %
    %     MimEditBlue is a Gui Plugin for the MIM Toolkit.
    %
    %
    %     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
        ButtonText = 'Blue'
        SelectedText = 'Blue'
        ToolTip = 'Edit with blue label'
        Category = 'Segmentation label'
        Visibility = 'Dataset'
        Mode = 'Edit'

        HidePluginInDisplay = false
        PTKVersion = '1'
        ButtonWidth = 5
        ButtonHeight = 1
        Icon = 'paint.png'
        IconColour = GemMarkerPoint.DefaultColours{1}
        Location = 31
    end

    methods (Static)
        function RunGuiPlugin(gui_app)
            gui_app.ImagePanel.PaintBrushColour = 1;
        end

        function enabled = IsEnabled(gui_app)
             enabled = gui_app.IsDatasetLoaded && gui_app.ImagePanel.OverlayImage.ImageExists && ...
                isequal(gui_app.ImagePanel.SelectedControl, 'Paint');
        end

        function is_selected = IsSelected(gui_app)
            is_selected = gui_app.ImagePanel.PaintBrushColour == 1;
        end
    end
end


function p = getPosition( o, u )
%getPosition  Get position of graphics object
%
%  p = getPosition(o,u) sets the position of a graphics object o with units
%  u.
%
%  In contrast to getting the Position property directly, this function
%  honors the ActivePositionProperty of axes.

%  Copyright 2009-2016 The MathWorks, Inc.
%  $Revision: 1435 $ $Date: 2016-11-17 17:50:34 +0000 (Thu, 17 Nov 2016) $

% Get position
if ~isempty( findprop( o, 'ActivePositionProperty' ) )
    switch o.ActivePositionProperty
        case 'position'
            q = o.Position;
        case 'outerposition'
            q = o.OuterPosition;
        otherwise
            error( 'uix:InvalidState', ...
                'Unknown value ''%s'' for property ''ActivePositionProperty'' of %s.', ...
                o.ActivePositionProperty, class( o ) )
    end
else
    q = o.Position;
end

% Get units
if ~isempty( findprop( o, 'Units' ) )
    v = o.Units;
else
    v = 'pixels';
end

% Convert
if strcmp( u, v ) % trivial
    p = q;
else % conversion required
    p = hgconvertunits( ancestor( o, 'figure' ), q, v, u, o.Parent );
end

end % getPosition


function dfadjusttoolbar(dffig)
%DFADJUSTTOOLBAR Adjust contents of distribution fitting plot toolbar

%   $Revision: 1.1.6.5 $  $Date: 2004/01/24 09:35:14 $
%   Copyright 2003-2004 The MathWorks, Inc.

h0 = findall(dffig,'Type','uitoolbar');
h1 = findall(h0,'Parent',h0);
czoom = [];
for j=length(h1):-1:1
   mlabel = get(h1(j),xlate('TooltipString'));
   if ~isempty(findstr(mlabel,'Zoom')) || ~isempty(findstr(mlabel,'Pan'))
      czoom(end+1) = h1(j);
   elseif isempty(findstr(mlabel,'Print'))
      delete(h1(j));
      h1(j) = [];
   else
     c1 = h1(j);
   end
end

% Add more icons especially for distribution fitting
if exist('dficons.mat','file')==2
   icons = load('dficons.mat','icons');
   state = dfgetset('showlegend');
   if isempty(state), state = 'on'; end
   try
      % Try to get the default MATLAB legend icon
      legicon = load([matlabroot '/toolbox/matlab/icons/legend.mat']);
      cdata = legicon.cdata;
   catch
      cdata = icons.icons.legend; % in case of trouble, use older icon
   end
   c2 = uitoggletool(h0, 'CData',cdata,...
                    'State',state,...
                    'TooltipString', 'Legend On/Off',...
                    'Separator','on',...
                    'ClickedCallback','dfittool(''togglelegend'')',...
                    'Tag','showlegend');
   state = dfgetset('showgrid');
   if isempty(state), state = 'off'; end
   c3 = uitoggletool(h0, 'CData',icons.icons.grid,...
                    'State',state,...
                    'TooltipString', ('Grid On/Off'),...
                    'Separator','off',...
                    'ClickedCallback','dfittool(''togglegrid'')',...
                    'Tag','showgrid');
   c = get(h0,'Children');
   cnew = [c1 czoom c2 c3]';

   set(h0,'Children',cnew(end:-1:1));
end


function ip = inplace(a)
% INPLACE Convert to a type that supports inplace modification
% ipa = inplace(v) creates an inplace double object from any matrix v.
%
% Example:
%    ipa = inplace(ones(5));

if nargin == 0
    error('inplace:invalidParameter', ['ipdouble must be created with an initial .']);
elseif isa(a,'ipdouble')
    % make a copy
    ipd = inplace(a.a);

    return;

end

    function out = ip_get_a()
        out = a;
    end

    function ip_assign(in)
        a = in;
    end

    function ip_subsasgn(S,B)
        subsasgn(a,S,B);
    end

    ip.get_a = @ip_get_a;
    ip.assign = @ip_assign;
    ip.subsasgn = @ip_subsasgn;

    ip = class(ip,'inplace');

% ***** end inplace *****
end


function tor_ihb_TalSpace()
% :Usage:
% ::
%
%    tor_ihb_TalSpace
%
% Main function to view SPM99 cluster's (contours & 3D) in Talariach space
%
%==================================================================================
%   Graphic objects and their 'Tags':
%==================================================================================
%   type        handle          Tag                     Description
%----------------------------------------------------------------------------------
%   figure      hFigMain        ihb_TalSpaceMain_fig    Main figure
%   figure      hFig3D          ihb_TalSpace3D_fig      3D view figure
%   figure      hFigLeg         ihb_TalSpaceLeg_fig     Legend figure
%
%   axes        hAxis3D         ihb_axesTalSpace3D      Axes for 3D view
%   light       hLight          ihb_lightTalSpace3D     Light object for 3D view
%
%   patch                       ihb_cntAxial            contours patch handles
%   patch                       ihb_cntFrontal              in 3D view window
%   patch                       ihb_cntSaggitalL
%   patch                       ihb_cntSaggitalR
%
%   patch                       ihb_surfaceCluster      isosurface patch
%
%   uicontrol                   ihb_CursorCoord         coordinates under cursor
%   uicontrol                   ihb_ClusterLevelProb    cluster probability
%   uicontrol                   ihb_VoxelLevelProb      extr. probability
%   uicontrol                   ihb_VolumeInVox         cluster volume
%   uicontrol                   ihb_ClusterPopUp        select cluster combo box
%
%   uicontrol                   ihb_clr_Orig            pushbuttons for
%   uicontrol                   ihb_clr_Symm            color change in
%   uicontrol                   ihb_clr_Surface         legend window
%   uicontrol                   ihb_clr_Axial
%   uicontrol                   ihb_clr_Frontal
%   uicontrol                   ihb_clr_Saggital
%
%   line                        ihb_LineOriginal        lines for original clusters
%   line                        ihb_LineSymmetrical     lines for symmetrical clusters
%
%   uimenu                      ihb_VoxSizeMenu111
%   uimenu                      ihb_VoxSizeMenu222
%   uimenu                      ihb_VoxSizeMenu444
%
%   uimenu                      ihb_RendererMenuZbuffer
%   uimenu                      ihb_RendererMenuOpenGL
%
%   uimenu                      ihb_TransparencyMenu
%   uimenu                      ihb_TransparencyMenuOpaque
%   uimenu                      ihb_TransparencyMenuLow
%   uimenu                      ihb_TransparencyMenuMedium
%   uimenu                      ihb_TransparencyMenuHigh
%
%   uimenu                      ihb_Axes3DMenuClusterOnly
%   uimenu                      ihb_Axes3DMenuWholeBrain
%
%   uimenu                      ihb_LineWidthMenuThin
%   uimenu                      ihb_LineWidthMenuNormal
%   uimenu                      ihb_LineWidthMenuThick
%
%==================================================================================
%  Application data (name used with setappdata the same as handle or variable name
%==================================================================================
% for hFigMain:
%
%   axes            hAxAxial            axial
%   axes            hAxFront            frontal
%   axes            hAxSagL             left saggital
%   axes            hAxSagR             right saggital
%   strucure array  clusters            array of selected clusters
%   integer         indClusterToView    index of currently viewed cluster in clusters array
%   bool            drawSymLS           == 1 if draw symmetrical on left saggital
%   bool            drawSymRS           == 1 if draw symmetrical on right saggital
%
%----------------------------------------------------------------------------------
%
% for hAxis (where hAxis is one of hAxAxial, hAxFront, hAxSagL, hAxSagR):
%   (see ihb_LoadSlice for detail)
%
%   strucure array  sliceInfo           array of Talarich slice information (ihbdfl_ax_info etc.)
%   integer array   rngArray            array of local indexes in sliceInfo
%   integer         sliceIndex          index of slice in the local range array rngArray
%   double          sliceDist           slice distance from origin
%   string          axType              axis type: 'ax' 'fr' 'sl' 'sr'
%   1x2 vector      xLim                limit values for X direction
%   1x2 vector      yLim                limit values for Y direction
%
%
%==================================================================================
% Default information in ihb_TalSpaceDfl.mat file (see ihb_ResetDefaults)
%==================================================================================
% To get default variable with name var use:
%
% load('ihb_TalSpaceDfl.mat', 'var');
%
% To save:
%
% save('ihb_TalSpaceDfl.mat', 'var', '-append');
%----------------------------------------------------------------------------------
% Figures tags for windows created by SPM during call spm_getSPM
%----------------------------------------------------------------------------------
% ihbdfl_spm_fig_Interactive
% ihbdfl_spm_fig_SelFileWin
% ihbdfl_spm_fig_ConMan
%----------------------------------------------------------------------------------
% Minimal size of clusters to draw
%----------------------------------------------------------------------------------
% ihbdfl_min_size_to_draw
%----------------------------------------------------------------------------------
% Sizes of voxels used in Talariach space
%----------------------------------------------------------------------------------
% ihbdfl_tal_x_vox
% ihbdfl_tal_y_vox
% ihbdfl_tal_z_vox
%----------------------------------------------------------------------------------
% Sizes of main window and axis for ihb_TalSpace
%----------------------------------------------------------------------------------
% ihbdfl_main_width
% ihbdfl_main_height
% ihbdfl_main_gap
% ihbdfl_main_x
% ihbdfl_main_y
% ihbdfl_main_z
% ihbdfl_main_info_h
%----------------------------------------------------------------------------------
% Talariach slices information
%----------------------------------------------------------------------------------
% ihbdfl_ax_info
% ihbdfl_fr_info
% ihbdfl_sl_info
% ihbdfl_sr_info
%----------------------------------------------------------------------------------
% Axis limits to draw slice
%----------------------------------------------------------------------------------
% ihbdfl_xLimD
% ihbdfl_yLimD
% ihbdfl_zLimD
% ihbdfl_xLimI
% ihbdfl_yLimI
% ihbdfl_zLimI
%----------------------------------------------------------------------------------
% 3D view Renderer ('zbuffer' or 'OpenGL')
% 3D view transparency (available only for OpenGL
%----------------------------------------------------------------------------------
% ihbdfl_renderer
% ihbdfl_transparency
%----------------------------------------------------------------------------------
% Axes for 3D view type. If ihbdfl_bAxesIsClusterOnly == 1 - axes have cluster range
%                                                        0 - axes have brain range
%----------------------------------------------------------------------------------
% ihbdfl_bAxesIsClusterOnly
%----------------------------------------------------------------------------------
% Colors defaults
%----------------------------------------------------------------------------------
% ihbdfl_color_clOrig
% ihbdfl_color_clSymm
% ihbdfl_color_surface
% ihbdfl_color_cntAx
% ihbdfl_color_cntFr
% ihbdfl_color_cntSag
%----------------------------------------------------------------------------------
% Line width
%----------------------------------------------------------------------------------
% ihbdfl_line_width
%==================================================================================
%
% ..
%   09.04.01    Sergey Pakhomov
%   01.08.01    last modified
% ..

% ..
%    Create Default information file if necessary
% ..
dflFileName = ihb_FileFolderName('dfl');
fid = fopen(dflFileName);
if fid == -1
    ihb_ResetDefaults;
else
    fclose(fid);
end
%==================================================================================
% Delete previous figures
%==================================================================================
ihb_ResetFigure('ihb_TalSpaceMain_fig');
ihb_ResetFigure('ihb_TalSpace3D_fig');
ihb_ResetFigure('ihb_TalSpaceLeg_fig');
%==================================================================================
% Create main figure
%==================================================================================
screenUnits = get(0, 'units');      % Save current screen units
set(0, 'units', 'pixels');          % Set pixels units for screen
scrSize = get(0,'ScreenSize');      % Get screen size in pixels
set(0, 'units', screenUnits);       % Restore current screen units

load(dflFileName, 'ihbdfl_main_width');
load(dflFileName, 'ihbdfl_main_height');
pos(3) = ihbdfl_main_width;
pos(4) = ihbdfl_main_height;
pos(1) = (scrSize(3) - pos(3))/2;
pos(2) = (scrSize(4) - pos(4))/2;

hFigMain = figure(...
    'Visible', 'off',...
    'NumberTitle', 'off',...
    'MenuBar', 'none',...
    'Name', 'Talairach slices',...
    'Tag', 'ihb_TalSpaceMain_fig',...
    'CloseRequestFcn', 'ihb_CloseTalSpaceCB',...
    'ResizeFcn', 'ihb_ResizeTalSpaceCB',...
    'units', 'pixels',...
    'Position', pos);
%==================================================================================
% Set menu
%==================================================================================
%----------------------------------------------------------------------------------
% File menu
%----------------------------------------------------------------------------------
hFileMenu = uimenu('Label', 'File');
uimenu(hFileMenu, 'Label', 'New clusters', 'Callback', 'ihb_GetClusterSet');
uimenu(hFileMenu, 'Label', 'Exit', 'Callback', 'close', 'Separator', 'on');
%----------------------------------------------------------------------------------
% 3D View menu
%----------------------------------------------------------------------------------
h3DViewMenu = uimenu('Label', '3D View', 'Callback', 'ihb_TalSpaceView3D');
%----------------------------------------------------------------------------------
% Color Legend menu
%----------------------------------------------------------------------------------
hLegendMenu = uimenu('Label', 'Colors', 'Callback', 'ihb_ColorsTalSpace');
%----------------------------------------------------------------------------------
% Option menu
%----------------------------------------------------------------------------------
hOptionMenu = uimenu('Label', 'Options');
	%------------------------------------------------------------------------------
	%     Voxel size submenu
	%------------------------------------------------------------------------------
    hVoxSizeMenu = uimenu(hOptionMenu, 'Label', 'Voxel size');
        uimenu(hVoxSizeMenu, 'Tag', 'ihb_VoxSizeMenu111', 'Label', '1x1x1', 'Callback', 'ihb_TalSpaceVoxSizeMenuCB(1)');
        uimenu(hVoxSizeMenu, 'Tag', 'ihb_VoxSizeMenu222', 'Label', '2x2x2', 'Callback', 'ihb_TalSpaceVoxSizeMenuCB(2)');
        uimenu(hVoxSizeMenu, 'Tag', 'ihb_VoxSizeMenu444', 'Label', '4x4x4', 'Callback', 'ihb_TalSpaceVoxSizeMenuCB(4)');
	%------------------------------------------------------------------------------
	%     Renderer submenu
	%------------------------------------------------------------------------------
    hRendererMenu  = uimenu(hOptionMenu, 'Label', '3D renderer');
        uimenu(hRendererMenu, 'Tag', 'ihb_RendererMenuZbuffer', 'Label', 'Zbuffer', 'Callback', 'ihb_TalSpaceRendererMenuCB(1)');
        uimenu(hRendererMenu, 'Tag', 'ihb_RendererMenuOpenGL', 'Label', 'OpenGL', 'Callback', 'ihb_TalSpaceRendererMenuCB(2)');
	%------------------------------------------------------------------------------
	%     Transparency submenu
	%------------------------------------------------------------------------------
    hTransparencyMenu  = uimenu(hOptionMenu, 'Tag', 'ihb_TransparencyMenu', 'Label', '3D Transparency');
        uimenu(hTransparencyMenu, 'Tag', 'ihb_TransparencyMenuOpaque', 'Label', 'Opaque', 'Callback', 'ihb_TalSpaceTransparencyMenuCB(1.0)');
        uimenu(hTransparencyMenu, 'Tag', 'ihb_TransparencyMenuLow', 'Label', 'Low', 'Callback', 'ihb_TalSpaceTransparencyMenuCB(0.8)');
        uimenu(hTransparencyMenu, 'Tag', 'ihb_TransparencyMenuMedium', 'Label', 'Medium', 'Callback', 'ihb_TalSpaceTransparencyMenuCB(0.5)');
        uimenu(hTransparencyMenu, 'Tag', 'ihb_TransparencyMenuHigh', 'Label', 'High', 'Callback', 'ihb_TalSpaceTransparencyMenuCB(0.2)');
	%------------------------------------------------------------------------------
	%     3D axes submenu
	%------------------------------------------------------------------------------
    hAxes3DMenu  = uimenu(hOptionMenu, 'Label', '3D view axes');
        uimenu(hAxes3DMenu, 'Tag', 'ihb_Axes3DMenuClusterOnly', 'Label', 'Cluster Only', 'Callback', 'ihb_TalSpaceAxes3DMenuCB(1)');
        uimenu(hAxes3DMenu, 'Tag', 'ihb_Axes3DMenuWholeBrain', 'Label', 'Whole Brain', 'Callback', 'ihb_TalSpaceAxes3DMenuCB(0)');
	%------------------------------------------------------------------------------
	%     Smoothing submenu
	%------------------------------------------------------------------------------
    % hSmoothMenu = uimenu(hOptionMenu, 'Label', 'Smoothing');
	%------------------------------------------------------------------------------
	%     Line width submenu
	%------------------------------------------------------------------------------
    hLineWidthMenu = uimenu(hOptionMenu, 'Label', 'Line width');
        uimenu(hLineWidthMenu, 'Tag', 'ihb_LineWidthMenuThin', 'Label', 'Thin', 'Callback', 'ihb_TalSpaceLineWidthMenuCB(1)');
        uimenu(hLineWidthMenu, 'Tag', 'ihb_LineWidthMenuNormal', 'Label', 'Normal', 'Callback', 'ihb_TalSpaceLineWidthMenuCB(2)');
        uimenu(hLineWidthMenu, 'Tag', 'ihb_LineWidthMenuThick', 'Label', 'Thick', 'Callback', 'ihb_TalSpaceLineWidthMenuCB(4)');
    hResetMenu = uimenu(hOptionMenu, 'Label', 'Reset Defaults', 'Callback', 'ihb_TalSpaceResetMenuCB');
%----------------------------------------------------------------------------------
% Help menu
%----------------------------------------------------------------------------------
hHelpMenu  = uimenu('Label', 'Help');
    uimenu(hHelpMenu, 'Label', 'Web site', 'Callback', 'ihb_TalSpaceHelp');
    uimenu(hHelpMenu, 'Label', 'About', 'Callback', 'ihb_AboutTalSpace');
%----------------------------------------------------------------------------------
ihb_TalSpaceSetMenuCheck;
%----------------------------------------------------------------------------------
% Set axis and information UI
%----------------------------------------------------------------------------------
ihb_SetAxis(hFigMain);
ihb_SetInfoUI(hFigMain);
%----------------------------------------------------------------------------------
% Set mouse move callback
%----------------------------------------------------------------------------------
set(hFigMain, 'WindowButtonMotionFcn', 'ihb_MotionTalSpaceCB');
%----------------------------------------------------------------------------------
% Select cluster set and cluster to view    while
%----------------------------------------------------------------------------------
bIsEmpty = 0;
while bIsEmpty == 0
    bIsEmpty = tor_ihb_GetClusterSet;
    if bIsEmpty == 0
        h = msgbox('Cluster to view should be selected', 'Warning!', 'warn', 'modal');
        waitfor(h);
    end
end