% EEG_INSERTBOUND - insert boundary event in an EEG event structure.
%
% Usage:
%       >> [eventout newind] = eeg_insertbound( eventin, pnts, ...
%                                                abslatency, duration);
% Required Inputs:
%   eventin    - EEGLAB event structure (EEG.event)
%   pnts       - data points in EEG dataset (EEG.pnts * EEG.trials)
%   abslatency - absolute latency of regions in original dataset. Can
%                also be an array of [beg end] latencies with one row
%                per region removed. Then 'lengths' argument is ignored.
% Optional Inputs:
%   lengths    - lengths of removed regions
%
% Outputs:
%   eventout   - EEGLAB event output structure with added boundaries
%   newind     - Indices of the new events
%
% Notes:
%   This function performs the following: 
%   1) add boundary events to the 'event' structure; 
%        remove nested boundaries; 
%        recompute the latencies of all events.
%   2) all latencies are given in (float) data points. 
%        e.g., a latency of 2000.3 means 0.3 samples (at EEG.srate)
%              after the 2001st data frame (since first frame has latency 0).
% 
% Author: Arnaud Delorme and Hilit Serby, SCCN, INC, UCSD, April, 19, 2004
%
% See also: EEG_EEGREJ, POP_MERGESET

% Copyright (C) 2004 Arnaud Delorme, SCCN, INC, UCSD, 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 [eventin, newind] = eeg_insertbound( eventin, pnts, regions, lengths)
    
    if nargin < 3
        help eeg_insertbound;
        return;
    end

    eeglab_options;
    regions = round(regions);
    regions(regions < 1) = 1;
    regions(regions > pnts) = pnts;
    for i=2:size(regions,1)
        if regions(i-1,2) >= regions(i,1)
            regions(i,1) = regions(i-1,2)+1;
        end
    end

    if ~isempty(regions)
        fprintf('eeg_insertbound(): %d boundary (break) events added.\n', size(regions, 1));
    else 
        return;
    end

    % recompute latencies of boundevents (in new dataset)
    % ---------------------------------------------------
    [~, tmpsort] = sort(regions(:,1));
    regions        = regions(tmpsort,:);
    lengths = regions(:,2)-regions(:,1)+1;
    
    if ~isempty(eventin) && isfield(eventin, 'latency')
         eventLatencies = [ eventin.latency ]; 
         if length(eventLatencies) ~= length(eventin)
             error('Some events do not have latencies')
         end
    else 
        eventLatencies = [];
    end
    newEventLatencies = eventLatencies;
    oriLen            = length(eventin);
    rmEvent           = [];
	for iRegion = 1:size(regions,1) % sorted in decreasing order

        % find event succeeding boundary to insert event
        % at the correct location in the event structure
        % ----------------------------------------------
        tmpind    = find( eventLatencies - regions(iRegion,1) > 0 );
        if ~isempty(newEventLatencies)
            newEventLatencies(tmpind) = newEventLatencies(tmpind)-lengths(iRegion);
        end

        % insert event
        % ------------
        [tmpnest, addlength ]  = findnested(eventin, eventLatencies, regions(iRegion,:));
        rmEvent = [ rmEvent tmpnest ];
        %if regions(iRegion,1) % do not remove first event

            eventin(end+1).type   = eeg_boundarytype(eventin);
            eventin(end).latency  = regions(iRegion,1)-sum(lengths(1:iRegion-1))-0.5;
            eventin(end).duration = lengths(iRegion,1)+addlength;
        %end
    end

    % copy latencies
    % --------------
    if ~isempty(newEventLatencies)
        for iEvent = 1:oriLen
            eventin(iEvent).latency = newEventLatencies(iEvent);
        end
    end
    eventin(rmEvent) = [];
    
    % resort events
    % -------------
    if ~isempty(eventin) && isfield(eventin, 'latency')
%       eventin([ eventin.latency ] < 1) = [];
        eventin([ eventin.latency ] < 0) = [];
        alllatencies = [ eventin.latency ];
        [~, sortind] = sort(alllatencies);
        eventin = eventin(sortind);
        newind = sortind(oriLen+1:end);
    end
    
    if ~isempty(rmEvent)
        fprintf('eeg_insertbound(): boundary events inserted and %d events removed.\n', length(rmEvent));
    end

    
% look for nested events
% return indices of nested events and
% their total length
% -----------------------------------
function [ indEvents, addlen ] = findnested(event, eventlat, region)
    indEvents = find( eventlat > region(1) & eventlat < region(2));

    if ~isempty(event) && isfield(event,'type') && isfield(event, 'duration')
        boundaryInd = eeg_findboundaries( event(indEvents) );
        addlen      = sum( [ event(indEvents(boundaryInd)).duration ] );
    else
        addlen = 0;
    end
    
