% ConfigPropStorage - Stores information about all the configurable properties registered.
% c.f. @distcomp/@configpropstorage

% Copyright 2007-2021 The MathWorks, Inc.

classdef ( Hidden, Sealed ) ConfigPropStorage

    properties ( Access = private )
       % Struct storing information about configurable properties registered
       PropertyInfo 
    end

    methods ( Access = private )
        % c.f. @distcomp/@configpropstorage/configpropstorage.m
        function obj = ConfigPropStorage()       
        end
        
        % c.f. @distcomp/@configpropstorage/pGetPropertyNames.m
        function names = pGetPropertyNames(obj, classNameOrFunctionName)
        %Return names of configurable properties.
        %   props = pGetPropertyNames(obj, classNameOrFunctionName)
        %   The value is returned as a cell string array.
            
            parallel.internal.settings.ConfigPropStorage.pVerifyClassName(classNameOrFunctionName);
            try
                classInfo = obj.PropertyInfo.(classNameOrFunctionName);
                names = classInfo.PropertyNames;
            catch %#ok<CTCH>
                % We don't have any information about this class.
                names = {};
            end
        end
    end

    methods ( Static, Access = private )
        
        % c.f. @distcomp/@configpropstorage/pVerifyClassName.m
        function pVerifyClassName(name)
        %Throw an error if name is clearly an invalid name of a class or a function.
        
            parallel.internal.customattr.checkSimpleConstraint('nonemptystring', 'name', name);
        end
      
        % c.f. @distcomp/@configpropstorage/pGetInstance.m
        function obj = pGetInstance
        %Return a singleton.
        
            persistent storage;
            if isempty(storage)
                % Create and initialize a new singleton.
                % We don't need to mlock the object because it only performs lazy introspection.
                storage = parallel.internal.settings.ConfigPropStorage;
                storage.PropertyInfo = parallel.internal.settings.ConfigPropStorage.pGetAllConfigurableProperties();
            end
            
            obj = storage;
        end
    
        % c.f. @distcomp/@configpropstorage/pGetAllConfigurableProperties.m
        function propertyInfo = pGetAllConfigurableProperties()
        %Static method that returns all configurable properties in the distcomp package.
        %    PropertyInfo = pGetAllConfigurableProperties() 
        %    Returns a struct props whose field names are names of classes in the
        %    distcomp package, and the corresponding value is a struct storing the
        %    information about the configurable properties in that class.
        %
            import parallel.internal.settings.ConfigPropStorage

            %% All the configurable properties on all of our scheduler objects.
            % NB the order in which the properties appear in this file corresponds to the
            % order in which they are applied when setting a configuration.  
            % The following CCS properties have different allowable values depending
            % on SchedulerHostname: ClusterSize, ClusterVersion JobTemplate, UseSOAJobSubmission.
            % It is very important SchedulerHostname comes first before the other properties 
            % in this list.
            ccsschedulerProps = {'SchedulerHostname', 'ClusterSize', 'DataLocation', ...
                                'ClusterMatlabRoot', 'UseSOAJobSubmission', 'ClusterVersion', ...
                                'JobTemplate', 'JobDescriptionFile'};
            genericschedulerProps = {'ClusterSize', 'DataLocation', 'HasSharedFilesystem', ...
                                'ClusterMatlabRoot', 'ClusterOsType', 'GetJobStateFcn', ...
                                'SubmitFcn', 'ParallelSubmitFcn',...
                                'CancelJobFcn', 'CancelTaskFcn', ...
                                'DestroyJobFcn', 'DestroyTaskFcn'};
            jobmanagerProps   = {'UserName'};
            localschedulerProps = {'ClusterSize', 'DataLocation'};
            lsfschedulerProps = {'ClusterSize', 'DataLocation', 'HasSharedFilesystem', ...
                                'ClusterMatlabRoot', ...
                                'SubmitArguments', 'ClusterOsType', ...
                                'ParallelSubmissionWrapperScript'};
            pbsproschedulerProps = {'ClusterSize', 'ClusterMatlabRoot', ...
                                'ClusterOsType', ...
                                'DataLocation',  ...
                                'HasSharedFilesystem', ...
                                'ParallelSubmissionWrapperScript', ...
                                'ProcsPerNode', ...
                                'RcpCommand', ...
                                'ResourceTemplate', ...
                                'RshCommand', ...
                                'SubmitArguments',  ...
                               };
            slurmschedulerProps = {'ClusterSize', ...
                                'ClusterMatlabRoot', ...
                                'DataLocation', ...
                                'SubmitArguments', ...
                                'ParallelSubmissionWrapperScript'};
            torqueschedulerProps = {'ClusterSize', 'ClusterMatlabRoot', ...
                                'DataLocation', ...
                                'HasSharedFilesystem', ...
                                'ParallelSubmissionWrapperScript', ...
                                'ProcsPerNode', ...
                                'RcpCommand', ...
                                'ResourceTemplate', ...
                                'RshCommand', ...
                                'SubmitArguments', ...
                               };
            
            %% All the configurable properties on all of our job objects.
            % distcomp.job:
            jobProps = {'FileDependencies', 'PathDependencies', ...
                        'MinimumNumberOfWorkers', 'MaximumNumberOfWorkers', ...
                        'QueuedFcn', 'RunningFcn',  'FinishedFcn', ...
                        'Timeout', 'RestartWorker'};
            % distcomp.paralleljob:
            paralleljobProps = {'FileDependencies', 'PathDependencies', ...
                                'MinimumNumberOfWorkers', 'MaximumNumberOfWorkers', ...
                                'QueuedFcn', 'RunningFcn',  'FinishedFcn', ...
                                'Timeout', 'RestartWorker'};
            % distcomp.matlabpooljob:
            matlabpooljobProps = {'FileDependencies', 'PathDependencies', ...
                                'MinimumNumberOfWorkers', 'MaximumNumberOfWorkers', ...
                                'QueuedFcn', 'RunningFcn',  'FinishedFcn', ...
                                'Timeout', 'RestartWorker'};
            % distcomp.simplejob
            simplejobProps = {'FileDependencies', 'PathDependencies'};
            % distcomp.simpleparalleljob
            simpleparalleljobProps = {'FileDependencies', 'PathDependencies', ...
                                'MinimumNumberOfWorkers', 'MaximumNumberOfWorkers'};
            % distcomp.simplematlabpooljob
            simplematlabpooljobProps = {'FileDependencies', 'PathDependencies', ...
                                'MinimumNumberOfWorkers', 'MaximumNumberOfWorkers'};
            
            %% All the configurable properties on all of our task objects.
            % distcomp.task
            taskProps = {'CaptureCommandWindowOutput', ...
                         'Timeout', 'MaximumNumberOfRetries', 'FinishedFcn', 'RunningFcn'};
            %distcomp.simpletask
            simpletaskProps = {'CaptureCommandWindowOutput'};
            
            %% All the configurable properties when calling findResource.
            % Only findResource's Type argument is not writable, so we handle that below.
            % The data types of findResource's configurable properties are the only data
            % types we can't figure out via inspection, so we also declare them below.
            findResourceProps = {'Type'};
            findResourceTypes = {'string'};
            findResourceWritable = false;
            JobManagerFindResourceProps = {'Type', 'Name', 'LookupURL'};
            JobManagerFindResourceTypes = {'string', 'string', 'string'};
            JobManagerFindResourceWritable = [false, true, true];
            
            
            %% Form the return values.
            % For each configurable object, create a substructure storing the property
            % names, their data types and IsWritable status.
            propertyInfo = struct(...
                'ccsscheduler',           ConfigPropStorage.iCreateSubstruct(ccsschedulerProps), ...
                'genericscheduler',       ConfigPropStorage.iCreateSubstruct(genericschedulerProps),...
                'jobmanager',             ConfigPropStorage.iCreateSubstruct(jobmanagerProps), ...
                'localscheduler',         ConfigPropStorage.iCreateSubstruct(localschedulerProps), ...
                'lsfscheduler',           ConfigPropStorage.iCreateSubstruct(lsfschedulerProps), ...
                'pbsproscheduler',        ConfigPropStorage.iCreateSubstruct(pbsproschedulerProps), ...
                'slurmscheduler',         ConfigPropStorage.iCreateSubstruct(slurmschedulerProps), ...
                'torquescheduler',        ConfigPropStorage.iCreateSubstruct(torqueschedulerProps), ...
                'job',                    ConfigPropStorage.iCreateSubstruct(jobProps), ...
                'paralleljob',            ConfigPropStorage.iCreateSubstruct(paralleljobProps), ...
                'matlabpooljob',          ConfigPropStorage.iCreateSubstruct(matlabpooljobProps), ...
                'simplejob',              ConfigPropStorage.iCreateSubstruct(simplejobProps), ...
                'simpleparalleljob',      ConfigPropStorage.iCreateSubstruct(simpleparalleljobProps), ...
                'simplematlabpooljob',    ConfigPropStorage.iCreateSubstruct(simplematlabpooljobProps), ...
                'task',                   ConfigPropStorage.iCreateSubstruct(taskProps), ...
                'simpletask',             ConfigPropStorage.iCreateSubstruct(simpletaskProps), ...
                'findResource',           ConfigPropStorage.iCreateSubstruct(findResourceProps), ...
                'JobManagerFindResource', ConfigPropStorage.iCreateSubstruct(JobManagerFindResourceProps));
            
            %% Fill in the data types we know a-priori.
            % All data types not declared here will be found via object introspection when
            % we are first asked for them.
            propertyInfo.findResource.DataTypes = findResourceTypes;
            propertyInfo.JobManagerFindResource.DataTypes = JobManagerFindResourceTypes;
            
            %% Handle special cases of IsWritable
            % Only the Type argument to findResource is not writable.
            propertyInfo.findResource.IsWritable = findResourceWritable;
            propertyInfo.JobManagerFindResource.IsWritable = JobManagerFindResourceWritable;
        end       

        function propertySubstruct = iCreateSubstruct(propertyNames)
        % Return a single struct storing the information about the configurable
        % properties. 
        
            % We only want a single struct, so we enclose the cell arrays in curly braces.
            propertySubstruct = struct('PropertyNames', {propertyNames}, ...
                                       'DataTypes', {{}}, ...
                                       'IsWritable', true(size(propertyNames)));
        end
    end

    methods ( Hidden, Static, Access = ?parallel.internal.settings.ProfilesConverter )
        % c.f. @distcomp/@configpropstorage/getConfigurableProperties.m
        function props = getConfigurableProperties(className)
        %getConfigurableProperties Static method to get configurable properties.
        %
        %  Input is a class name or 'findResource', or 'JobManagerFindResource'.
        %  Note: Removed return arguments 'type' and 'isWritable' as they
        %  are no longer used.
        
            parallel.internal.settings.ConfigPropStorage.pVerifyClassName(className);
            store = parallel.internal.settings.ConfigPropStorage.pGetInstance();
            
            % Strip of the initial distcomp. part when present.
            className = regexprep(className, '^distcomp\.', '');
            
            % Do not to query for the data types unless we are asked to return them, as this
            % may trigger introspection.
            props = store.pGetPropertyNames(className);
        end
    end
end
