function obj = subsasgn( obj, S, value )
%SUBSASGN Subscripted assignment for distributed array
%   A(I) = B
%   A(I,J) = B for 2-D distributed arrays
%   A(I1,I2,I3,...,IN) = B for N-D distributed arrays
%   
%   A{...} indexing is not supported for distributed cell arrays.
%   A.field indexing is not supported for distributed arrays of structs.
%   
%   To expand an N-D distributed array A to higher dimensions via
%   A(I1,I2,...IN,IN+1) = B, B must be a scalar.
%   
%   A(I) = B cannot be used to expand the size of A.
%   
%   Example:
%       N = 1000;
%       D = distributed.eye(N);
%       D(1,N) = pi
%   
%   See also SUBSASGN, DISTRIBUTED, DISTRIBUTED/EYE.


%   Copyright 2006-2020 The MathWorks, Inc.

% SUBSASGN always needs an output
if nargout==0
    error(message('MATLAB:subsasgnMustHaveOutput'));
end

% Make sure S is a valid substruct
matlab.bigdata.internal.util.checkValidSubstruct(S);

% Need to capture deleting case up-front is the SqrBrktLiteral is lost on
% copying.
if builtin('_isEmptySqrBrktLiteral',value)
    % Deleting subsasgn
    spmdfcn = @iSubsasgnSquareEmptyHelper;
else
    % General subsasgn
    spmdfcn = @iSubsasgnHelper;
end

% Disentangle the subs in case they contain any distributed arrays.
% distributedutil.distributedSpmdWrapper will check for validity of any
% distributed arguments. Since each subscript can have multiple arguments
% each is written as [type, numSubs, iscell, sub1, sub2, ...]
subsArgs = {};
for ii=1:numel(S)
    storeAsCell = iscell(S(ii).subs);
    if storeAsCell
        subsArgs = [subsArgs, {S(ii).type}, numel(S(ii).subs), storeAsCell, S(ii).subs]; %#ok<AGROW>
    else
        subsArgs = [subsArgs, {S(ii).type}, 1, storeAsCell, {S(ii).subs}]; %#ok<AGROW>
    end
end
obj = distributedutil.distributedSpmdWrapper(spmdfcn, obj, value, subsArgs{:});
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Helpers to re-create the substruct and apply it as appropriate

function subs = iRebuildSubscript(args)
% Rebuild unpacked subscript. The arguments are packed as:
%   [type, numSubs, iscell, sub1, sub2, ...]
n=1;
subargs = {};
while n<numel(args)
    type = args{n};
    nSubs = args{n+1};
    subsAsCell = args{n+2};
    if subsAsCell
        subs = args(n+2+(1:nSubs));
    else
        assert(nSubs==1,"A non-cell subsindex cannot have more than one subscript");
        subs = args{n+3};
    end
    subargs = [subargs, {type}, {subs}]; %#ok<AGROW>
    n = n + 3 + nSubs;
end
subs = substruct(subargs{:});
end


function coDd = iSubsasgnHelper( coDd, value, varargin )
% General subsasgn
subs = iRebuildSubscript(varargin);
coDd = subsasgn( coDd, subs, value );
end

function coDd = iSubsasgnSquareEmptyHelper( coDd, ~, varargin )
% Assignment to []
subs = iRebuildSubscript(varargin);
coDd = hSubsasgnSquareEmpty( coDd, subs );
end
