function mustBeInRange(value, lowerBound, upperBound, varargin)
%MATLAB Code Generation Library Function

%   Copyright 2022 The MathWorks, Inc.
%#codegen

narginchk(3,5)
coder.internal.prefer_const(varargin)

coder.internal.assert(isnumeric(value) || islogical(value), ...
    'MATLAB:validators:mustBeNumericOrLogical');

coder.internal.assert(isreal(value), 'MATLAB:validators:mustBeReal');

validateBound(lowerBound, 'MATLAB:validatorUsage:invalidLowerBound');
validateBound(upperBound, 'MATLAB:validatorUsage:invalidUpperBound');

[includeLower,includeUpper] = getIntervalType(varargin{:});

args = {'ReportedID','MATLAB:validators:mustBeInRange', ...
    string(lowerBound), string(upperBound)};
if includeLower
    if includeUpper
        coder.internal.assert(all(value >= lowerBound, 'all') && all(value <= upperBound, 'all'), ...
            'CatalogID',"MATLAB:validators:LeftClosedRightClosed",args{:});
    else
        coder.internal.assert(all(value >= lowerBound, 'all') && all(value < upperBound, 'all'), ...
            'CatalogID',"MATLAB:validators:LeftClosedRightOpen",args{:});
    end
else
    if includeUpper
        coder.internal.assert(all(value > lowerBound, 'all') && all(value <= upperBound, 'all'), ...
            'CatalogID',"MATLAB:validators:LeftOpenRightClosed",args{:});
    else
        coder.internal.assert(all(value > lowerBound, 'all') && all(value < upperBound, 'all'), ...
            'CatalogID',"MATLAB:validators:LeftOpenRightOpen",args{:});
    end
end
end


function validateBound(bound, errorId)
coder.inline('always')
coder.internal.assert(((isnumeric(bound) && isreal(bound)) ||isa(bound,'logical')) &&...
    isscalar(bound), errorId, 'mustBeInRange');
end


function [includeLower, includeUpper] = getIntervalType(varargin)
coder.internal.prefer_const(varargin)
includeLower = true;
includeUpper = true;

if ~isempty(varargin)
    flag1 = varargin{1};
    validoptions = {'inclusive','exclusive','exclude-lower','exclude-upper'};
    option1 = validatestring(flag1,validoptions,mfilename);
    [includeLower,includeUpper] = determineBoundaryType(option1);
    
    if nargin > 1
        flag2 = varargin{2};
        option2 = validatestring(flag2,validoptions,mfilename);
        coder.internal.assert((strcmp(option1,'exclude-lower') && strcmp(option2,'exclude-upper')) ||...
                (strcmp(option1,'exclude-upper') && strcmp(option2,'exclude-lower')), ...
                'MATLAB:validatorUsage:ConflictingBoundaryOptions',option1,option2);
        includeLower = false;
        includeUpper = false;
    end
end

end

function [iL,iU] = determineBoundaryType(option)
coder.internal.prefer_const(option)
if strcmpi(option,'inclusive')
    iL = true;
    iU = true;
elseif strcmpi(option,'exclusive')
    iL = false;
    iU = false;
elseif strcmpi(option,'exclude-lower')
    iL = false;
    iU = true;
else
    iL = true;
    iU = false;
end
end
