function [b,idx] = extremeKElements(minkOrMaxk,a,K,varargin)
%MATLAB Code Generation Library Function

%   Copyright 2017=2020 The MathWorks, Inc.
%#codegen

if nargout == 2
    coder.inline('always');
end
narginchk(3,6);
coder.internal.prefer_const(minkOrMaxk,K,varargin);
coder.internal.assert(isnumeric(a) || islogical(a) || ischar(a), ...
    'Coder:toolbox:unsupportedClass',mfilename,class(a));
nargs = coder.internal.indexInt(length(varargin));
argidx = coder.internal.indexInt(1);
if argidx <= nargs && isnumeric(varargin{1})
    coder.internal.assertValidDim(varargin{1});
    dim = coder.internal.indexInt(varargin{1});
    argidx = argidx + 1;
else
    dim = coder.internal.constNonSingletonDim(a);
    coder.internal.assert(isscalar(a) || size(a,dim) ~= 1, ...
        'Coder:toolbox:autoDimIncompatibility');
end
comparisonMethod = coder.internal.parseSortNVPairs(varargin{argidx:end});
coder.internal.assert(isnumeric(K) && isscalar(K) && isreal(K) && ...
    floor(K) == K && K >= 0, ...
    'CatalogID','MATLAB:topk:InvalidK', ...
    'ReportedID',['MATLAB:',minkOrMaxk,':InvalidK']);
if K <= size(a,dim)
    k = coder.internal.indexInt(K);
else
    k = coder.internal.indexInt(size(a,dim));
end
if coder.const(strcmp(minkOrMaxk,'maxk'))
    sortdir = 'd';
else
    sortdir = 'a';
end
ROWCASE = coder.internal.isConstTrue(isrow(a)) && ...
    coder.internal.isConstTrue(dim == 2);
COLCASE = coder.internal.isConstTrue(iscolumn(a)) && ...
    coder.internal.isConstTrue(dim == 1);
if nargout == 1
    AZERO = coder.internal.scalarEg(a);
    f = @(x)exkb(x,k,sortdir,comparisonMethod);
    b = coder.internal.applyVectorFunction(f,a,dim,k,AZERO);
elseif coder.const(ROWCASE || COLCASE)
    [idx,b] = exkib(a,k,sortdir,comparisonMethod);
else
    IZERO = coder.internal.indexInt(0);
    f = @(x)exkib(x,k,sortdir,comparisonMethod);
    idx = coder.internal.applyVectorFunction(f,a,dim,k,IZERO);
    b = firstKElements(a,dim,k,idx);
end

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

function b = exkb(a,k,sortdir,comparisonMethod)
% Local extreme K method returning the output data vector and no index
% vector.
coder.internal.prefer_const(k,sortdir,comparisonMethod);
[~,b] = exkib(a,k,sortdir,comparisonMethod);

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

function [idx,b] = exkib(a,k,sortdir,comparisonMethod)
% Local extreme K method returning the index vector first.
coder.internal.prefer_const(k,sortdir,comparisonMethod);
ONE = coder.internal.indexInt(1);
n = coder.internal.indexInt(length(a));
if coder.internal.isConstTrue(isrow(a))
    idx = zeros(1,k,coder.internal.indexIntClass);
    b = eml_expand(coder.internal.scalarEg(a),1,k);
else
    idx = zeros(k,1,coder.internal.indexIntClass);
    b = eml_expand(coder.internal.scalarEg(a),k,1);
end
if k == 0
elseif k > 64 && k > eml_rshift(n,coder.internal.indexInt(6))
    % It can be faster to use mergesort if we're going to return a
    % substantial part of the sorted array. The cutoff k > n/64 is not
    % optimal, rather selected for simplicity.
    itmp = coder.internal.sortIdx(a,sortdir,comparisonMethod,'L');
    for j = ONE:k
        i = itmp(j);
        idx(j) = i;
        b(j) = a(i);
    end
else
    % Initialize the buffer.
    for j = ONE:k
        [b,~,idx] = coder.internal.sortedInsertion(a(j),j,b,j-1,k,idx, ...
            sortdir,comparisonMethod,'L');
    end
    % Process the remaining elements.
    for j = k+1:n
        [b,~,idx] = coder.internal.sortedInsertion(a(j),j,b,k,k,idx, ...
            sortdir,comparisonMethod,'L');
    end
end
%--------------------------------------------------------------------------
