function y = quantize(x, varargin)
%QUANTIZE(x, ...) Quantize fixed-point numbers.

% Copyright 2011-2014 The MathWorks, Inc.

%#codegen

coder.internal.prefer_const(varargin);

if nargin < 1
    eml_invariant(false, 'MATLAB:narginchk:notEnoughInputs');
elseif nargin > 6
    eml_invariant(false, 'MATLAB:narginchk:tooManyInputs');
end

if isfloat(x)
    y = x;
elseif (nargin > 1)
    % At least one varargin is provided
    if isnumerictype(varargin{1})
        % Caller syntax: y = quantize(x,Ty,rm,om)
        if nargin > 4
            eml_invariant(false, 'MATLAB:narginchk:tooManyInputs');
        end
        
        if isscaleddouble(x)
            Tx = eml_typeof(x);
            Ta = varargin{1};
            Ty = numerictype('DataType',Tx.DataType,'Signed',Ta.Signed,'WordLength',Ta.WordLength,'FractionLength',Ta.FractionLength);
        elseif isfixed(x)
            Ty = varargin{1};
        else
            eml_invariant(false, 'fixed:fi:unsupportedDataType', x.DataType);
        end
        
        if nargin > 2
            rm = varargin{2};
            if nargin > 3
                y = q(x,Ty,rm,varargin{3});
            else
                y = q(x,Ty,rm,'wrap');
            end
        else
            y = q(x,Ty,'floor','wrap');
        end
    elseif isscalar(varargin{1}) && ~isempty(varargin{1}) && isreal(varargin{1}) && (islogical(varargin{1}) || isnumeric(varargin{1}))
        % Caller syntax: y = quantize(x,s,wl,fl,rm,om)
        if isscaleddouble(x)
            Tx = eml_typeof(x);
            if nargin > 3
                eml_invariant(isnumeric(varargin{2}) && isscalar(varargin{2}), ...
                          'fixed:numerictype:invalidWLInputArg');
                eml_invariant(isnumeric(varargin{3}) && isscalar(varargin{3}), ...
                          'fixed:numerictype:invalidFLInputArg');
                Ty = numerictype(...
                    'DataType',       Tx.DataType,...
                    'Signed',         varargin{1},...
                    'WordLength',     double(varargin{2}),...
                    'FractionLength', double(varargin{3}));
            elseif nargin > 2
                eml_invariant(isnumeric(varargin{2}) && isscalar(varargin{2}), ...
                          'fixed:numerictype:invalidWLInputArg');
                Ty = numerictype(...
                    'DataType',       Tx.DataType,...
                    'Signed',         varargin{1},...
                    'WordLength',     double(varargin{2}),...
                    'FractionLength', (double(varargin{2}) - 1));
            else
                Ty = numerictype(...
                    'DataType',       Tx.DataType,...
                    'Signed',         varargin{1},...
                    'WordLength',     16,...
                    'FractionLength', 15);
            end
        elseif isfixed(x)
            if nargin > 3
                eml_invariant(isnumeric(varargin{2}) && isscalar(varargin{2}), ...
                          'fixed:numerictype:invalidWLInputArg');
                eml_invariant(isnumeric(varargin{3}) && isscalar(varargin{3}), ...
                          'fixed:numerictype:invalidFLInputArg');
                Ty = numerictype(varargin{1}, ...
                    double(varargin{2}), double(varargin{3}));
            elseif nargin > 2
                eml_invariant(isnumeric(varargin{2}) && isscalar(varargin{2}), ...
                          'fixed:numerictype:invalidWLInputArg');
                Ty = numerictype(varargin{1}, ...
                    double(varargin{2}), (double(varargin{2}) - 1));
            else
                Ty = numerictype(varargin{1}, 16, 15);
            end
        else
            eml_invariant(false, 'fixed:fi:unsupportedDataType', x.DataType);
        end
        
        if nargin > 4
            rm = varargin{4};
            if nargin > 5
                y = q(x,Ty,rm,varargin{5});
            else
                y = q(x,Ty,rm,'wrap');
            end
        else
            y = q(x,Ty,'floor','wrap');
        end
    else
        eml_invariant(false, 'fixed:numerictype:invalidInputArg', varargin{1});
    end
else
    % Use all defaults (no varargin provided)
    if isscaleddouble(x)
        Tx = eml_typeof(x);
        Ty = numerictype(...
            'DataType',       Tx.DataType,...
            'Signed',         true,...
            'WordLength',     16,...
            'FractionLength', 15);
        
        y  = q(x,Ty,'floor','wrap');
        
    elseif isfixed(x)
        y  = q(x, numerictype(1,16,15), 'floor', 'wrap');
    else
        eml_invariant(false, ...
            'fixed:fi:unsupportedDataType', x.DataType);
    end
end

function y = q(x,Ty,rm,om)
F    = fimath('OverflowMode',om,'RoundMode',rm);
temp = eml_cast(x,Ty,F);
y    = eml_fimathislocal(temp,false);
