function dt = table(varargin)
%TABLE Build a codistributed table from codistributed arrays
%   DT = TABLE(D1,D2,...) creates a codistributed table DT from codistributed
%   arrays D1, D2, ... . All arrays must be codistributed and have the same
%   number of rows. The result is always distributed using a 1D distribution
%   scheme over the first dimension.
%   
%   DT = TABLE(..., 'VariableNames', {'name1', ..., 'name_M'}) creates a table
%   that has the specified variable names.  The names need not be valid MATLAB
%   identifiers, but must be unique.
%   
%   DT = TABLE(..., 'DimensionNames', {'dim1', 'dim2'}) creates a table
%   that has the specified dimension names.  The names need not be valid MATLAB
%   identifiers, but must be unique.
%   
%   See also TABLE, CODISTRIBUTED.
%   


%   Copyright 2016-2020 The MathWorks, Inc.

% Attempt to deal with trailing p-v pairs.
numVars = matlab.bigdata.internal.util.countTableVarInputs(varargin);
varValues = varargin(1:numVars);
pnames   = {'VariableNames', 'RowNames', 'DimensionNames'};
dflts    = {             [],         [],               []};
priority = [              0,          0,                0];
[varNames, ~, dimNames, supplied] ...
    = matlab.internal.datatypes.parseArgsTabularConstructors(pnames, dflts, priority, ...
                                                             "MATLAB:table:StringParamNameNotSupported", ...
                                                             varargin{numVars+1:end});
if supplied.RowNames
    error(message("parallel:distributed:TableUnsupportedParam"));
end

if ~supplied.VariableNames
    varNames = arrayfun(@inputname, 1:numVars, "UniformOutput", false);
    empties = cellfun("isempty", varNames);
    if any(empties)
        varNames(empties) = matlab.internal.tabular.defaultVariableNames(find(empties));
    end
    % Make sure default names or names from inputname don't conflict
    varNames = matlab.lang.makeUniqueStrings(varNames, {}, namelengthmax);
end

if ~supplied.DimensionNames
    rowDimName = getString(message("MATLAB:table:uistrings:DfltRowDimName"));
    varDimName = getString(message("MATLAB:table:uistrings:DfltVarDimName"));
    dimNames = {rowDimName, varDimName};
end


matlab.bigdata.internal.util.checkTableVariableNames(varNames, dimNames, numVars);

% Data inputs must all be codistributed
if ~all(cellfun(@iscodistributed, varValues))
    error(message("parallel:distributed:AllTableArgsDistributed"));
end

% Data inputs must all have same number of rows
nVars = numel(varNames);
nRows = cellfun(@(x) size(x,1), varValues);
if ~all(nRows == nRows(1))
    error(message("MATLAB:table:UnequalVarLengths"));
end
nRows = nRows(1);

% We require the inputs to be distributed in dimension 1. We want even
% distribution of data, so use the number of rows to design the ideal
% distribution.
varValues = cellfun(@(x) iRedistribute(x, nRows), varValues, "UniformOutput", false);
localParts = cellfun(@(x) getLocalPart(x), varValues, "UniformOutput", false);

% Now form the table on each worker.
localTable = matlab.bigdata.internal.util.makeTabularChunk(@table, localParts, ...
    {'VariableNames', varNames, 'DimensionNames', dimNames});

% Build a new codistributed from the local parts
codistr = codistributor1d(1, codistributor1d.unsetPartition, [nRows,nVars]);
dt = codistributed.pDoBuildFromLocalPart(localTable, codistr);

end

function out = iRedistribute(in, nRows)
% Redistribute one input
sz = size(in);
sz(1) = nRows;
codistr = codistributor1d(1, codistributor1d.unsetPartition, sz);
out = redistribute(in, codistr);
end
