function mustBeInRange(value, lowerBound, upperBound, inclusiveFlags)
%MUSTBEINRANGE Validate that value is in the specified range
%   MUSTBEINRANGE(A,LOWER,UPPER) throws an error if any element of A is not
%   within the range defined by LOWER and UPPER. A value is within the
%   range if it is greater or equal to LOWER, and less than or equal to
%   UPPER.
%
%   MUSTBEINRANGE(A,LOWER,UPPER,BOUNDFLAG1,BOUNDFLAG2) Optional flags
%   BOUNDFLAG1 and BOUNDFLAG2 indicate if upper or lower bound is
%   included in the range. The values of the optional flags must be one of
%   the following:
%      "inclusive"
%      "exclusive"
%      "exclude-lower"
%      "exclude-upper"
%   "inclusive" is the default.
%   Use at most two of these values to indicate whether the lower bound
%   and upper bound should be excluded or included from a range. The only
%   valid combination of these flags are "exclude-lower" and
%   "exclude-upper".
%
%   For example, the following call to mustBeInRange validates that A must
%   be greater than 0, and less or equal to 100:
%
%   mustBeInRange(A,0,100,"exclude-lower");
%
%   MATLAB calls the lt, gt, le, ge functions when comparing a value with
%   boundary values.
%
%   Class support:
%   All numeric or logical classes
%
%   See also GE, GT, LE, LT.
 
%   Copyright 2020 The MathWorks, Inc.

    arguments
        value
        lowerBound
        upperBound
    end
    arguments(Repeating)
        inclusiveFlags (1,1) matlab.internal.validation.BoundInclusivity
    end

    if ~isnumeric(value) && ~islogical(value)
        throwAsCaller(createValidatorException('MATLAB:validators:mustBeNumericOrLogical'));
    end
    
    if ~isreal(value)
        throwAsCaller(MException(message('MATLAB:validators:mustBeReal')));
    end
    
    if  ~((isnumeric(lowerBound) && isreal(lowerBound)) || isa(lowerBound, 'logical')) || ~isscalar(lowerBound)
        error(message('MATLAB:validatorUsage:invalidLowerBound', 'mustBeInRange'));
    end
    
    if  ~((isnumeric(upperBound) && isreal(upperBound)) || isa(upperBound, 'logical')) || ~isscalar(upperBound)
        error(message('MATLAB:validatorUsage:invalidUpperBound', 'mustBeInRange'));
    end

    boundInclusivity = [1,1];
    if nargin > 3
        lowerSet = 0;
        upperSet = 0;
        strflags = cellfun(@(f)f.Flag,inclusiveFlags);

        for i=1:numel(strflags)
            switch strflags(i)
                case "inclusive"
                    if ~lowerSet && ~upperSet
                        lowerSet = i;
                        upperSet = i;
                    else
                        error(message('MATLAB:validatorUsage:ConflictingBoundaryOptions', strflags(i-1), strflags(i)));
                    end
                case "exclusive"
                    if ~lowerSet && ~upperSet
                        lowerSet = i;
                        upperSet = i;
                        boundInclusivity = [0,0];
                    else
                        error(message('MATLAB:validatorUsage:ConflictingBoundaryOptions', strflags(i-1), strflags(i)));
                    end
                case "exclude-lower"
                    if ~lowerSet
                        lowerSet = i;
                        boundInclusivity(1) = 0;
                    else
                        error(message('MATLAB:validatorUsage:ConflictingBoundaryOptions', strflags(lowerSet), strflags(i)));
                    end
                case "exclude-upper"
                    if ~upperSet
                        upperSet = i;
                        boundInclusivity(2) = 0;
                    else
                        error(message('MATLAB:validatorUsage:ConflictingBoundaryOptions', strflags(upperSet), strflags(i)));
                    end
            end
        end
    end
    
    if boundInclusivity(1) == 1
        if boundInclusivity(2) == 1
            if all(value >= lowerBound & value <= upperBound, 'all')
                return;
            end
            messageID = "MATLAB:validators:LeftClosedRightClosed";
        else
            if all(value >= lowerBound & value < upperBound, 'all')
                return;
            end
            messageID = "MATLAB:validators:LeftClosedRightOpen";
        end
    else
        if boundInclusivity(2) == 1
            if all(value > lowerBound & value <= upperBound, 'all')
                return;
            end
            messageID = "MATLAB:validators:LeftOpenRightClosed";
        else
            if all(value > lowerBound & value < upperBound, 'all')
                return;
            end
            messageID = "MATLAB:validators:LeftOpenRightOpen";
        end
    end

    messageObj = message(messageID, num2str(lowerBound), num2str(upperBound));
    throwAsCaller(MException('MATLAB:validators:mustBeInRange', messageObj));
end
