function D = spm_eeg_reduce(S)
% Apply data reduction to M/EEG dataset
% FORMAT D = spm_eeg_reduce(S)
% S                     - input structure
%
% fields of S:
%   S.D                 - MEEG object or filename of M/EEG mat-file with
%   
%   S.channels          - cell array of channel names. Can include generic
%                         wildcards: 'All', 'EEG', 'MEG' etc
%   S.conditions          - cell array of condition trial names. 
%   S.method           - name for the spectral estimation to use. This
%                        corresponds to the name of a plug-in function that comes
%                        after 'spm_eeg_reduce_' prefix.
%   S.keeporig         - keep the original unreduced channels (1) or remove
%                        (0, default).
%   S.keepothers       - keep the other (not involved) channels
%   S.settings         - plug-in specific settings
%   S.timewin          - time windows or interest
%   S.prefix           - prefix for the output file (default - 'R')
%
% Output:
% D                     - M/EEG object 
%__________________________________________________________________________

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


%-Startup
%--------------------------------------------------------------------------
spm('FnBanner', mfilename);
spm('FigName','M/EEG reduce'); spm('Pointer','Watch');


%-Configure the analysis
%--------------------------------------------------------------------------
if ~isfield(S, 'channels'),   S.channels = 'all';             end
if ~isfield(S, 'conditions'), S.conditions.all = 1;           end
if ~isfield(S, 'timewin'),    S.timewin  = [-Inf Inf];        end
if ~isfield(S, 'keeporig'),   S.keeporig = false;          end
if ~isfield(S, 'keepothers'), S.keepothers  = true;           end
if ~isfield(S, 'prefix'),     S.prefix   = 'R';               end


if iscell(S.D)
    badind = [];
    for i = 1:numel(S.D)
        DD{i} = spm_eeg_load(S.D{i});
        badind = [badind DD{i}.badchannels];    
    end
    D = DD{1};
    badind = unique(badind);
else
    D = spm_eeg_load(S.D);
    DD{1}  = D;
    badind = D.badchannels;
end

chanind = setdiff(D.selectchannels(S.channels), badind);

if isempty(chanind)
    error('No channels selected.');
end

%%%%%%%%%
% MWW
samples = {};
for i = 1:size(S.timewin, 1)
    samples{i} = D.indsample(S.timewin(i, 1)):D.indsample(S.timewin(i, 2));
end

if isfield(S.conditions, 'all')
    trials = 1:D.ntrials;
else    
    trials = D.indtrial(S.conditions, 'GOOD');
    if isempty(trials)
        error('No trials matched the selection, check the specified condition labels');
    end
end
%%%%%%%%%%


if ~isfield(S, 'method')
    S.method = 'pca';
    S.settings.ncomp = min(length(floor(chanind)/2), 100);
end

if isfield(S, 'settings')
    S1 = S.settings;
else
    S1 = [];
end

if numel(DD)>1
    S1.D = DD;
else
    S1.D = D;
end

S1.chanind = chanind; 
S1.trials = trials; 
S1.samples = samples; 
montage = feval(['spm_eeg_reduce_' S.method], S1);

if ~isempty(badind)
    montage.labelorg = [montage.labelorg(:); D.chanlabels(badind)'];
    if S.keeporig
        montage.tra((end+1):(end+length(badind)), (end+1):(end+length(badind))) = eye(length(badind));     
    else
        montage.tra(end, end+length(badind)) = 0;
    end
    
    if isfield(montage, 'chantypeorg')
        montage.chantypeorg = [montage.chantypeorg(:); lower(D.chantype(badind))'];
    end
    
    if isfield(montage, 'chanunitorg')
        montage.chanunitorg = [montage.chanunitorg(:); D.units(badind)'];
    end
end

% This is to discard bad channels but keep other channels (like non MEEG).
if S.keeporig
    montage.labelnew = [montage.labelnew(:); D.chanlabels(chanind)'];
    montage.tra((end+1):(end+length(chanind)), 1:length(chanind)) = eye(length(chanind));    
    
    if isfield(montage, 'chantypenew')
        montage.chantypenew = [montage.chantypenew(:); lower(D.chantype([badind chanind]))'];
    end
    
    if isfield(montage, 'chanunitnew')
        montage.chanunitnew = [montage.chanunitnew(:); D.units([badind chanind])'];
    end
end

% Reorder as in the original file. This might be handy when reducing and
% then grand-averaging or merging across subjects
[sel1, sel2] = spm_match_str(D.chanlabels, montage.labelnew);
sortind = [spm_vec(sel2); spm_vec(setdiff(1:length(montage.labelnew), sel2))];

montage.labelnew = montage.labelnew(sortind);
montage.tra = montage.tra(sortind, :);
if isfield(montage, 'chantypenew')
    montage.chantypenew = montage.chantypenew(sortind);
end
if isfield(montage, 'chanunitnew')
    montage.chanunitnew = montage.chanunitnew(sortind);
end

S1 = [];
S1.montage = montage;
S1.keepothers = S.keepothers; 
S1.prefix = S.prefix;
S1.updatehistory  = 0;
for i = 1:numel(DD)
    S1.D = DD{i};
    D = spm_eeg_montage(S1);
    
    %-Save new M/EEG dataset(s)
    %--------------------------------------------------------------------------
    D = D.history('spm_eeg_reduce', S);
    save(D);
    
    DD{i} = D;
end

if numel(DD)>1
    D = DD;
end

%-Cleanup
%--------------------------------------------------------------------------
spm('FigName','M/EEG reduce: done'); spm('Pointer','Arrow');
