function [b,nshifts] = shiftdim(x,n)
%MATLAB Code Generation Library Function

%   Copyright 2006-2019 The MathWorks, Inc.
%#codegen

coder.internal.allowEnumInputs;
coder.internal.allowHalfInputs;
coder.internal.assert(nargin >= 1,'MATLAB:minrhs');
coder.internal.assert(~iscell(x),'Coder:toolbox:CellArraysNotSupported',mfilename);
ZERO = coder.internal.indexInt(0);
ndimsx = coder.internal.indexInt(eml_ndims(x));
IMAX = intmax(coder.internal.indexIntClass);
if nargin == 1
    if coder.internal.isConst(size(x)) && isscalar(x)
        ns = ZERO;
    else
        dim = coder.internal.constNonSingletonDim(x);
        coder.internal.assert(coder.internal.isConst(size(x,dim)) || ...
            isscalar(x) || ...
            size(x,dim) ~= 1, ...
            'Coder:toolbox:shiftdim_autoDimIncompatibility');
        ns = dim - 1;
    end
    negn = false;
else
    coder.internal.assert(~coder.isenum(n),'Coder:toolbox:shiftdim_3');
    coder.internal.assert(coder.internal.isConst(n), ...
        'Coder:toolbox:shiftdim_4');
    coder.internal.assert(isempty(n) || ...
        (coder.internal.isBuiltInNumeric(n) && isscalar(n) && ...
        isreal(n) && floor(n) == n && abs(double(n)) <= IMAX), ...
        'Coder:toolbox:shiftdim_invalidNshifts');
    if isempty(n) || n == 0
        ns = ZERO;
        negn = false;
    elseif n > 0
        coder.internal.assert(ndims(x) == ndimsx || ...
            n + 1 == coder.internal.constNonSingletonDim(x), ...
            'Coder:toolbox:shiftdim_wrongNDims');
        ns = coder.const(rem(coder.internal.indexInt(n),ndimsx));
        negn = false;
    else
        ns = coder.const(coder.internal.indexInt(abs(n)));
        negn = true;
    end
end
if ns == 0
    b = x;
    nshifts = 0;
elseif negn
    b = negativeShift(x,ns);
    nshifts = -double(ns);
else
    b = positiveShift(x,ns);
    nshifts = double(ns);
end

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

function b = negativeShift(x,ns)
coder.internal.allowEnumInputs;
ONE = coder.internal.indexInt(1);
ndimsx = coder.internal.indexInt(eml_ndims(x));
ndimsb = ns + ndimsx;
sz = cell(1,ndimsb);
for k = coder.unroll(1:ns)
    sz{k} = ONE;
end
for k = coder.unroll(1:ndimsx)
    sz{ns + k} = coder.internal.indexInt(size(x,k));
end
b = reshape(x,sz{:});

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

function b = positiveShift(x,ns)
coder.internal.allowEnumInputs;
coder.internal.prefer_const(ns);
ONE = coder.internal.indexInt(1);
ND = coder.internal.indexInt(eml_ndims(x));
sz = cell(1,ND);
% b = permute(x,[(ns + 1):ND,1:ns]);
for k = coder.unroll((ns + 1):ND)
    sz{k - ns} = coder.internal.indexInt(size(x,k));
end
offset = ND - ns;
for k = coder.unroll(1:ns)
    sz{offset + k} = coder.internal.indexInt(size(x,k));
end
if noMovement(x,ns)
    b = reshape(x,sz{:});
else
    b = coder.nullcopy(reshape(x,sz{:}));
    if coder.isRowMajor
        startDim = ONE;
    else
        startDim = ND;
    end
    b = looper(b,x,ns,startDim);
end

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

function b = looper(b,x,ns,dim,varargin)
coder.inline('always');
coder.internal.allowEnumInputs;
coder.internal.prefer_const(ns,dim);
ONE = coder.internal.indexInt(1);
ND = coder.internal.indexInt(eml_ndims(x));
if coder.const(dim >= ONE && dim <= ND)
    if coder.isRowMajor
        for k = ONE:size(x,dim)
            b = looper(b,x,ns,dim + 1,varargin{:},k);
        end
    else
        for k = ONE:size(x,dim)
            b = looper(b,x,ns,dim - 1,k,varargin{:});
        end
    end
else
    subsb = coder.nullcopy(varargin);
    for k = coder.unroll((ns + 1):ND)
        subsb{k - ns} = varargin{k};
    end
    offset = ND - ns;
    for k = coder.unroll(1:ns)
        subsb{offset + k} = varargin{k};
    end
    if iscell(x)
        b{subsb{:}} = x{varargin{:}};
    else
        b(subsb{:}) = x(varargin{:});
    end
end

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

function p = noMovement(x,ns)
coder.internal.allowEnumInputs;
coder.internal.prefer_const(ns);
ND = coder.internal.indexInt(eml_ndims(x));
p = true;
if ns > 0 && ~isempty(x)
    for k = coder.unroll((ns + 1):ND)
        p = p && size(x,k) == 1;
    end
end

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