% POP_RMDAT - Keep or remove continuous data around specific events
%
% Usage:
%   >> OUTEEG = pop_rmdat( EEG); % pop-up a data entry window
%   >> OUTEEG = pop_rmdat( EEG, typerange, timelimits, invertselection);
%
% Graphic interface:
%   "Time-locking event type(s)" - [edit box] Select 'Edit > Event values' 
%                to see a list of event.type values; else use the push button.
%                To use event types containing spaces, enter in single-quotes. 
%   "..."      - [push button] scroll event types.
%   "Time limits" - [edit box] epoch latency range [start, end] in seconds relative
%                to the event type latency.
% 
% Inputs:
%   EEG        - Input dataset. Data may already be epoched; in this case,
%                extract (shorter) subepochs time locked to epoch events.
%   typerange  - Cell array of event types to time lock to.
%                (Note: An event field called 'type' must be defined in 
%                the 'EEG.event' structure).
%   timelimits - Epoch latency limits [start end] in seconds relative to the time-locking event 
%                {default: [-1 2]}%   
%   invertselection - [0|1] Invert selection. 0 is to keep data around events
%                and 1 is to remove them {default:1 to remove them}
%   
% Outputs:
%   OUTEEG     - output dataset
%
% Authors: Arnaud Delorme, SCCN, INC, UCSD, 2009-

% 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.

function [EEG, com] = pop_rmdat( EEG, events, timelims, invertsel )

if nargin < 1
   help pop_rmdat;
	return;
end
com = '';
if nargin < 4
    invertsel = 1;
    warning('In EEGLAB < 2023.0, the function kept instead of removed the selected segments (now fixed)')
end
if isempty(EEG(1).event)
    error( [ 'No event. This function removes data' 10 'based on event latencies' ]);
end
if isempty(EEG(1).trials)
    error( 'This function only works with continuous data');
end
if ~isfield(EEG(1).event, 'latency')
    error( 'Absent latency field in event array/structure: must name one of the fields ''latency''');
end

if nargin < 3
	% popup window parameters
	% -----------------------
   promptstr    = { strvcat('Time-locking event type(s) ([]=all):', ...
                    'Select ''Edit > Event values'' to see type values.'), ...
                    'Epoch limits [start, end] in seconds:', ... 
                    'Name for the new dataset:', ... 
					'Out-of-bounds EEG rejection limits ([min max], []=none):'  };

   cbevent = ['tmpEEG = get(gcbf, ''userdata'');' ...
           'if ~isfield(tmpEEG.event, ''type'')' ...
				   '   errordlg2(''No type field'');' ...
				   'else' ...
                   '   tmpevent = tmpEEG.event;' ...
                   '   if isnumeric(tmpEEG.event(1).type),' ...
				   '        [tmps,tmpstr] = pop_chansel(unique([ tmpevent.type ]));' ...
				   '   else,' ...
                   '        [tmps,tmpstr] = pop_chansel(unique({ tmpevent.type }));' ...
                   '   end;' ...
				   '   if ~isempty(tmps)' ...
				   '       set(findobj(''parent'', gcbf, ''tag'', ''events''), ''string'', tmpstr);' ...
				   '   end;' ...
				   'end;' ...
				   'clear tmpEEG tmps tmpv tmpstr tmpevent tmpfieldnames;' ];
   
   geometry = { [2 1 1.2] [2 1 1.2] };
   uilist = { { 'style' 'text'       'string' 'Event type(s) ([]=all)' } ...
              { 'style' 'edit'       'string' '' 'tag' 'events' } ...
              { 'style' 'pushbutton' 'string' '...' 'callback' cbevent } ...
              { 'style' 'text'       'string' 'Time limits [start, end] in sec.' } ...
              { 'style' 'edit'       'string' '-1 1' } ...
              { 'style' 'popupmenu'  'string' 'Keep selected|Remove selected' } };
              
   result = inputgui( 'geometry', geometry, 'uilist', uilist, 'helpcom', 'pophelp(''pop_rmdat'')', 'title', 'Remove data portions around events - pop_rmdat()', 'userdata', EEG(1));
   if isempty(result) 
       return; 
   end
   
   if strcmpi(result{1}, '[]'), result{1} = ''; end
   if ~isempty(result{1})
       if strcmpi(result{1}(1),'''')   % If event type appears to be in single-quotes, use comma
                                       % and single-quote as delimiter between event types. toby 2.24.2006
                                       % fixed Arnaud May 2006
            events = eval( [ '{' result{1} '}' ] );
       else events = parsetxt( result{1});
       end
   else 
       events = {};
   end
   timelims = eval( [ '[' result{2} ']' ] );
   invertsel = result{3}-1;
 
end

% process multiple datasets
% -------------------------
if length(EEG) > 1
    if nargin < 3
        [ EEG, com ] = eeg_eval( 'pop_rmdat', EEG, 'warning', 'on', 'params', { events, timelims, invertsel } );
    else
        [ EEG, com ] = eeg_eval( 'pop_rmdat', EEG, 'params', { events, timelims, invertsel } );
    end
    return;
end

tmpevent = EEG.event;

% Checking for numeric values in fieldnames and changing them to string
 for i = 1: length(tmpevent)
     checknum(i) = isnumeric(tmpevent(i).type);
 end
  if sum(checknum)~=0
       tmpindx = find(checknum == 1);
       for i = 1: length(tmpindx)
           tmpevent(tmpindx(i)).type = num2str(tmpevent(tmpindx(i)).type);
       end
  end

% compute event indices
% ---------------------
allinds = [];
for index = 1:length(events)
    inds = strmatch(events{index},{ tmpevent.type }, 'exact');
    allinds = [allinds(:); inds(:) ]';
end
allinds = sort(allinds);
if isempty(allinds)
    disp('No event found');
    return;
end

% compute time limits
% -------------------
array = [];
bnd = strmatch('boundary', lower({tmpevent.type }));
bndlat = [ tmpevent(bnd).latency ];
for bind = 1:length(allinds)
    evtlat = EEG.event(allinds(bind)).latency;
    evtbeg = evtlat+EEG.srate*timelims(1);
    evtend = evtlat+EEG.srate*timelims(2);
    if any(bndlat > evtbeg & bndlat < evtend)
        % find the closer upper and lower boundaries
        bndlattmp = bndlat(bndlat > evtbeg & bndlat < evtend);
        diffbound = bndlattmp-evtlat;
        allneginds = find(diffbound < 0);
        allposinds = find(diffbound > 0);
        if ~isempty(allneginds), evtbeg = bndlattmp(allneginds(1)); end
        if ~isempty(allposinds), evtend = bndlattmp(allposinds(1)); end;       
        fprintf('Boundary found: time limits for event %d reduced from %3.2f to %3.2f\n', allinds(bind), ...
            (evtbeg-evtlat)/EEG.srate, (evtend-evtlat)/EEG.srate);
    end
    if ~isempty(array) && evtbeg < array(end)
        array(end) = evtend;
    else
        array = [ array; evtbeg  evtend];
    end
end

if ~isempty(array) && array(1) < 1, array(1) = 1; end
if ~isempty(array) && array(end) > EEG.pnts, array(end) = EEG.pnts; end
if isempty(array)
    disp('No event found');
    return;
end

if invertsel
    EEG = pop_select(EEG, 'notime', (array-1)/EEG.srate);
else
    EEG = pop_select(EEG, 'time', (array-1)/EEG.srate);
end  
   
% generate output command
% -----------------------
com = sprintf('EEG = pop_rmdat( EEG, %s);', vararg2str( { events timelims invertsel } ));
