% AbstractClusterMemento - class for constructing cluster objects for display of clusters or their associated jobs and tasks

% Copyright 2012-2018 The MathWorks, Inc.

classdef (Abstract, Hidden) AbstractClusterMemento < parallel.internal.display.Memento
    
    properties (SetAccess = immutable, GetAccess = protected)
        % The type of cluster
        Type
        % The minimum PV pairs necessary to create a cluster that displays
        % the same as the underlying cluster.
        Data
    end
    properties (Transient, Constant, GetAccess = private)
        % Constant map of cluster type to constructor function. The memento
        % is designed to be serialized, but this map should NEVER be
        % serialized, so it is explicitly marked Transient.
        ConstructorMap = iConstructorMap;
    end
    
    methods
        function obj = AbstractClusterMemento(type, data)
            obj.Type = type;
            obj.Data = data;
        end
        
        function c = createObjectFromMemento(obj)
            import parallel.internal.cluster.ClusterCache
            % The cluster we are looking for might be in the cache of
            % recently used clusters
            c = ClusterCache.Instance.get(obj);
            if ~isempty(c)
                % If the cluster type is MJS, then we need to check the
                % cached cluster object is in a valid state. See g1778660.
                if ~isa(c, 'parallel.cluster.MJS') || parallel.internal.types.States.isValidState(c.State)
                    return
                end
            end
            % If the cluster is not in the cache, we use the memento data
            % to construct a new cluster object and add it to the cache.
            constructor = obj.ConstructorMap(obj.Type);
            paramNames  = fieldnames(obj.Data);
            paramValues = struct2cell(obj.Data);
            args = [paramNames'; paramValues'];
            c = constructor(args{:});
            ClusterCache.Instance.add(obj, c);
        end
        
    end
end

function cm = iConstructorMap()
cm                                      = containers.Map;
cm ('parallel.cluster.MJS')             = @parallel.cluster.MJS;
cm ('parallel.cluster.MJSComputeCloud') = @parallel.cluster.MJSComputeCloud;
cm ('parallel.cluster.Local')           = @parallel.cluster.Local;
cm ('parallel.cluster.Generic')         = @parallel.cluster.Generic;
cm ('parallel.cluster.HPCServer')       = @parallel.cluster.HPCServer;
cm ('parallel.cluster.LSF')             = @parallel.cluster.LSF;
cm ('parallel.cluster.PBSPro')          = @parallel.cluster.PBSPro;
cm ('parallel.cluster.Slurm')           = @parallel.cluster.Slurm;
cm ('parallel.cluster.Torque')          = @parallel.cluster.Torque;
cm ('parallel.cluster.TaskRunner')      = @parallel.cluster.TaskRunner;
end
