function [zero,dim,dimsupplied,omitnan,isvdim,userSelectedOutputType] = ...
    process_sumprod_inputs(opname,x,varargin)
%MATLAB Code Generation Private Function

%   Used to sort out inputs of SUM, PROD, and MEAN, e.g. sum(x),
%   sum(x,dim), sum(x,flag), or sum(x,dim,flag). ZERO is 0 of the output
%   type, and DIM is the dimension along which to perform the operation.
%   The third output, DIMSUPPLIED, is TRUE if DIM was an explicit input,
%   FALSE if DIM was inferred using coder.internal.constNonSingletonDim.
%   The last output, OMITNAN, is true if NaNs are to be excluded, otherwise
%   false. All outputs of this function are compile-time constants.

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

coder.inline('always');
coder.internal.allowHalfInputs;
coder.internal.prefer_const(opname,varargin);
narginchk(2,5);
if nargin >= 3 && coder.internal.isVectorDim(varargin{1})
    dimsupplied = true;
    coder.internal.assert(coder.internal.isConst(varargin{1}), ...
        'Coder:toolbox:dimNotConst');
    if isnumeric(varargin{1})
        dim = varargin{1};
    else
        dim = char(varargin{1});
    end
    isvdim = true;
    firstflag = 2;
elseif nargin >= 3 && isnumeric(varargin{1})
    dimsupplied = true;
    coder.internal.assert(coder.internal.isConst(varargin{1}), ...
        'Coder:toolbox:dimNotConst');
    coder.internal.assertValidDim(varargin{1});
    dim = coder.internal.indexInt(varargin{1});
    isvdim = false;
    firstflag = 2;
else
    dim = coder.internal.constNonSingletonDim(x);
    dimsupplied = false;
    isvdim = false;
    firstflag = 1;
end
[acctype,nanflag,userSelectedOutputType] = process_flags(opname, ...
    varargin{firstflag:end});
% By request, we require an explicit choice, either 'native' or 'double',
% to be supplied when computing sums and the target is 'HDL'.
coder.internal.assert(~coder.target('hdl') || isa(x,'float') || ...
    userSelectedOutputType || strcmp(opname,'prod'), ...
    'Coder:toolbox:sum_hdlRequiresFlag',class(x));
coder.internal.assert(~(acctype == NATIVE && ischar(x)), ...
    'Coder:toolbox:UnsupportedCharWithNative');
omitnan = (nanflag == OMITNAN);
if acctype == DOUBLE || (acctype == DEFAULT && ~isfloat(x))
    zero = double(coder.internal.scalarEg(x));
else
    zero = coder.internal.scalarEg(x);
end

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

function [acctype,nanflag,userSelectedOutputType] = ...
    process_flags(opname,varargin)
coder.internal.prefer_const(opname,varargin);
[accidx,nanidx,nacc,nnan,nunk] = coder.const(@findflags,varargin{:});
coder.internal.assert(nacc <= 1,'MATLAB:sum:repeatedFlagOutType');
coder.internal.assert(nnan <= 1,'MATLAB:sum:repeatedFlagNaN');
if coder.const(strcmp(opname,'prod'))
    coder.internal.assert(nunk == 0,'MATLAB:prod:unknownFlag');
else
    coder.internal.assert(nunk == 0,'MATLAB:sum:unknownFlag');
end
userSelectedOutputType = accidx > 0;
if accidx > 0
    acctype = coder.const(convertAcctypeString(varargin{accidx}));
else
    acctype = DEFAULT;
end
if nanidx > 0
    nanflag = coder.const(convertNaNFlagString(varargin{nanidx}));
else
    nanflag = INCLUDENAN;
end

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

function [accidx,nanidx,nacc,nnan,nunk] = findflags(varargin)
coder.internal.prefer_const(varargin);
ZERO = coder.internal.indexInt(0);
accidx = ZERO;
nanidx = ZERO;
nacc = ZERO;
nnan = ZERO;
nunk = ZERO;
for k = coder.unroll(1:nargin)
    vk = varargin{k};
    coder.internal.assert(coder.internal.isConst(vk), ...
        'Coder:toolbox:FlagMustBeConst');
    if coder.const(convertAcctypeString(vk) >= 0)
        nacc = nacc + 1;
        accidx = coder.internal.indexInt(k);
    elseif coder.const(convertNaNFlagString(vk) >= 0)
        nnan = nnan + 1;
        nanidx = coder.internal.indexInt(k);
    else
        nunk = nunk + 1;
    end
end

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

function acctype = convertAcctypeString(arg)
coder.internal.prefer_const(arg);
n = eml_max(strlength(arg),1);
if coder.const(strncmpi(arg,'native',n))
    acctype = NATIVE;
elseif coder.const(strncmpi(arg,'double',eml_max(n,2)))
    acctype = DOUBLE;
elseif coder.const(strncmpi(arg,'default',eml_max(n,2)))
    acctype = DEFAULT;
else
    acctype = UNKNOWN;
end

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

function nanflag = convertNaNFlagString(arg)
coder.internal.prefer_const(arg);
matchParam = @coder.internal.matchStringParameter;
if coder.const(matchParam(arg,'includenan') || matchParam(arg,'includemissing'))
    nanflag = INCLUDENAN;
elseif coder.const(matchParam(arg,'omitnan') || matchParam(arg,'omitmissing'))
    nanflag = OMITNAN;
else
    nanflag = UNKNOWN;
end

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

function n = UNKNOWN
coder.inline('always');
n = int8(-1);

function n = DEFAULT
coder.inline('always');
n = int8(0);

function n = NATIVE
coder.inline('always');
n = int8(1);

function n = DOUBLE
coder.inline('always');
n = int8(2);

function n = INCLUDENAN
coder.inline('always');
n = int8(3);

function n = OMITNAN
coder.inline('always');
n = int8(4);

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