function [B,I] = rmMissingOutliers(funName,A,varargin)
% rmMissingOutliers Helper function for rmmissing and rmoutliers
%
%   FOR INTERNAL USE ONLY -- This feature is intentionally undocumented.
%   Its behavior may change, or it may be removed in a future release.
%
%   B - A after removing rows or columns
%   I - Colum(row) logical vector indicating removed rows(columns)
%

%   Copyright 2015-2018 The MathWorks, Inc.

opts = parseInputs(funName,A,varargin{:});

if ~opts.AisTable
    if ~ismatrix(A)
        issueError(funName,'NDArrays');
    end
    I = applyFun(funName,A,opts);
    I = cumputeIndex(I,opts.byRows,opts.minNum);
else
    if ~all(varfun(@ismatrix,A,'OutputFormat','uniform'))
        issueError(funName,'NDArrays');
    end
    if opts.byRows
        if opts.dataVarsProvided
            I = applyFun(funName,A(:,opts.dataVars),opts);
        else
            % Don't index into a table if we don't have to
            I = applyFun(funName,A,opts);
        end
        I = cumputeIndex(I,opts.byRows,opts.minNum);
        if isa(A,'timetable') && isequal(funName,'rmmissing')
            % Also remove the rows which correspond to missing RowTimes
            I = I | ismissing(A.Properties.RowTimes);
        end
    else
        I = false(1,width(A));
        for vj = opts.dataVars
            Ivj = applyFun(funName,A(:,vj),opts);
            I(vj) = cumputeIndex(Ivj,opts.byRows,opts.minNum);
        end
    end
end
B = reduceSize(A,I,opts.byRows);
end

%--------------------------------------------------------------------------
function I = applyFun(funName,A,opts)
% Find missing data or outliers
if isequal(funName,'rmmissing')
    I = ismissing(A);
else
    I = isoutlier(A,opts.isoutlierArgs{:});
end
end

%--------------------------------------------------------------------------
function I = cumputeIndex(I,byRows,minNum)
% Colum(row) logical vector indicating removed rows(columns)
I = sum(I,1 + byRows) >= minNum;
end

%--------------------------------------------------------------------------
function B = reduceSize(A,I,byRows)
% Keep non-missing
if byRows
    B = A(~I,:);
else
    B = A(:,~I);
end
end

%--------------------------------------------------------------------------
function opts = parseInputs(funName,A,varargin)
% Parse RMMISSING/RMOUTLIERS inputs

% We let the ISMISSING/ISOUTLIER calls error out for A of invalid type
opts.AisTable = matlab.internal.datatypes.istabular(A);

% Defaults
opts.minNum = 1;
opts.byRows = true;
opts.dataVarsProvided = false;
if ~opts.AisTable
    if isrow(A) && ~isscalar(A)
        opts.byRows = false;
    end
    opts.dataVars = NaN; % not supported for arrays
else
    opts.dataVars = 1:width(A);
end
if isequal(funName,'rmoutliers')
    opts.isoutlierArgs = {}; % arguments needed for ISOUTLIER computation
end

% Parse the outlier method, the trailing DIM and N-V pairs (including
% inputs which need to be forwarded to ISOUTLIER).
errorForDataVars = true;
opts = matlab.internal.math.rmMissingOutliersVarargin(funName,A,opts,...
    errorForDataVars,varargin{:});
end

%--------------------------------------------------------------------------
function issueError(funName,errorId)
% Issue error from the correct error message catalog
error(message(['MATLAB:', funName, ':', errorId]));
end
