% MJSComputeCloud - Perform discovery for MJSComputeCloud

%    Copyright 2012-2020 The MathWorks, Inc.

classdef MJSComputeCloud < parallel.internal.discover.AbstractDiscoverer

    methods
        function obj = MJSComputeCloud()
            import parallel.internal.types.SchedulerType
            obj = obj@parallel.internal.discover.AbstractDiscoverer(SchedulerType.MJSComputeCloud);
        end
    end

    methods % overrides of Abstract methods in AbstractDiscoverer
        function discover(obj, terminateEarlyFcn)
            % discover - discover MJSComputeCloud clusters
            % Fires ClusterFound events for each cluster
            % returned from the call to cloud center.
            % We need to repeatedly check if the terminateEarlyFcn() 
            % in case the user has asked us to cancel discovery.
            validateattributes(terminateEarlyFcn, {'function_handle'}, {'scalar'});
            
            try
                clusterInfos = parallel.internal.cluster.MJSComputeCloudFinder.getAllClusters();
                if terminateEarlyFcn()
                    return;
                end

                % For now, we'll let the cloud center decide if the cluster is compatible.  At some
                % point in the future, we may allow the clusters to be backwards compatible in the
                % same way as MJS.
                isCompatible = parallel.internal.cluster.MJSComputeCloudFinder.isCompatibleCluster(clusterInfos);
                if terminateEarlyFcn()
                    return;
                end

                for ii = 1:numel(clusterInfos)
                    obj.notifyFound(clusterInfos(ii), isCompatible(ii));
                    if terminateEarlyFcn()
                        return;
                    end
                end
            catch ex
                % notify listeners of the failed discovery, if this is an authentication failure
                if strcmp(ex.identifier, 'parallel:cluster:cloudcenterclient:CloudCenterAuthenticationFailure')
                    obj.notify('DiscoveryFailed', ...
                        parallel.internal.discover.DiscoveryFailedEventData(ex));
                end
                
                % ... and re-throw the exception
                rethrow(ex);
            end
        end
    end

    methods (Access = private)
        function notifyFound(obj, clusterInfo, isCompatible)

            schPropNames = {'Identifier', 'Certificate', 'ClusterSharedState'};
            propNames = {'Name', 'NumWorkers', 'Identifier', 'Certificate', 'ClusterSharedState'};
            propVals = {clusterInfo.ClusterName, ...
                clusterInfo.NumberOfWorkers, ...
                clusterInfo.ClusterID,...
                clusterInfo.SSLCertificate,...
                clusterInfo.ClusterSharedState};

            matlabRelease = clusterInfo.MatlabReleaseVersion;
            evtData = parallel.internal.discover.ClusterFoundEventData.createForMJSComputeCloud(...
                propNames, propVals, schPropNames, matlabRelease, isCompatible);
            obj.notify('ClusterFound', evtData);
        end
    end
end
