function ind = strfind(text, varargin)
%STRFIND  Find one string within another.
%   K = STRFIND(TEXT,PATTERN)
%   
%   Note that TEXT must be a codistributed array of strings or cell array
%   of char vectors. The output is always a cell array of index vectors.
%   
%   Example:
%   spmd
%       s = {'How much wood'; 'would a woodchuck chuck?'};
%       S = codistributed(s);
%       strfind(S,'wo')
%   end
%   
%   Limitations:
%   Pattern objects are not supported.
%   
%   See also STRFIND, CODISTRIBUTED.
%   
%   


%   Copyright 2015-2022 The MathWorks, Inc.

narginchk(2, 4);
% PATTERN is currently not supported
matlab.bigdata.internal.util.errorIfPatternInput('distributed', text, varargin{:});

% If the pattern or subsequent args are distributed, gather them now.
argList = distributedutil.CodistParser.gatherElements(varargin);

if ~iscodistributed(text)
    % Trailing parameters are codistributed, but not the array itself. Use
    % the normal MATLAB version with the gathered arguments.
    ind = strfind(text, argList{:});
    return;
end

% The first input must be an array of strings. The others are just bound in
% and used for each element.
if ~isStringArray(text)
    error(message('parallel:distributed:NotStringArray', 'STRFIND'));
end

% A scalar string input can produce a row vector output. String arrays
% produce cell arrays in an element-wise manner
if isstring(text) && isscalar(text) && ~iForceCellOutputTrue(argList)
    % Scalar might expand to row vector
    indLpCell = iWrapStrfind(getLocalPart(text), argList{:});
    if ~isempty(indLpCell)
        % Unwrap scalar cell of local part
        indLp = indLpCell{1};
        sizeIndLp = size(indLp);
    else
        % Set size to [0 0] for workers without data
        sizeIndLp = zeros(1,2);
    end
    % Communicate local sizes
    concatenatedSize = spmdCat(sizeIndLp, 1);
    % Create partition, global size, and codistributor for the result
    partitionInd = concatenatedSize(:,2)';
    globalSizeInd = sum(concatenatedSize, 1);
    codistr = codistributor1d(2, partitionInd, globalSizeInd);
    
    % Workers that did not carry input data need empty local part of
    % correct dimension
    if isempty(indLpCell)
        indLp = zeros(globalSizeInd(1), partitionInd(spmdIndex));
    end
    
    ind = codistributed.pDoBuildFromLocalPart(indLp, codistr);
else
    % One output element for each input element.
    ind = codistributed.pElementwiseUnaryOp(@(x) iWrapStrfind(x, argList{:}), text);
end
end

function out = iWrapStrfind(in, varargin)
% To avoid problems with local workers only having a single element force
% return of a cell array.
out = strfind(in, varargin{:});
if ~iscell(out)
    out = {out};
end
end

function tf = iForceCellOutputTrue(argList)
% If 'ForceCellOutput' is true, we go through the same branch as for
% non-scalar inputs
tf = size(argList, 2)== 3 && ...
    strcmpi(argList{2}, 'forcecelloutput') && ...
    argList{3};
end