function varargout = pagemlmrdivideCommon(fcnName, varargin)
% Common logic for both PAGEMLDIVIDE and PAGEMRDIVIDE.

%   Copyright 2021-2022 The MathWorks, Inc.

narginchk(3, 4); % (A,B) or (A,Atrans,B)
nargoutchk(1, 2); % Caller should never request 0 outputs
[inputMatrices, transA] = iParseArgs(fcnName, varargin);
varargout = cell(1,max(1,nargout));

% Calculate the number of pages in dimensions 3 and up, referred as 
% trailing output dimensions. Will error if the corresponding page 
% dimensions of the inputs are not consistent.
trailingOutDims = parallel.internal.array.pagefunTrailingDimensions(inputMatrices, ...
    "MATLAB:"+fcnName+":mismatchImplicitExpansion");

% Get the codistributor of the output.
outCodistr = pagefunGetOutputsCodistr(inputMatrices, trailingOutDims);
% Redistribute the inputs if needed.
inputMatrices = pagefunRedistributeInputsIfNeeded(inputMatrices, outCodistr);

% Extract the local parts.
localParts = pagefunGetLocalParts(inputMatrices);
% We might need one or two outputs.
localOut = cell(size(varargout));
% Call in-memory pagemtimes.
try
    if fcnName == "pagemldivide"
        A = inputMatrices{1};
        [localOut{:}] = pagemldivide(localParts{1}, transA, localParts{2});
    else
        A = inputMatrices{2};
        [localOut{:}] = pagemrdivide(localParts{1}, localParts{2}, transA);
    end
    err = [];
catch err
end
% Check for errors
err = spmdCat(err);
if ~isempty(err)
    throw(err(1));
end

% Build the output(s). The first output will have been expanded as usual.
varargout{1} = pagefunBuildOutputs(localOut(1), outCodistr, trailingOutDims);
% The second output is always 1x1x... with the same number of pages as the
% matrix input A.
if nargout>1
    if iscodistributed(A)
        Acodistr = getCodistributor(A);
        rcondSz = size(A);
        rcondSz(1:2) = 1;
        rcondCodistr = codistributor1d(Acodistr.Dimension, Acodistr.Partition, rcondSz);
        varargout{2} = codistributed.build(localOut{2}, rcondCodistr);
    else
        % A was not distributed so build rcond should be replicated on all
        % workers.
        varargout{2} = codistributed.pConstructFromReplicated(localOut{2});
    end
end
end

function [inputMatrices, transA] = iParseArgs(fcnName, args)
% Parse and check the input arguments
catalog = "MATLAB:" + fcnName + ":";
if any(cellfun(@issparse, args))
    throwAsCaller(iMException(catalog+"sparseNotSupported"));
end
if numel(args) == 2
    % No transpose flag - both inputs must be arrays.
    inputMatrices = args;
    transA = 'n';
else % numel(args) == 3
    if fcnName=="pagemldivide"
        transArg = 2;
    else
        transArg = 3;
    end
    arrayArgs = setdiff(1:3,transArg);
    inputMatrices = args(arrayArgs);
    % Transpose flag text will be check by in-memory function on all workers.
    % Here just make sure they are strings.
    transA = args{transArg};
    if ~matlab.internal.datatypes.isScalarText(transA)
        throwAsCaller(iMException(catalog+"invalidOption"));
    end
end
% Both matrices must be floating point
if ~isfloat(inputMatrices{1}) || ~isfloat(inputMatrices{2})
    throwAsCaller(iMException(catalog+"invalidArray"));
end
end


function me = iMException(id)
% Create an MException from the specified error ID
me = MException(message(id));
end
