function X = prepareData(fun,type,X,checknnz,obsin)
% Prepare term-document matrix for learning an LDA model.

% Inputs:
%   fun      - Name of the calling function or method, char vector
%   type     - 'Train', 'Prediction' or 'Validation'
%                For 'Train' and 'Prediction', X is passed as a required
%                positional input from the top function. For 'Validation',
%                X is passed using 'ValidationData' parameter.
%   X        - Input data, sparse double matrix
%   checknnz - Check if X has any nonzero elements, true or false
%   obsin    - Documents (observations ) in 'rows' or 'columns'. Specifies
%              orientation of X if X is passed as a matrix.
%
% Output:
%   X        - W-by-N sparse double matrix for W words and N documents

%   Copyright 2017 The MathWorks, Inc.

assert(ismember(type,{'Train' 'Prediction' 'Validation'}));

if ~isfloat(X) || ~isreal(X) || ~ismatrix(X) || any(X(:)<0)
    switch type
        case {'Train' 'Prediction'}
            error(message('stats:clustering:ldautils:prepareData:BadX'));
            
        case 'Validation'
            error(message('stats:clustering:ldautils:prepareData:BadValidationX'));
    end
end

% Sparse single can be supported when this type is supported in MATLAB. For
% now the C++ code assumes sparse double.
if ~isa(X,'double')
    X = double(X);
end

obsin = validatestring(obsin,{'rows' 'columns'},fun,'DocumentsIn');
if strcmp(obsin,'rows')
    X = X';
end

if ~issparse(X)
    try
        X = sparse(X);
    catch me
        error(message('stats:clustering:ldautils:prepareData:NotConvertibleToSparse',...
            fun,me.message));
    end
end

if checknnz
    if nnz(X)==0
        error(message('stats:clustering:ldautils:prepareData:OnlyZerosInX'));
    end
end

switch type
    case 'Train'
        if any(any(isnan(X)))
            error(message('stats:clustering:ldautils:prepareData:NaNsForTraining'));
        end
        
        if any(round(X(:))~=X(:))
            error(message('stats:clustering:ldautils:prepareData:BadX'));
        end

    case 'Validation'
        if any(any(isnan(X)))
            error(message('stats:clustering:ldautils:prepareData:NaNsForValidation'));
        end
        
        if any(round(X(:))~=X(:))
            error(message('stats:clustering:ldautils:prepareData:BadValidationX'));
        end

    case 'Prediction'
        Xgood = X(:);
        if any(any(isnan(X)))
            bad = isnan(Xgood);
            Xgood(bad) = 0;
        end
        
        if any(round(Xgood)~=Xgood)
            error(message('stats:clustering:ldautils:prepareData:BadX'));
        end
end

end
