function y = issorted(x,varargin)
%MATLAB Code Generation Library Function
%
% Limitations:
%
%   1. Cell input for first argument is not supported

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

coder.internal.allowEnumInputs;
narginchk(1,inf);
nv = coder.internal.indexInt(nargin - 1);
coder.internal.assert(~iscell(x), ...
    'Coder:toolbox:CellArraysNotSupported',mfilename);
y = true;
if nv == 1 && coder.internal.isConst(varargin{1}) && ...
        coder.internal.isTextRow(varargin{1}) && ...
        strncmpi(varargin{1},'rows',eml_max(1,length(varargin{1})))
    y = issortedrows(x);
    return
end
ONE = coder.internal.indexInt(1);
idx = ONE;
% Extract DIM from VARARGIN.
if nv >= idx && isnumeric(varargin{idx})
    coder.internal.assertValidDim(varargin{idx});
    dim = coder.internal.indexInt(varargin{idx});
    coder.internal.assert(coder.internal.isConst(dim) || ...
        coder.const(~coder.internal.eml_option_eq('VariableSizing','DisableInInference')), ...
        'Coder:toolbox:dimNotConst');
    idx = idx + 1;
else
    dim = coder.internal.nonSingletonDim(x);
end
% Extract the sort direction from VARARGIN.
dir = ASCEND; % default
strict = false; % default
if nv >= idx && coder.internal.isTextRow(varargin{idx})
    coder.internal.assert(coder.internal.isConst(varargin{idx}), ...
        'Coder:toolbox:SortDirMustBeConstant');
    [dir,strict] = coder.internal.sortDirectionStringToChar(varargin{idx});
    if dir ~= UNRECOGNIZED
        idx = idx + 1;
    end
end
nleft = nv - idx + 1;
if dir == UNRECOGNIZED
    coder.internal.assert(nleft == 2 || nleft == 4, ...
        'CatalogID','MATLAB:issortedrows:DIRnotRecognized', ...
        'ReportedID','MATLAB:issorted:sortDirection');
    dir = ASCEND;
end
[comparisonMethod,missingPlacement] = ...
    coder.internal.parseSortNVPairs(varargin{idx:end});
nx = coder.internal.indexInt(size(x,dim));
if isempty(x)
    return
elseif nx == 1
    if strict
        y = coder.internal.reduceToScalar(x,@(p,x)and(p,~isnan(x)),true);
    end
    return
end
if coder.isRowMajor
    firstDim = coder.internal.indexInt(1);
else
    firstDim = coder.internal.indexInt(coder.internal.ndims(x));
end
if dir == MONOTONIC
    [y,~,~] = looper(y,x,dim,dir,comparisonMethod,missingPlacement, ...
        strict,firstDim);
else
    y = looper(y,x,dim,dir,comparisonMethod,missingPlacement, ...
        strict,firstDim);
end

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

function [y,missingPlacement,dir] = looper(y,x,dim,dir, ...
    comparisonMethod,missingPlacement, ...
    strict,thisDim,varargin)
coder.inline('always');
coder.internal.prefer_const(dim,comparisonMethod,missingPlacement, ...
    strict,thisDim,dir);
ND = coder.internal.indexInt(coder.internal.ndims(x));
ONE = coder.internal.indexInt(1);
TWO = coder.internal.indexInt(2);
if thisDim >= ONE && thisDim <= ND
    if dim == thisDim
        n = coder.internal.indexInt(size(x,dim)) - 1;
    else
        n = coder.internal.indexInt(size(x,thisDim));
    end
    for k = 1:n
        if coder.isRowMajor
            if nargout == 3
                [y,missingPlacement,dir] = looper(y,x,dim,dir, ...
                    comparisonMethod,missingPlacement,strict, ...
                    thisDim + 1,varargin{:},k);
            else
                y = looper(y,x,dim,dir, ...
                    comparisonMethod,missingPlacement,strict, ...
                    thisDim + 1,varargin{:},k);
            end
        else
            if nargout == 3
                [y,missingPlacement,dir] = looper(y,x,dim,dir, ...
                    comparisonMethod,missingPlacement,strict, ...
                    thisDim - 1,k,varargin{:});
            else
                y = looper(y,x,dim,dir, ...
                    comparisonMethod,missingPlacement,strict, ...
                    thisDim - 1,k,varargin{:});
            end
        end
        if ~y
            break
        end
    end
else
    x1 = x(varargin{:});
    subs = varargin;
    subs{dim} = subs{dim} + 1;
    x2 = x(subs{:});
    if strict
        if nargout == 3 && dir == MONOTONIC
            if coder.internal.sortLT(x1,x2,comparisonMethod,'I')
                dir = ASCEND;
            elseif coder.internal.sortLT(x2,x1,comparisonMethod,'I')
                dir = DESCEND;
            else
                dir = ASCEND;
                y = false;
            end
        elseif dir == DESCEND
            y = y & coder.internal.sortLT(x2,x1,comparisonMethod,'I');
        else
            y = y & coder.internal.sortLT(x1,x2,comparisonMethod,'I');
        end
    elseif nargout == 3 && dir == MONOTONIC
        if missingPlacement == 'F'
            % If MissingPlacement is 'first', the sort direction cannot
            % be determined when x1 == x2 or x1 is NaN.
            if isequal(x1,x2) || isnan(x1)
            elseif isnan(x2)
                dir = ASCEND;
                y = false;
            elseif coder.internal.sortLT(x1,x2,comparisonMethod,'I')
                dir = ASCEND;
            else
                dir = DESCEND;
            end
        elseif missingPlacement == 'L'
            if isequal(x1,x2) || isnan(x2)
            elseif isnan(x1)
                dir = ASCEND;
                y = false;
            elseif coder.internal.sortLT(x1,x2,comparisonMethod,'I')
                dir = ASCEND;
            else
                dir = DESCEND;
            end
        else % if missingPlacement == 'A'
            % If x1 == x2 or both x1 and x2 are NaN, the sort direction
            % cannot be determined yet. However if x1 is NaN and x2 is not
            % NaN, then the sort direction must be descending.
            if isequal(x1,x2)
            elseif isnan(x1)
                missingPlacement = 'F';
                dir = DESCEND;
            elseif isnan(x2)
                missingPlacement = 'L';
                dir = ASCEND;
            elseif coder.internal.sortLT(x1,x2,comparisonMethod,'I')
                missingPlacement = 'L';
                dir = ASCEND;
            else
                missingPlacement = 'F';
                dir = DESCEND;
            end
        end
    else
        y = y & coder.internal.sortLE([x1;x2],dir,ONE,TWO, ...
            comparisonMethod,missingPlacement);
    end
end

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

function dir = ASCEND
coder.inline('always');
[dir,~] = coder.const(@coder.internal.sortDirectionStringToChar,'ascend');

function dir = DESCEND
coder.inline('always');
[dir,~] = coder.const(@coder.internal.sortDirectionStringToChar,'descend');

function dir = MONOTONIC
coder.inline('always');
[dir,~] = coder.const(@coder.internal.sortDirectionStringToChar,'monotonic');

function dir = UNRECOGNIZED
coder.inline('always');
[dir,~] = coder.const(@coder.internal.sortDirectionStringToChar,'unrecognized');

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