function [preshoot, iStart] = ...
    getPreshoots(x, t, upperState, lowerState, upperBound, lowerBound, seekFactor, tm, iPre, iPost)
%GETPRESHOOTS Compute Overshoot and Undershoot in pre-transition aberration region
%
%  returns the overshoot and undershoot in the pre-transition aberration
%  regions of the input waveform (x) for the pulse state metrics (lower,
%  level, and upper) of each state (1 and 2).  It also returns the instants
%  of the corresponding metrics in order to facilitate plotting and
%  graphing utilities.
%
%  The overshoot and undershoot parameters are computed in conformance to
%  Section 5.3.5 of IEEE Std 181-2003.

%   Copyright 2011-2021 The MathWorks, Inc.
%#codegen

  n = numel(tm.Polarity);

  if n > 0
    preState = signal.internal.polaritySelect(tm.Polarity, lowerState, upperState);
    preBound = signal.internal.polaritySelect(tm.Polarity, lowerBound, upperBound);
    tPre = signal.internal.linterp(t(iPre), t(iPre+1), x(iPre), x(iPre+1), preBound);

    %Get pre-transition metrics
    Tseek = tPre - seekFactor * tm.Duration;

    above = zeros(n, 1);
    below = zeros(n, 1);
    iOpre = zeros(n, 1);
    iUpre = zeros(n, 1);

    for i=1:n
      iStartTmp = find(t(1:iPre(i)) > Tseek(i), 1, 'first');
      if isempty(iStartTmp) 
        %protect against empty region
        iStart = iPre(i);      
      elseif i>2 && iStartTmp(1) < iPost(i-1) 
        %protect against narrow pulse.
        iStart = iPost(i-1);
      else
        iStart = iStartTmp(1);
      end
      [above(i), iAbove] = max(x(iStart:iPre(i)));
      [below(i), iBelow] = min(x(iStart:iPre(i)));
      iOpre(i) = iAbove + iStart - 1;
      iUpre(i) = iBelow + iStart - 1;
    end

    rOpre = (above - preState) / (upperState - lowerState);
    rUpre = (preState - below) / (upperState - lowerState);

    preshoot = struct('Overshoot',         rOpre*100, ...
                      'Undershoot',        rUpre*100, ...
                      'OvershootLevel',    x(iOpre), ...
                      'UndershootLevel',   x(iUpre), ...
                      'OvershootInstant',  t(iOpre), ...
                      'UndershootInstant', t(iUpre));
  else
    preshoot = struct('Overshoot',         zeros(0,1), ...
                      'Undershoot',        zeros(0,1), ...
                      'OvershootLevel',    zeros(0,1), ...
                      'UndershootLevel',   zeros(0,1), ...
                      'OvershootInstant',  zeros(0,1), ...
                      'UndershootInstant', zeros(0,1));
    iStart = 1;
  end    
end
