function t = strcat(varargin)
%MATLAB Code Generation Library Function

% Copyright 2023 The MathWorks, Inc.
%#codegen

narginchk(1,inf);

hasCellArrayInputs = false;
for i = 1:nargin
    coder.internal.errorIf(~isnumeric(varargin{i}) ...
        && ~ischar(varargin{i}) && ~iscell(varargin{i}), ...
        'MATLAB:strcat:InvalidInputType');
    if iscell(varargin{i})
        hasCellArrayInputs = true;
    end
end

if hasCellArrayInputs
    t = strcatCell(varargin{:});
else
    t = strcatChar(varargin{:});
end

end

% strcat implementation for char vectors
function t = strcatChar(varargin)
rows = zeros(1, nargin);

for i = 1:nargin
    rows(i) = size(varargin{i}, 1);
end

if all(rows == 0)
    t = '';
    return
end

for i = 1:nargin
    coder.internal.errorIf(~ismatrix(varargin{i}), 'MATLAB:strfun:InputDimension');
end

maxrows = max(rows);
nvarargin = cell(1,nargin);

for i = 1:nargin
    if rows(i) == 0
        nvarargin{i} = '';
        continue
    end
    if rows(i) == 1 && rows(i) < maxrows
        rows(i) = maxrows;
        nvarargin{i} = repmat(varargin{i},maxrows,1);
    else
        nvarargin{i} = varargin{i};
    end
end

[~,nzp,nzr] = find(rows,1);
n = nzr(1);
zp = nzp(1);

for i = 1:nargin
    coder.internal.errorIf(rows(i) ~= 0 && rows(i) ~= n, 'MATLAB:strcat:NumberOfInputRows');
end

space = 0;
for i = 1:nargin
    if rows(i) == 0
        continue
    end
    space = space + numel(varargin{i});
end

notempty = true(1,n);
s = blanks(space);
input = ''; %#ok<NASGU>
sAcc = '';
coder.varsize('sAcc');
svector = zeros(n,2);

k = 0;

for i = 1:n
    k = k + 1;
    s = blanks(space);
    input = sanitizeInputAndConvertToChar(nvarargin{zp}(i,:));

    pos = length(input);
    s(1:pos) = input;
    pos = pos + 1;
    for j = (zp+1):length(varargin)
        if rows(j) == 0
            continue
        end
        input = sanitizeInputAndConvertToChar(nvarargin{j}(i,:));
        len = length(input);
        s(pos:pos+len-1) = input;
        pos = pos + len;
    end

    s = s(1:pos-1);
    lenS = numel(s);
    prevS = numel(sAcc);
    sAcc = [sAcc s]; %#ok<AGROW>
    svector(k,1) = prevS + 1;
    svector(k,2) = prevS + lenS;
    notempty(1,k) = ~isempty(s);
end

if n > 1
    t = splitStringByBoundaries(sAcc, svector);
else
    t = s;
end

end


function i = sanitizeInputAndConvertToChar(arg)
coder.internal.prefer_const('arg')
if ischar(arg) && ~isempty(arg) && (arg(end) == 0 || isspace(arg(end)))
    i = char(deblank(arg));
else
    i = char(arg);
end
end


function r = splitStringByBoundaries(s,splitBoundaries)
srowz = splitBoundaries(1,2) - splitBoundaries(1,1) + 1;
for i = 2:size(splitBoundaries,1)
    srowz = max(srowz, splitBoundaries(i,2) - splitBoundaries(i,1) + 1);
end
scolz = size(splitBoundaries,1);
r = repmat(' ',scolz,srowz);

for i = 1:scolz
    strsz = splitBoundaries(i,2) - splitBoundaries(i,1) + 1;
    r(i,1:strsz) = char(s(splitBoundaries(i,1):splitBoundaries(i,2)));
end
end

% strcat implementation for cellarrays
function t = strcatCell(varargin)

% Convert all inputs to cell arrays
nvarargin = cell(1,nargin);
for i = 1:nargin
    coder.internal.errorIf(~iscell(varargin{i}) && ~ischar(varargin{i}) ...
        && ~isempty(varargin{i}), 'MATLAB:strcat:InvalidInputType')
    if ischar(varargin{i})
        nvarargin{i} = cellstr(varargin{i});
    elseif iscell(varargin{i})
        nvarargin{i} = varargin{i};
    else
        nvarargin{i} = {''};
    end
end

% Try to get the size at compile time
sz = [1 1];
constNonScalar = false;
for i = coder.unroll(1:nargin)
    % Search for a non scalar element that has compile time constant size
    % Especially useful if one of the inputs is heterogenous cell array
    if coder.internal.isConstFalse(isscalar(nvarargin{i}))
        sz = size(nvarargin{i});
        constNonScalar = true;
        break;
    end
end

if coder.internal.isConstFalse(constNonScalar)
    % There are no non scalar inputs with compile time constant size
    % get the runtime size of the first non scalar.
    for i = coder.unroll(1:nargin)
        if ~isscalar(nvarargin{i})
            sz = size(nvarargin{i});
            break;
        end
    end
end

% Validate input size
for i = coder.unroll(1:nargin)
    coder.internal.assert(isscalar(nvarargin{i}) || isequal(size(nvarargin{i}), sz), ...
        'MATLAB:strcat:InvalidInputSize');
end

nnvarargin = cell(1,nargin);

for i = 1:nargin
    if isscalar(nvarargin{i})
        nnvarargin{i} = repmat(nvarargin{i}, sz);
    else
        nnvarargin{i} = nvarargin{i};
    end
end

t = cell(sz);
% Let coder attempt auto unroll if one of the inputs is a heterogenous cell
for i = 1:numel(t)
    s = cell(1, nargin);
    for j = coder.unroll(1:nargin)
        s{j} = nnvarargin{j}{i};
    end
    t{i} = [s{:}];
end

end
