function [m,v,halvesHigh] = vmedian(v,n,nanflag,offset,stride,RESTOREVATEND) 
%MATLAB Code Generation Private Function

%   m = median v(offset + (1:n))
%
%   nanflag must be lowercase 'o' or 'i' (other chars ignored if longer).
%
%   offset is optional and defaults to 0 if not supplied.
%
%   v is modified and is provided as an output to help avoid making a copy
%   if desired.
%
%   halvesHigh is 0 with non-integer inputs or when m is exact, otherwise
%   -1 or 1, depending on which direction the integer value m has been
%   rounded. The mathematical median is halfway between m and m -
%   halvesHigh.

%   Copyright 2002-2020 The MathWorks, Inc.
%#codegen

narginchk(3,6);
coder.internal.allowEnumInputs;
ZERO = coder.internal.indexInt(0);
ONE = coder.internal.indexInt(1);
if nargin < 4
    offset = ZERO;
end
if nargin < 5
    stride = ONE;
    RESTOREVATEND = false;
else
    NaNInd = coder.nullcopy(zeros(1,length(v),coder.internal.indexIntClass));
end
coder.internal.prefer_const(n,nanflag,offset,stride);
vlen = n;
numNaNs = ZERO;
numNaNsToBeReplaced = ZERO;
% numNaNs keeps track of all the NaNs in V. NaNs at the end of V won't get
% swaped and don't need to be replaced at the end. numNaNsToBeReplaced
% keeps track of only those NaNs that need to be replaced.

halvesHigh = zeros('like',real(v));
if isfloat(v)
    if nanflag(1) == 'o'
        % Squeeze out any nans.
        vlen = ZERO;
        count = ONE;
        for k = 1:stride:n * stride
            if isnan(v(offset + k))
                if RESTOREVATEND
                    % Replace NaN with a value from the end of the window
                    % Make wasNaN(count) true so that a NaN can be put back
                    % afterwards

                    % Starting at the right end of the window, find the first
                    % non-NaN value and use that to replace the NaN
                    % Stop looking when we get to the current position
                    while n - numNaNs > count && ...
                        isnan(v(offset + (n - numNaNs) * stride))
                        numNaNs = numNaNs + 1;
                    end
                    if n - numNaNs == count
                        % Break if there are no more non-NaN values in the
                        % window
                        break
                    end
                    v(offset + k) = v(offset + (n - numNaNs) * stride);
                    numNaNsToBeReplaced = numNaNsToBeReplaced + 1;
                    NaNInd(numNaNsToBeReplaced) = k;
                    numNaNs = numNaNs + 1;
                    vlen = vlen+1;
                end
            else
                vlen = vlen + 1;
                if ~RESTOREVATEND && vlen < k
                    v(offset + vlen) = v(offset + k);
                end
            end
            if RESTOREVATEND && count + numNaNs == n
                % All the elements right of v(k) are NaNs
                break
            end
            count = count + ONE;
        end
    else
        % Return the first NaN if we find any.
        for k =1:stride:n * stride
            if isnan(v(offset + k))
                m = coder.internal.nan('like',v);
                return
            end
        end
    end
end
if vlen <= 4
    [m,halvesHigh] = med01234(v,vlen,offset,stride);
else
    midm1 = eml_rshift(vlen,ONE);
    mid = midm1 + 1;
    evenlength = (eml_bitand(vlen,ONE) == ZERO);
    idx0 = offset + 1;
    if islogical(v)
        m = 0;
    else
        m = coder.internal.scalarEg(v);
    end
    if evenlength
        [m(1),v,ifirst,ilast] = coder.internal.quickselect(v,mid, ...
            idx0,vlen,stride,'A','I');
        if midm1 < ifirst
            % The output argument v, at least, is needed to secure the x =
            % foo(x) optimization to avoid data copies.
            [m1,~,~,~] = coder.internal.quickselect(v,midm1, ...
                idx0,ilast-1,stride,'A','I');
            [m(1),halvesHigh] = coder.internal.mid(m,cast(m1,'like',m));
        end
    else
        % Second output is required to secure a = foo(a) optimization.
        [m(1),~,~,~] = coder.internal.quickselect(v,mid,idx0,vlen,stride, ...
            'A','I');
    end
end
if RESTOREVATEND && numNaNs>ZERO
    % Put buffer back in original order
    for k = 1:numNaNsToBeReplaced
        v(offset+NaNInd(k)) = coder.internal.nan();
    end
end
        

%--------------------------------------------------------------------------

function [m,halvesHigh] = med01234(v,vlen,offset,stride)
% Quick calculation for vlen = 0, 1, 2, 3, or 4. Assumes NaNs have been
% removed and that offset + vlen <= numel(v).
coder.inline('always');

coder.internal.prefer_const(vlen,offset,stride);
if islogical(v)
    m = 0;
else
    m = coder.internal.scalarEg(v);
end
halvesHigh = int8(0);
% Since vlen is variable in the omitnan case even when the size of v is
% fixed, the compiler wants to include all the vlen cases handled below,
% even the ones that can't happen because v is too small. Here we help it
% to eliminate the cases that can't happen by defining some Booleans that
% indicate whether a statically-sized v even has enough elements for a
% given case to apply.
HAS1 = coder.const(~coder.internal.isConst(size(v)) || numel(v) >= 1);
HAS2 = coder.const(~coder.internal.isConst(size(v)) || numel(v) >= 2);
HAS3 = coder.const(~coder.internal.isConst(size(v)) || numel(v) >= 3);
HAS4 = coder.const(~coder.internal.isConst(size(v)) || numel(v) >= 4);
compMethod = 'A'; % auto
missingPlacement = 'I'; % ignore
if vlen == 0 || ~HAS1
    if isfloat(v)
        m = coder.internal.nan('like',v);
    end
elseif vlen == 1 && HAS1
    m(1) = v(offset + 1);
elseif vlen == 2 && HAS2
    [m(1),halvesHigh] = coder.internal.mid(v(offset + 1),v(offset + 1 + stride));
elseif vlen == 3 && HAS3
    i1 = offset + 1;
    i2 = offset + (1 + stride);
    i3 = offset + (1 + 2*stride);
    [~,j2] = coder.internal.sort3(i1,v(i1),i2,v(i2),i3,v(i3), ...
        compMethod,missingPlacement);
    m(1) = v(j2);
elseif HAS4
    i1 = offset + 1;
    i2 = offset + (1 + stride);
    i3 = offset + (1 + 2*stride);
    [j1,j2,j3] = coder.internal.sort3(i1,v(i1),i2,v(i2),i3,v(i3), ...
        compMethod,missingPlacement);
    i4 = offset + (1 + 3*stride);
    v4 = v(i4);
    if coder.internal.sortLT(v(j1),v4,compMethod,missingPlacement)
        if coder.internal.sortLT(v4,v(j3),compMethod,missingPlacement)
            [m(1),halvesHigh] = coder.internal.mid(v(j2),v4);
        else
            [m(1),halvesHigh] = coder.internal.mid(v(j2),v(j3));
        end
    else
        [m(1),halvesHigh] = coder.internal.mid(v(j1),v(j2));
    end
end

%--------------------------------------------------------------------------
