function c = bitconcat(varargin)
% MATLAB Code Generation Library function.
%
% CONCAT Perform concatenation of two fixpt input operands.
%
% Both a and b must be fixed point inputs
% output type cannot be more than 32 bits
% both a and b can be scalars or vectors
% if both are vectors then their size should match

%   Copyright 2002-2014 The MathWorks, Inc.
%#codegen

% To make sure the number of the input arguments is right

if eml_ambiguous_types
    for i = 1:length(varargin)
        if ~isscalar(varargin{i})
            c = coder.ignoreConst(reshape(zeros(size(varargin{i})), size(varargin{i})));
            return;
        end;
    end
    c = coder.ignoreConst(reshape(zeros(size(varargin{1})), size(varargin{1})));
    return;
end

% Error if any input argument is variable sized
for idx = 1:nargin
    eml_invariant(eml_is_const(size(varargin{idx})), ...
        'Coder:toolbox:NoVarSizeInputs', sprintf('%d',(idx)));
end

if (nargin == 1)
    c = bitconcat_unary(varargin{1});
else
    c = bitconcat_nary(varargin{:});
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = bitconcat_unary(a)

bitconcat_checkarg(a);
n = numel(a);
if n<2
    T = numerictype(0, a.WordLength, 0);
    varargout{1} = reinterpretcast(a,T);
else
    t = eml_typeof(a(n));
    wlen = t.WordLength;
    
    maxWL = getFixedPointWidthLimit();
    eml_invariant((wlen * n) <= maxWL, ...
                  'fixed:coder:outputWLExceedsMaxWLLimit', maxWL);
    
    % Concatenate the inputs, using varargout to accumulate the intermediate results.
    % The loop counts downwards, so that it creates a series of assignments like this:
    %
    %      out4 = in4; // Initial assignment, created before the start of the loop.
    %      out3 = eml_concat(in3,out4);
    %      out2 = eml_concat(in2,out3);
    %      out1 = eml_concat(in1,out2);
    %
    varargout{n} = a(n);
    for i = coder.unroll(n-1:-1:1)
        varargout{i} = eml_bitconcat(a(i), varargout{i+1});
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function varargout = bitconcat_nary(varargin)

maxWL = getFixedPointWidthLimit();

n = nargin;
Fm = eml_fimath(varargin{1});
fmIsLocal = coder.const(eml_fimathislocal(varargin{1}));

bitconcat_checkarg(varargin{n});
varargout{n} = varargin{n};

% Concatenate the inputs, using varargout to accumulate the intermediate results.
% The loop counts downwards, so that it creates a series of assignments like this:
%
%      out4 = in4; // Initial assignment, created before the start of the loop.
%      out3 = eml_concat(in3,out4);
%      out2 = eml_concat(in2,out3);
%      out1 = eml_concat(in1,out2);
%
for i = coder.unroll(n-1:-1:1)
    bitconcat_checkarg(varargin{i});
    outWlen = bitconcat_getwordlength(varargin{i}) + bitconcat_getwordlength(varargout{i+1});
    eml_invariant(outWlen <= maxWL, ...
        'fixed:coder:outputWLExceedsMaxWLLimit', maxWL);
    % Create a binary bitconcat. The most common case is:
    %     varargout{i} = eml_bitconcat(varargin{i}, varargout{i+1});
    % However, either varargin{i} or varargout{i+1} could be non-scalar, so there
    % are four cases to consider.
    if isscalar(varargin{i})
        if isscalar(varargout{i+1})
            varargout{i} = eml_bitconcat(varargin{i}(1), varargout{i+1}(1));
        else
            if coder.const(fmIsLocal)
                varargout{i} = fi(zeros(size(varargout{i+1})), 'numerictype', numerictype(0, outWlen, 0), 'fimath', Fm);
            else
                varargout{i} = fi(zeros(size(varargout{i+1})), 'numerictype', numerictype(0, outWlen, 0));
            end
            for k = 1:numel(varargout{i})
                varargout{i}(k) = eml_bitconcat(varargin{i}(1), varargout{i+1}(k));
            end
        end
    else
        if coder.const(fmIsLocal)
            varargout{i} = fi(zeros(size(varargin{i})), 'numerictype', numerictype(0, outWlen, 0), 'fimath', Fm);
        else
            varargout{i} = fi(zeros(size(varargin{i})), 'numerictype', numerictype(0, outWlen, 0));
        end
        if isscalar(varargout{i+1})
            for k = 1:numel(varargout{i})
                varargout{i}(k) = eml_bitconcat(varargin{i}(k), varargout{i+1}(1));
            end
        else
            eml_invariant(coder.internal.scalexpCompatible(varargin{i},varargout{i+1}), ...
                'fixed:fi:DimAgree');
            for k = 1:numel(varargout{i})
                varargout{i}(k) = eml_bitconcat(varargin{i}(k), varargout{i+1}(k));
            end
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function wl = bitconcat_getwordlength(x)
    eml_transient;
    y = eml_typeof(x);
    wl = y.WordLength;   

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function bitconcat_checkarg(a)

eml_invariant(isfi(a), 'fixed:fi:inputArgsNotFis');
eml_invariant(isreal(a), ...
    'fixed:fi:unsupportedComplexArguments', 'BITCONCAT');

if ~isfixed(a)
    % non fi-fixedpoint not supported
    eml_invariant(false, ...
        'fixed:coder:fiFcnDTypeErrorFixPtOnly','BITCONCAT');
end

eml_invariant(~eml_isslopebiasscaled(a), ...
    'fixed:coder:slopeBiasInputsNotSupported');
