% parallel.parfor.ClusterOptions parforOptions for running on ClusterParforEngine.

% Copyright 2018-2022 The MathWorks, Inc.

classdef ClusterOptions < parallel.parfor.Options

    properties (SetAccess = immutable)
        Cluster           (1,1)
        AutoAttachFiles   (1,1) logical
        AutoAddClientPath (1,1) logical
        AttachedFiles
        AdditionalPaths
    end
    
    methods
        function obj = ClusterOptions(cluster, parserResults, unspecifiedProperties)
            obj = obj@parallel.parfor.Options(parserResults, unspecifiedProperties);
            assert(isa(cluster, 'parallel.Cluster'), ...
                   'Expected a parallel.Cluster.');
            % Check the number of workers in the cluster - must be non-zero, and finite if the
            % RangePartitionMethod is 'auto'. We must use hGetMaxNumWorkers to avoid problems with
            % resizable clusters.
            nw = cluster.hGetMaxNumWorkers();
            if nw == 0
                error(message('parallel:lang:parfor:ClusterNumWorkersNonZero'));
            end
            if isinf(nw) && ...
                    (strcmp(obj.RangePartitionMethod, 'auto') || ...
                     strcmp(obj.RangePartitionMethod, 'default'))
                error(message('parallel:lang:parfor:ClusterNumWorkersInf'));
            end
            
            obj.Cluster = cluster;
            obj.AutoAttachFiles = parserResults.AutoAttachFiles;
            obj.AutoAddClientPath = parserResults.AutoAddClientPath;
            obj.AttachedFiles = cellstr(parserResults.AttachedFiles);
            obj.AdditionalPaths = cellstr(parserResults.AdditionalPaths);
        end
        
        function engine = createEngine(obj, initData, parforF, ~)
            engine = parallel.internal.cluster.ClusterParforEngine( ...
                obj.RangePartitionMethod, obj.SubrangeSize, ...
                obj.Cluster, obj.AutoAttachFiles, obj.AutoAddClientPath, ...
                obj.AttachedFiles, obj.AdditionalPaths, initData, parforF);
        end
    end
    
    methods (Access = protected)
        function group = getSpecificPropertyGroup(obj)
            group = struct('Cluster', obj.Cluster, ...
                           'AutoAttachFiles', obj.AutoAttachFiles, ...
                           'AutoAddClientPath', obj.AutoAddClientPath, ...
                           'AttachedFiles', {obj.AttachedFiles}, ...
                           'AdditionalPaths', {obj.AdditionalPaths});
            group = matlab.mixin.util.PropertyGroup(group);
        end
    end
    
    methods (Static, Hidden)
        function clusterOpts = build(cluster, varargin)
            p = parallel.parfor.Options.getBaseOptionsParser();

            logicalScalarValidation = ...
                @(x) validateattributes(x, {'logical'}, {'scalar'});
            p.addParameter('AutoAttachFiles', true, logicalScalarValidation);
            p.addParameter('AutoAddClientPath', true, logicalScalarValidation);

            oneOrMoreTextArgsValidation = @iOneOrMoreTextArgsValidation;
            p.addParameter('AttachedFiles', {}, oneOrMoreTextArgsValidation);
            p.addParameter('AdditionalPaths', {}, oneOrMoreTextArgsValidation);

            p.parse(varargin{:});
            clusterOpts = parallel.parfor.ClusterOptions(cluster, p.Results, p.UsingDefaults);
        end
    end
end

function iOneOrMoreTextArgsValidation(arg)
    if ~matlab.internal.datatypes.isText(arg)
        error(message('parallel:lang:parfor:OptionsArgumentMustBeText'));
    end
end
