function C = convn_kernel(n,C,iC0,A,iA0,B,iB0,shape,AContainsNonFinites)
%MATLAB Code Generation Private Function

%   Copyright 1984-2017 The MathWorks, Inc.

% C(I+J) = sum of A(I)*B(J) over suitable index vectors I and J. This can
% be viewed as the sum of 2-D convolutions by generating nested outer loops
% to run through all the suitable values of the subscripts for dimensions
% 3 and higher.
%#codegen
coder.inline('always');
coder.internal.prefer_const(shape);
if nargin < 9
    if coder.isRowMajor
        % No need to check since we will not be calling BLAS.
        AContainsNonFinites = true;
    else
        AContainsNonFinites = coder.internal.anyNonFinite(A);
    end
end
ZERO = coder.internal.indexInt(0);
% coder.const(n) forces the compiler to generate non-recursive code.
if ~(isempty(A) || isempty(B) || isempty(C))
    [cBegin,cEnd] = get_c_limits(coder.const(n),C,A,B,shape);
    if n <= 2
        [cBegin1,cEnd1] = get_c_limits(ones(coder.internal.indexIntClass),C,A,B,shape);
        C = eml_conv2(C,iC0,A,iA0,B,iB0,cBegin1,cEnd1,cBegin,cEnd,AContainsNonFinites);
    else
        nm1 = (n - 1);
        sA = coder.internal.prodsize(A,'below',n);
        sB = coder.internal.prodsize(B,'below',n);
        sC = coder.internal.prodsize(C,'below',n);
        for j = ZERO:(size(B,n) - 1)
            iB1 = iB0 + j*sB;
            for i = ZERO:(size(A,n) - 1)
                iA1 = iA0 + i*sA;
                cOffset = i + j;
                if cOffset >= cBegin && cOffset <= cEnd
                    iC1 = iC0 + sC*(cOffset - cBegin);
                    C = convn_kernel(nm1,C,iC1,A,iA1,B,iB1,shape,AContainsNonFinites);
                end
            end
        end
    end
end

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

function y = FULL
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('f'));

function y = SAME
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('s'));

function y = VALID %#ok
coder.inline('always');
y = coder.const(coder.internal.convShapeStrToID('v'));

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

function [cBegin,cEnd] = get_c_limits(n,C,A,B,shape)
% Calculate beginning and ending C array positions for dimension n.
coder.inline('always');
coder.internal.prefer_const(n,shape);
ZERO = coder.internal.indexInt(0);
ONE = coder.internal.indexInt(1);
if shape == FULL
    cBegin = ZERO;
    cEnd = coder.internal.indexInt(size(C,n)) - 1;
elseif shape == SAME
    cBegin = eml_rshift(coder.internal.indexInt(size(B,n)),ONE);
    cEnd = cBegin + coder.internal.indexInt(size(C,n)) - 1;
else % if shape == VALID
    cBegin = coder.internal.indexInt(size(B,n)) - 1;
    cEnd = coder.internal.indexInt(size(A,n)) - 1;
end

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

function C = eml_conv2(C,iC0,A,iA0,B,iB0, ...
    firstRowC,lastRowC,firstColC,lastColC,AContainsNonFinites)
% 2-Dimensional Convolution.
USEBLAS = ~coder.isRowMajor && ...
    (coder.target('mex') || coder.target('sfun'));
AXPYTHRESH = coder.internal.blas.threshold('xaxpy',class(C),isreal(C));
ZERO = coder.internal.indexInt(0);
ONE = coder.internal.indexInt(1);
ma = coder.internal.indexInt(size(A,1));
na = coder.internal.indexInt(size(A,2));
mb = coder.internal.indexInt(size(B,1));
nb = coder.internal.indexInt(size(B,2));
mc = lastRowC - firstRowC + 1;
if na < firstColC
    firstColB = firstColC - na + 1;
else
    firstColB = ZERO;
end
if nb <= lastColC
    lastColB = nb;
else
    lastColB = lastColC + 1;
end
if ma < firstRowC
    firstRowB = firstRowC - ma + 1;
else
    firstRowB = ZERO;
end
if mb <= lastRowC
    lastRowB = mb;
else
    lastRowB = lastRowC + 1;
end
% Perform convolution
for j = firstColB:(lastColB - 1)
    if j < firstColC
        firstColA = firstColC - j;
    else
        firstColA = ZERO;
    end
    if j + na - 1 < lastColC
        lastColA = na;
    else
        lastColA = lastColC - j + 1;
    end
    for k = firstColA:lastColA - 1
        if j + k > firstColC
            c_offset = j + k - firstColC;
        else
            c_offset = ZERO;
        end
        iC = iC0 + c_offset*mc;
        iA = iA0 + k*ma;
        iB = iB0 + firstRowB + j*mb;
        for i = firstRowB:(lastRowB - 1)
            if i < firstRowC
                firstRowA = firstRowC - i;
            else
                firstRowA = ZERO;
            end
            if i + ma <= lastRowC
                lastRowA = ma;
            else
                lastRowA = lastRowC - i + 1;
            end
            a_length = lastRowA - firstRowA;
            BiB = B(iB);
            % Put a run-time threshold on the potential use of external
            % BLAS functions for xAXPY.
            if coder.const(coder.isRowMajor && ...
                    coder.internal.isConstTrue(ismatrix(A)))
                % TODO: convert to 2-D indexing.
                aidx = iA + firstRowA - 1;
                cidx = iC - 1;
                for r = 1:a_length
                    C(cidx + 1) = C(cidx + 1) + BiB*A(aidx + 1);
                    aidx = aidx + 1;
                    cidx = cidx + 1;
                end
            elseif USEBLAS && ~(BiB == 0 && AContainsNonFinites) && ...
                    a_length >= AXPYTHRESH
                C = coder.internal.blas.xaxpy(a_length,BiB, ...
                    A,iA + firstRowA,ONE, ...
                    C,iC,ONE);
            else
                aidx = iA + firstRowA - 1;
                cidx = iC - 1;
                for r = 1:a_length
                    C(cidx + 1) = C(cidx + 1) + BiB*A(aidx + 1);
                    aidx = aidx + 1;
                    cidx = cidx + 1;
                end
            end
            iB = iB + 1;
            if i >= firstRowC
                iC = iC + 1;
            end
        end
    end
end

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