function [A,center,scale] = rescaleKernel(A,a,b,inputMin,inputMax)
%MATLAB Code Generation Private Function

%   Copyright 2020 The MathWorks, Inc.
%#codegen

coder.internal.prefer_const(a,b,inputMin,inputMax);
if isempty(A)
    if nargout > 1
        center = zeros(min(1,size(A,1)),0,'like',A);
        scale = zeros(min(1,size(A,1)),0,'like',A);
    end
    return
end
SCALARA = coder.internal.isConstTrue(isscalar(a));
SCALARB = coder.internal.isConstTrue(isscalar(b));
SCALARIMIN = coder.internal.isConstTrue(isscalar(inputMin));
SCALARIMAX = coder.internal.isConstTrue(isscalar(inputMax));
% Determine where to center the problem based on the input range
if SCALARA && SCALARB && SCALARIMIN && SCALARIMAX
    sigma = max(min(0,inputMax),inputMin);
    A = A - sigma;
    iMin = inputMin - sigma;
    iMax = inputMax - sigma;
    % Scale to prevent overflow/underflow
    [~,e1] = log2(max(abs(iMax),abs(iMin)));
    r1 = pow2(e1 - 1);
    [~,e2] = log2(max(abs(a),abs(b)));
    r2 = pow2(e2 - 1);
    r3 = pow2(fix((e1 + e2)/2) - 1);
    % Regularize constant values to return lowerbound of output range.
    if iMin == iMax
        A(~isnan(A)) = a;
        if nargout
            center = zeros(1,'like',A);
            scale = ones(1,'like',A);
        end
        return
    end
    c1 = iMax/r1;
    c2 = iMin/r1;
    z = (c1*(a/r3) - c2*(b/r3))/(c1 - c2);
    c1 = b/r2;
    c2 = iMax/r3 - iMin/r3;
    s = (c1 - a/r2)/c2/r3;
    t = (r3/r2)*z;
    A = r2*(s*A + t);
    % Force output to be within the requested output range.
    A(A < a) = a;
    A(A > b) = b;
    if nargout > 1
        center = sigma - t/s;
        scale = 1/(r2*s);
    end
else
    sigma = bsxfun(@max,min(0,inputMax),inputMin);
    A = bsxfun(@minus,A,sigma);
    iMin = bsxfun(@minus,inputMin,sigma);
    iMax = bsxfun(@minus,inputMax,sigma);
    % Scale to prevent overflow/underflow
    [~,e1] = log2(max(abs(iMax),abs(iMin)));
    [~,e2] = log2(bsxfun(@max,abs(a),abs(b)));
    SCALARE1 = coder.internal.isConstTrue(isscalar(e1));
    SCALARE2 = coder.internal.isConstTrue(isscalar(e2));
    % Force compatible sizing.
    if SCALARE1 || SCALARE2
        % Only scalar expansion is needed.
        r1 = pow2(e1 - 1);
        r2 = pow2(e2 - 1);
        r3 = pow2(fix((e1 + e2)/2) - 1);
        % Regularize constant values to return lowerbound of output range.
        constReg = (iMin == iMax);
    else
        % r3 combines the size info from all parameters.
        r3 = pow2(fix(bsxfun(@plus,e1,e2)/2) - 1);
        r1 = bsxfun(@plus, ...
            pow2(e1 - 1), ...
            zeros(size(r3),'like',A));
        r2 = bsxfun(@plus, ...
            pow2(e2 - 1), ...
            zeros(size(r3),'like',A));
        % Regularize constant values to return lowerbound of output range.
        constReg = bsxfun(@or,iMin == iMax,false(size(r3)));
    end
    z = ( ...
        (iMax./r1).*(a./r3) - ...
        (iMin./r1).*(b./r3) + ...
        (constReg./r1).*(a./r3) ...
        )./( ...
        (iMax./r1) - ...
        (iMin./r1) + ...
        (constReg./r1) ...
        );
    s = ( ...
        (b./r2) - ...
        (a./r2) ...
        )./( ...
        (iMax./r3) - ...
        (iMin./r3) + ...
        (constReg./r3) ...
        )./r3;
    t = (r3./r2).*z;
    % R = r2.*(s.*A + t) with vector expansion.
    T = bsxfun(@times,A,s);
    A = bsxfun(@plus,T,t);
    T = bsxfun(@times,A,r2);
    minnan = @(x,y)min(x,y,'includenan');
    maxnan = @(x,y)max(x,y,'includenan');
    A = bsxfun(maxnan,T,a);
    A = bsxfun(minnan,A,b);
    if nargout > 1
        center = bsxfun(@minus,sigma,bsxfun(@rdivide,t,s));
        scale = bsxfun(@rdivide,1,bsxfun(@times,r2,s));
    end
end
