classdef (Abstract) Validation
%

%   Copyright 2020-2021 The MathWorks, Inc.

    methods (Static)
        
        function mustBeEmptyOrPipeline(value)
            if ~isempty(value) && ~isa(value, 'bioinfo.pipeline.Pipeline')
                error(message("bioinfo:Pipeline:Validation:mustBeEmptyOrPipeline"));
            end
        end
        
        function mustBeEmptyOrVarName(value)
            bioinfo.internal.ValidationHelper.mustBeEmptyOrScalar(value);
            if ~isempty(value)
                mustBeValidVariableName(value);
            end
        end
        
        function mustBeEmptyOrA(value, klass)
            if ~isempty(value) && ~isa(value, klass)
                error(message("bioinfo:Pipeline:Validation:mustBeEmptyOrClass", klass));
            end
        end
        
        function mustBeEmptyOrScalar(value)
            if numel(value) > 1
                error(message("bioinfo:Pipeline:Validation:mustBeEmptyOrScalar"));
            end
        end
        
        function mustBeUnique(value)
            uniqueValues = unique(value);
            if numel(value) ~= numel(uniqueValues)
                error(message("bioinfo:Pipeline:Validation:mustBeUnique"));
            end
        end
        
        function mustBeSplitDimension(value)
            if ~isequal(value, "all") || ~isequal(value, 'all')
                try
                    mustBePositive(value);
                    mustBeInteger(value);
                    if ~isempty(value) % Allow []
                        mustBeVector(value);
                    end
                catch ME
                    error(message("bioinfo:Pipeline:Validation:mustBeSplitDimension"));
                end
            end
        end

        function mustBeScalarPipelineOrPLPRJ(p)
            % Checks whether p is a scalar pipeline object or a PLPRJ file
            if isa(p, "bioinfo.pipeline.Pipeline")
                if ~isscalar(p)   
                   error(message("bioinfo:biopipelineDesigner:mustBeScalarPipelineOrPLPRJ"));
               end
            elseif ~bioinfo.pipeline.internal.Validation.isPLPRJFile(p)
                error(message("bioinfo:biopipelineDesigner:mustBeScalarPipelineOrPLPRJ"));
            end
        end

        function mustBePLPRJFile(p)
            if ~bioinfo.pipeline.internal.Validation.isPLPRJFile(p)
                error(message("bioinfo:biopipelineDesigner:mustBeScalarPipelineOrPLPRJ"));
            end
        end

        function tf = isPLPRJFile(p)
            % returns logical array with the same numel as p
            
            p = convertCharsToStrings(p);
            tf = false(numel(p),1);
            
            for i = 1:numel(p)
                try
                    if (isstring(p(i)) && isfile(p(i)) && endsWith(p(i), ".plprj"))
                        varlist = string(who(matfile(p(i))));
                        tf(i)   = strcmp("plprjData", varlist);
                    end
                catch
                end
            end
        end

        function mustBeBlockID(BlockIDs, mustBeValidBlockScalar)
            % MUSTBEBLOCKID validates inputs for functions that accept
            % block identifiers
            %
            % BLOCKIDS cannot be zero-length text value (e.g. "" and '').
            % BLOCKIDS must be empty or a vector of one of the following:
            %
            % - Names of blocks, as a string or cellstr
            % - Numeric indexes of blocks (positive integers)
            % - Block objects
            %
            % mustBeValidBlockScalar specifies that BlockIDs must reference
            % a single block
            if nargin < 2
                mustBeValidBlockScalar = false;
            end

            BlockIDs = convertCharsToStrings(BlockIDs);

            try
                mustBeInteger(BlockIDs);
                mustBePositive(BlockIDs);
                mustBeNumeric(BlockIDs);
            catch ME
                % If not integer, must be one of these types
                if ~(isstring(BlockIDs) || isa(BlockIDs, 'bioinfo.pipeline.Block'))
                    error(message("bioinfo:Pipeline:InvalidType"));
                end

                % cannot be zero-length string ("" and '')
                if ~isempty(BlockIDs) && isscalar(BlockIDs) && isstring(BlockIDs) && strlength(BlockIDs)==0
                    error(message("bioinfo:Pipeline:InvalidBlocks"));
                end
            end

            if mustBeValidBlockScalar && ~isscalar(BlockIDs)
                error(message("bioinfo:Pipeline:NonScalar"));
            end
        end
    end
end
