function [LP, codistr] = hBuildFromReplicatedImpl(codistr, srcWorker, X)
; %#ok<NOSEM> % Undocumented
% Implementation of hBuildFromReplicatedImpl for codistributor1d.

%   Copyright 2009-2022 The MathWorks, Inc.

% Convert 'missing' type to double here if required.
if isa(X, 'missing')
    X = double(X);
end

sizeX = size(X);
isXsparse = issparse(X);
supported = distributedutil.Allocator.supportsCreation(X);
classX = class(X);

if srcWorker ~= 0
    % All workers other than srcWorker need to know what the size of X is
    % and whether we support its use. Broadcast both in one go to minimize
    % collective communication.
    data = spmdBroadcast(srcWorker, {size(X), isXsparse, supported, classX});
    [sizeX, isXsparse, supported, classX] = deal(data{:});
end

if ~supported
    error(message('parallel:codistributors:BuildUnsupportedClass', classX));
end

% We need to work with a completely specified codistributor with the correct
% global size
if ~isXsparse
    codistr = codistr.hGetCompleteForSize(sizeX);
else 
    % Check if codistr is supported for sparse
    codistr.hVerifySupportsSparse();
    
    % If codistr is not complete or the global size does not match the size
    % of the data, get the NNZ per row (codistr.Dimension==1) or column 
    % (codistr.Dimension==2) and get a complete, sparse, and balanced 
    % codistributor.
    if ~codistr.isComplete() || ~isequal(codistr.Cached.GlobalSize, sizeX)
        % Set distribution dimension if not set yet
        if codistr.Dimension == codistributor1d.unsetDimension
            codistr.Dimension = distributedutil.Sizes.lastNonSingletonDimension(sizeX);
        end
        nnzDimension = codistr.Dimension;
        % For vectors, ensure nnzDimension is singleton dimension.
        if isvector(X)
            nnzDimension = iscolumn(X) + 1;
        end
        nnz1D = parallel.internal.codistextern.sparseNnzPerRowOrColumn(...
            X, nnzDimension);
        codistr = codistr.hGetCompleteSparseBalancedForSize(sizeX, nnz1D);
    end
end

% Extract or send/receive the appropriate local part.
LP = getLocalPart(X, srcWorker, codistr);

if (istable(LP) || istimetable(LP)) && codistr.Dimension == 2
    % In this case, the variables of table LP is a subset of the variables
    % of table X. We need to relay this information to
    % hEnsureComplexityMatches as its action is per variable.
    LP = distributedutil.hEnsureComplexityMatches(LP, X, [], partitionIndices(codistr.Partition));
else
    LP = distributedutil.hEnsureComplexityMatches(LP, X);
end
end % End of hBuildFromReplicatedImpl.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function X = getLocalPart(X, srcWorker, codistr)
%LP = getLocalPart(X, srcWorker, codistr)  Go from a full array to the local parts.

szX = codistr.Cached.GlobalSize;
% Pad size of X with trailing ones if dim > ndims(X).  This allows us to create
% the right substruct for the subsref that follows.
if codistr.Dimension > length(szX)
    szX(end+1:codistr.Dimension) = 1;
end

idx = substruct('()', repmat({':'}, 1, length(szX)));
mwTag = 31681;
if srcWorker == 0
    % Everyone has the matrix, so we can index directly into it.
    idx.subs{codistr.Dimension} = partitionIndices(codistr.Partition);
    X = subsref(X,idx);
else
    % Send the appropriate portion of the matrix to each of the other workers.
    if spmdIndex == srcWorker
        for destWorker = 1:spmdSize
            if destWorker ~= srcWorker
                idx.subs{codistr.Dimension} = partitionIndices(codistr.Partition, destWorker);
                spmdSend(subsref(X,idx), destWorker, mwTag);
            end
        end
        % Done sending to others.  Retain only the portion we need for our local part.
        idx.subs{codistr.Dimension} = partitionIndices(codistr.Partition, srcWorker);
        X = subsref(X,idx);
    else
        X = spmdReceive(srcWorker, mwTag);
    end
end

end % End of getLocalPart.
