function D = spm_eeg_spatial_confounds(S)
% This function defines spatial confounds and adds them to MEEG dataset.
% FORMAT D = spm_eeg_spatial_confounds(S)
%
% S        - optional input struct
%  fields of S:
%   D        - MEEG object or filename of M/EEG mat-file with epoched data
%   mode     - method for definition of the confounds (EYES, BESA, SVD,
%              SPMEEG, CLEAR)
%__________________________________________________________________________

% Vladimir Litvak
% Copyright (C) 2008-2022 Wellcome Centre for Human Neuroimaging


%-Startup
%--------------------------------------------------------------------------
spm('FnBanner', mfilename);
spm('FigName','Define spatial confounds');

if ~isfield(S, 'mode') && isfield(S, 'method'),          S.mode  = S.method;             end
if ~isfield(S, 'threshold') && isfield(S, 'svdthresh'),  S.threshold  = S.svdthresh;    end


D = spm_eeg_load(S.D);

if ~isfield(S, 'conditions') || isempty(S.conditions),   S.conditions = D.condlist;      end 
if ~iscell(S.conditions), S.conditions = {S.conditions};                                 end

sconf = [];
switch upper(S.mode)
    case 'EYES'
        [D, ok] = check(D, 'sensfid');
        
        if ~ok
            if check(D, 'basic')
                errordlg(['The requested file is not ready for source reconstruction.'...
                    'Use prep to specify sensors and fiducials.']);
            else
                errordlg('The meeg file is corrupt or incomplete');
            end
            return
        end
        
        %% ============ Find or prepare head model
        
        if ~isfield(D, 'val')
            D.val = 1;
        end
        
        if ~isfield(D, 'inv') || ~iscell(D.inv) ||...
                ~(isfield(D.inv{D.val}, 'forward') && isfield(D.inv{D.val}, 'datareg')) ||...
                ~isa(D.inv{D.val}.mesh.tess_ctx, 'char') % detects old version of the struct
            D = spm_eeg_inv_mesh_ui(D, D.val);
            D = spm_eeg_inv_datareg_ui(D, D.val);
            D = spm_eeg_inv_forward_ui(D, D.val);
            
            save(D);
        end
        
        eyes = [-34 53 -38; 34 53 -38];
        
        
        sconf = [];
        sconf.label = D.chanlabels(D.indchantype('MEEG', 'GOOD'));
        sconf.coeff = nan(length(sconf.label), 6);
        sconf.bad = ones(length(sconf.label), 1);
        
        [junk, modalities] = modality(D, 1, 1);
        
        for k = 1:numel(modalities)
            chanind = indchantype(D, modalities{k}, 'GOOD');
            
            if isempty(chanind)
                continue;
            end
            
            data = spm_eeg_inv_get_vol_sens(D, [], [], [], modalities{k});
            
           
            eyes = spm_eeg_inv_transform_points(inv(data.transforms.toMNI), eyes);
            
            vol  = data.(modalities{k}).vol;
            sens = data.(modalities{k}).sens;
            
            if isa(vol, 'char')
                vol = ft_read_headmodel(vol);
            end            
            
            [vol, sens] = ft_prepare_vol_sens(vol, sens, 'channel', D.chanlabels(chanind));
            
            
            if strncmp(modalities{k}, 'MEG', 3)
                reducerank = 2;
            else
                reducerank = 3;
            end
            
            L  = ft_compute_leadfield(eyes, sens, vol, 'reducerank', reducerank);
            
            [sel1, sel2] = spm_match_str(sconf.label, D.chanlabels(chanind));
            
            sconf.coeff(sel1, :) = spm_cond_units(L(sel2, :));
            sconf.bad(sel1, :) = 0;
        end       
    case 'BESA'       
        sconf = spm_eeg_read_bsa(S.conffile );
    case 'SVD'       
        cl = S.conditions;
        svdinput = [];
        for i = 1:numel(cl)
            tmp      = D(D.indchantype('MEEG', 'GOOD'), D.indsample(1e-3*S.timewin(1)):D.indsample(1e-3*S.timewin(2)), D.indtrial(cl{i}, 'GOOD'));
            svdinput = [svdinput, reshape(tmp, size(tmp, 1),  [])];
        end
        [U, L, V] = spm_svd(svdinput);
        
        
        if isfield(S, 'threshold')
            temp = zeros(size(svdinput));
            for n = size(V, 2):-1:1
                temp = temp+U(:, n)*L(n,n)*V(:,n)';
                if max(max(abs(temp)))>S.threshold;
                    S.ncomp = min(n+1, size(V, 2));
                    break;
                else
                    S.ncomp = 0;
                end
            end       
        end
        
        if S.ncomp>0
            ncomp = min(S.ncomp, size(U, 2));
            [sel1, sel2] = spm_match_str(D.chanlabels(D.indchantype('MEEG')), D.chanlabels(D.indchantype('MEEG', 'GOOD')));
            sconf = [];
            sconf.label = D.chanlabels(D.indchantype('MEEG'));
            sconf.coeff = nan(length(sconf.label), ncomp);
            sconf.coeff(sel1, :) = U(sel2, 1:ncomp);
            sconf.bad = ones(length(sconf.label), 1);
            sconf.bad(sel1, :) = 0;
        end
    case 'SPMEEG'       
        Ds = spm_eeg_load(S.conffile);
        sconf = getfield(Ds, 'sconfounds');        
    case 'CLEAR'
        if isfield(D, 'sconfounds')
            D = rmfield(D, 'sconfounds');
        end
end

if ~isempty(sconf)
    D = sconfounds(D, sconf, 'append');
end

% Plot scalp topographies
% ---------------------------------------------------------------------
if any(any(D.sconfounds))
    
    Fgraph = spm_figure('GetWin','Graphics');clf
    
    in = [];
    in.f = Fgraph;
    in.noButtons = 1;
    in.cbar = 0;
    in.plotpos = 0;
    
    [junk, modalities] = modality(D, 1, 1);
    
    conf = getfield(D, 'sconfounds');
    
    nm = numel(modalities);
    nc = size(conf.coeff, 2);
    
    for i = 1:nc
        for j = 1:nm
            in.type = modalities{j};
            
            ind = D.indchantype(modalities{j}, 'GOOD');
            
            [sel1, sel2] = spm_match_str(D.chanlabels(ind), conf.label);
            
            Y = conf.coeff(sel2, i);            
            
            in.max = max(abs(Y));
            in.min = -in.max;
            
            in.ParentAxes = subplot(nc, nm, (i - 1)*nm + j);
            spm_eeg_plotScalpData(Y, D.coor2D(ind) , D.chanlabels(ind), in);
            title(sprintf('%s\ncomponent %.0f', modalities{j}, i));           
        end
    end
end

D = D.history(mfilename, S);
save(D);

%-Cleanup
%--------------------------------------------------------------------------
spm('FigName', 'Define spatial confounds: done');
