% POP_EEGTHRESH - reject artifacts by detecting outlier values.  This has 
%                   long been a standard method for selecting data to reject.
%                   Applied either for electrode data or component activations.
% Usage:
%   >> pop_eegthresh( INEEG, typerej); % pop-up interactive window
%   >> [EEG Indexes] = pop_eegthresh( INEEG, typerej, elec_comp, lowthresh, ...
%                upthresh, starttime, endtime, superpose, reject);
%
% Graphic interface:
%   "Electrode|Component indices(s)" - [edit box] indices of the electrode(s) or 
%                 component(s) to take into consideration. Same as the 'elec_comp'
%                 parameter from the command line.
%   "Minimum rejection threshold(s)" - [edit box] lower threshold limit(s) 
%                 (in uV|std. dev.). Sets command line parameter 'lowthresh'.
%   "Maximum rejection threshold(s)" - [edit box] upper threshold limit(s) 
%                  (in uV|std. dev.). Sets command line parameter 'upthresh'.
%   "Start time limit(s)" - [edit box] starting time limit(s) (in seconds). 
%                 Sets command line parameter 'starttime'.
%   "End time limit(s)" - [edit box] ending time limit(s) (in seconds). 
%                 Sets command line parameter 'endtime'.
%   "Display previous rejection marks: " - [Checkbox]. Sets the command line
%                 input option 'eegplotplotallrej'.
%   "Reject marked trials: " - [Checkbox]  Sets the command line
%                 input option 'eegplotreject'.
%
% Inputs:
%   INEEG      - input EEG dataset
%   typerej    - type of rejection (0 = independent components; 1 = raw
%              data). Default is 1. For independent components, before
%              thresholding the activations are normalized (to have std. dev. 1).
%   elec_comp  - [e1 e2 ...] electrode|component numbers to take 
%              into consideration for rejection
%   lowthresh  - lower threshold limit (in uV|std. dev. For components, the 
%              threshold(s) are in std. dev.). Can be an array if more than one 
%              electrode|component number is given in elec_comp (above). 
%              If fewer values than the number of electrodes|components, the 
%              last value is used for the remaining electrodes|components. 
%   upthresh   - upper threshold limit (in uV|std dev) (see lowthresh above)
%   starttime  - rejection window start time(s) in seconds (see lowthresh above)
%   endtime    - rejection window end time(s) in seconds (see lowthresh)
%   superpose  - [0|1] 0=do not superpose rejection markings on previous
%              rejection marks stored in the dataset: 1=show both current and
%              previously marked rejections using different colors. {Default: 0}.
%   reject     - [1|0] 0=do not actually reject the marked trials (but store the 
%              marks: 1=immediately reject marked trials. {Default: 1}.
% Outputs:
%   Indexes    - index of rejected trials
%     When EEGPLOT is called, modifications are applied to the current 
%     dataset at the end of the call to EEGPLOT when the user presses 
%     the 'Reject' button.
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: EEGTHRESH, EEGLAB, EEGPLOT, POP_REJEPOCH 

% Copyright (C) 2001 Arnaud Delorme, Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.

% 01-25-02 reformated help & license -ad 
% 03-07-02 added srate argument to eegplot call -ad

function [EEG, Irej, com] = pop_eegthresh( EEG, icacomp, elecrange, negthresh, posthresh, ...
   						starttime, endtime, superpose, reject, topcommand)

Irej = [];
com = '';
if nargin < 1
   help pop_eegthresh;
   return;
end
if nargin < 2
   icacomp = 1;
end

if icacomp == 0
	if isempty( EEG(1).icasphere )
		disp('Error: you must run ICA first'); return;
	end
end
if exist('reject') ~= 1
    reject = 1;
end

if nargin < 3
    
    % which set to save
    % -----------------
    promptstr = { fastif(icacomp,'Electrode (indices(s), Ex: 2 4 5):'   , 'Component (indices, Ex: 2 6:8 10):'), ...
                  fastif(icacomp,'Minimum rejection threshold(s) (uV, Ex:-20 -10 -15):', 'Minimum rejection threshold(s) (std. dev,  Ex: -3 -2.5 -2):'), ...
                  fastif(icacomp,'Maximum rejection threshold(s) (uV, Ex: 20 10 15):'  , 'Maximum rejection threshold(s) (std. dev, Ex: 2 2 2.5):'), ...
                  'Start time limit(s) (seconds, Ex -0.1 0.3):', ...
                  'End time limit(s) (seconds, Ex 0.2):', ...
                  'Display previous rejection marks', ...
                  'Reject marked trial(s)' };
    inistr = { fastif(icacomp, ['1:' int2str(EEG(1).nbchan)], '1:5'), ...
               fastif(icacomp, '-10', '-20'),  ...
               fastif(icacomp, '10', '20'), ...
               num2str(EEG(1).xmin), ...
               num2str(EEG(1).xmax), ...
               '0', ...
               '0' };
    
    g1 = [1 0.1 0.75];
    g2 = [1 0.22 0.85];
    geometry = {g1 g1 g1 g1 g1 1 g2 g2};
    uilist = {...
              { 'Style', 'text', 'string', promptstr{1}} {} { 'Style','edit'      ,'string' ,inistr{1}  'tag' 'cpnum'}...
              { 'Style', 'text', 'string', promptstr{2}} {} { 'Style','edit'      ,'string' ,inistr{2} 'tag' 'lowlim' }...
              { 'Style', 'text', 'string', promptstr{3}} {} { 'Style','edit'      ,'string' ,inistr{3}  'tag' 'highlim'}...
              { 'Style', 'text', 'string', promptstr{4}} {} { 'Style','edit'      ,'string' ,inistr{4}  'tag' 'starttime'}...
              { 'Style', 'text', 'string', promptstr{5}} {} { 'Style','edit'      ,'string' ,inistr{5}  'tag' 'endtime'}...
              {}...
              { 'Style', 'text', 'string', promptstr{6}} {} { 'Style','checkbox'  ,'string'  ,' ' 'value' str2double(inistr{6}) 'tag','rejmarks' }...
              { 'Style', 'text', 'string', promptstr{7}} {} { 'Style','checkbox'  ,'string'  ,' ' 'value' str2double(inistr{7}) 'tag' 'rejtrials'} ...
               };
    figname = fastif(icacomp == 0, 'Rejection abnormal comp. values -- pop_eegthresh()','Rejection abnormal elec. values -- pop_eegthresh()');
    result = inputgui( geometry,uilist,'pophelp(''pop_eegthresh'');', figname);
    
    size_result = size(result);
    if size_result(1) == 0
        return;
    end
    elecrange    = result{1};
    negthresh    = result{2};
    posthresh    = result{3};
    starttime    = result{4};
    endtime      = result{5};
    superpose    = result{6};
    reject       = result{7};
end

if ischar(elecrange) % convert arguments if they are in text format
    calldisp = 1;
    elecrange = eval( [ '[' elecrange ']' ]  );
    negthresh = eval( [ '[' negthresh ']' ]  );
    posthresh = eval( [ '[' posthresh ']' ]  );
    if ischar(starttime)
        starttime = eval( [ '[' starttime ']' ]  );
    end
    if ischar(endtime)
        endtime   = eval( [ '[' endtime ']' ]  );
    end
else
    calldisp = 0;
end

% process multiple datasets
% -------------------------
if length(EEG) > 1
    if nargin < 2
        [ EEG, com ] = eeg_eval( 'pop_eegthresh', EEG, 'warning', 'on', 'params', { icacomp, elecrange, negthresh, posthresh, starttime, endtime, superpose, reject } );
    else
        [ EEG, com ] = eeg_eval( 'pop_eegthresh', EEG, 'params', { icacomp, elecrange, negthresh, posthresh, starttime, endtime, superpose, reject } );
    end
    Irej = [];
    return;
end

if any(starttime < EEG.xmin) 
 fprintf('Warning : starttime inferior to minimum time, adjusted\n'); 
	starttime(find(starttime < EEG.xmin)) = EEG.xmin; 
end
if any(endtime   > EEG.xmax) 
	fprintf('Warning : endtime superior to maximum time, adjusted\n'); 
	endtime(find(endtime > EEG.xmax)) = EEG.xmax;
end
if isempty(elecrange)
    elecrange = 1:EEG.nbchan;
end

if icacomp == 1
	[Itmp Irej NS Erejtmp] = eegthresh( EEG.data, EEG.pnts, elecrange, negthresh, posthresh, [EEG.xmin EEG.xmax], starttime, endtime);
    tmpelecIout = zeros(EEG.nbchan, EEG.trials);
    tmpelecIout(elecrange,Irej) = Erejtmp;
else
    icaacttmp = eeg_getdatact(EEG, 'component', elecrange);
	[Itmp Irej NS Erejtmp] = eegthresh( icaacttmp, EEG.pnts, 1:length(elecrange), negthresh, posthresh, [EEG.xmin EEG.xmax], starttime, endtime);
    tmpelecIout = zeros(size(EEG.icaweights,1), EEG.trials);
    tmpelecIout(elecrange,Irej) = Erejtmp;
end

fprintf('%d channel selected\n', size(elecrange(:), 1));
fprintf('%d/%d trials marked for rejection\n', length(Irej), EEG.trials);
tmprejectelec = zeros( 1, EEG.trials);
tmprejectelec(Irej) = 1;

rej  = tmprejectelec;
rejE = tmpelecIout;
if calldisp
    if icacomp == 1
        macrorej = 'EEG.reject.rejthresh';
        macrorejE = 'EEG.reject.rejthreshE';
    else
        macrorej  = 'EEG.reject.icarejthresh';
        macrorejE = 'EEG.reject.icarejthreshE';
    end
	
	colrej = EEG.reject.rejthreshcol;
	eeg_rejmacro; % script macro for generating command and old rejection arrays
	     
    if icacomp == 1
        eegplot( EEG.data(elecrange,:,:), 'srate', EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:}); 
    else
        eegplot( icaacttmp, 'srate', EEG.srate, 'limits', [EEG.xmin EEG.xmax]*1000 , 'command', command, eegplotoptions{:}); 
    end
else 
    if reject == 1
        EEG = pop_rejepoch(EEG, rej, 0);
    end
end
if ~isempty(rej)
    if icacomp	== 1
        EEG.reject.rejthresh  = rej;
        EEG.reject.rejthreshE = rejE;
    else
        EEG.reject.icarejthresh  = rej;
        EEG.reject.icarejthreshE = rejE;
    end
end

%com = sprintf('Indexes = pop_eegthresh( %s, %d, [%s], [%s], [%s], [%s], [%s], %d, %d);', ...
%   inputname(1), icacomp, num2str(elecrange),  num2str(negthresh), ...
%   num2str(posthresh), num2str(starttime ) , num2str(endtime), superpose, reject ); 
com = [ com sprintf('EEG = pop_eegthresh(EEG,%s);', ...
		vararg2str({icacomp,elecrange,negthresh,posthresh,starttime,endtime,superpose,0})) ]; % reject is always set to 0 because trials are rejected in eegplot
if nargin < 3
	Irej = com;
end

% reject artifacts in a sequential fashion to save memory (ICA ONLY)
% -------------------------------------------------------
function [Irej, Erej] = thresh( data, elecrange, timerange, negthresh, posthresh, starttime, endtime);
    Irej    = [];
    Erej    = zeros(size(data,1), size(data,2));
    for index = 1:length(elecrange)
       tmpica = data(index,:,:);
       tmpica = reshape(tmpica, 1, size(data,2)*size(data,3));
       
       % perform the rejection
       % ---------------------	
	   tmpica = (tmpica-mean(tmpica,2)*ones(1,size(tmpica,2)))./ (std(tmpica,0,2)*ones(1,size(tmpica,2)));
	   [I1, Itmprej, NS, Etmprej] = eegthresh( tmpica, size(data,2), 1, negthresh, posthresh, timerange, starttime, endtime);
 	   Irej = union_bc(Irej, Itmprej);
 	   Erej(elecrange(index),Itmprej) = Etmprej;
	end

