% ConversionContext enumeration - defines the different contexts in which API properties
% can be converted.
% 
% Note that API2's NumWorkersRange are not converted to API1's Min/MaximumNumberOfWorkers
% because there is no direct mapping between these properties.

% Copyright 2011-2021 The MathWorks, Inc.
classdef ConversionContext
    enumeration
        Batch           (iGetConverterByContextName('Batch'));
        ClusterType     (iGetConverterByContextName('ClusterType'));
        Job             (iGetConverterByContextName('Job'));
        Task            (iGetConverterByContextName('Task'));
        Generic         (iGetConverterByContextName('Generic'));
        GenericR2016b   (iGetConverterByContextName('GenericR2016b'));
        HPCServer       (iGetConverterByContextName('HPCServer'));
        Local           (iGetConverterByContextName('Local'));
        LSF             (iGetConverterByContextName('LSF'));
        MJS             (iGetConverterByContextName('MJS'));
        PBSPro          (iGetConverterByContextName('PBSPro'));
        Slurm           (iGetConverterByContextName('Slurm'));
        Torque          (iGetConverterByContextName('Torque'));
    end
    
    properties (SetAccess = immutable, GetAccess = private)
        ToApi1ConverterMap
        ToApi2ConverterMap
    end
    
    methods
        function obj = ConversionContext(propConverterCell)
            obj.ToApi1ConverterMap = containers.Map(propConverterCell(:, 2), propConverterCell(:, 1));
            obj.ToApi2ConverterMap = containers.Map(propConverterCell(:, 1), propConverterCell(:, 2));
        end
    
        function propNames = convertToApi1(obj, propNames)
        % propNames = convertToApi1(obj, propNames)
        %   convert the supplied API2 property names to their API1 equivalents
        %   based on the current context.
            propNames = iConvertProps(obj.ToApi1ConverterMap, propNames);
        end
        
        function propNames = convertToApi2(obj, propNames)
        % propNames = convertToApi2(obj, propNames)
        %   convert the supplied API1 property names to their API2 equivalents
        %   based on the current context.
            propNames = iConvertProps(obj.ToApi2ConverterMap, propNames);
        end
    end
end

%---------------------------------------------------
function newProps = iConvertProps(converterMap, origProps)
% Convert props using the supplied conversion map.  Properties
% that aren't keys in the map are not changed.
returnCell = true;
if ~iscell(origProps)
    origProps = {origProps};
    returnCell = false;
end

newProps = origProps;
for ii = 1:numel(origProps)
    if ~converterMap.isKey(origProps{ii})
        continue;
    end
    newProps{ii} = converterMap(origProps{ii});
end

if ~returnCell
    newProps = newProps{1};
end
end


%---------------------------------------------------
function converterCell = iGetConverterByContextName(contextName)
% Get a specific converter based on the name of the context
persistent allContexts allConverters
if isempty(allContexts) && isempty(allConverters)
    [allContexts, allConverters]= iGetAllConverters();
end

idx = strcmp(contextName, allContexts);
converterCell = allConverters{idx};
end

%---------------------------------------------------
function [contexts, converters] = iGetAllConverters()
% Get all the converters used in this class.  The converters are
% cell arrays in the form {API1 name, API2 name}

% Cluster Types
clusterTypeConverter = { ...
    'generic', 'Generic'; ...
    'generic', 'GenericR2016b'; ...
    'hpcserver', 'HPCServer'; ...
    'local', 'Local'; ...
    'lsf', 'LSF'; ...
    'jobmanager', 'MJS'; ...
    'pbspro', 'PBSPro'; ...
    'slurm', 'Slurm'; ...
    'torque', 'Torque'; ...
    };
% File and paths
fileConverter = { ...
    'FileDependencies', 'AttachedFiles' };
fileAndPathConverter = [ ...
    fileConverter ;
    { 'PathDependencies', 'AdditionalPaths' } ];
% Job props
jobConverter = { ...
    % Parallel Job/MJS Job
    % Note the absence of Min and Max workers because these are far
    % too complicated to convert
    % MJS Job
    'QueuedFcn', 'JobQueuedFcn'; ...
    'RunningFcn', 'JobRunningFcn'; ...
    'FinishedFcn', 'JobFinishedFcn'; ...
    'Timeout', 'JobTimeout'; ...
    'RestartWorker', 'RestartWorker'; ...
    };
jobConverter = [fileAndPathConverter; jobConverter];
% Task props
taskConverter = { ...
    % Common Task
    'CaptureCommandWindowOutput', 'CaptureDiary'; ...
    % MJS Task
    'Timeout', 'TaskTimeout'; ...
    'MaximumNumberOfRetries', 'MaximumRetries'; ...
    'FinishedFcn', 'TaskFinishedFcn'; ...
    'RunningFcn', 'TaskRunningFcn'; ...
    };
% Cluster Props
configurationConverter = {'Configuration', 'Profile'};
allClusterPropConverter = [configurationConverter; {'Type', 'Type'}];
mjsConverter = { ...
    'Name', 'MJSName'; ...
    'LookupURL', 'Host'; ...
    'UserName', 'Username'; ...
    };
cjsConverter = { ...
    'ClusterSize', 'NumWorkers'; ...
    'DataLocation', 'JobStorageLocation'; ...
    'ClusterMatlabRoot', 'ClusterMatlabRoot'; ...
    'HasSharedFilesystem', 'HasSharedFilesystem'; ...
    'ClusterOsType', 'OperatingSystem'; ...
    'SubmitArguments', 'SubmitArguments'; ...
    };
hpcsConverter = { ...
    'SchedulerHostname', 'Host'; ...
    'UseSOAJobSubmission', 'UseSOAJobSubmission'; ...
    'ClusterVersion', 'ClusterVersion'; ...
    'JobTemplate', 'JobTemplate'; ...
    'JobDescriptionFile', 'JobDescriptionFile'; ...
    };
genericConverter = { ...
    'GetJobStateFcn', 'GetJobStateFcn'; ...
    'SubmitFcn', 'IndependentSubmitFcn'; ...
    'ParallelSubmitFcn', 'CommunicatingSubmitFcn'; ...
    'CancelJobFcn', 'CancelJobFcn'; ...
    'CancelTaskFcn', 'CancelTaskFcn'; ...
    'DestroyJobFcn', 'DeleteJobFcn'; ...
    'DestroyTaskFcn', 'DeleteTaskFcn'; ...
    };
lsfConverter = { ...
    'ParallelSubmissionWrapperScript', 'CommunicatingJobWrapper'; ...
    };
slurmConverter = { ...
    'ParallelSubmissionWrapperScript', 'CommunicatingJobWrapper'; ...
    };
pbsConverter = { ...
    'ParallelSubmissionWrapperScript', 'CommunicatingJobWrapper'; ...
    'ProcsPerNode', 'ProcsPerNode'; ...
    'RcpCommand', 'RcpCommand'; ...
    'ResourceTemplate', 'ResourceTemplate'; ...
    'RshCommand', 'RshCommand'; ...
    };
batchConverter = [configurationConverter; fileAndPathConverter; {'CurrentDirectory', 'CurrentFolder'}];

contexts = { ...
    'ClusterType'; ...
    'Job'; ...
    'Task'; ...
    'Generic'; ...
    'GenericR2016b'; ...
    'HPCServer'; ...
    'Local'; ...
    'LSF'; ...
    'MJS'; ...

    'PBSPro'; ...
    'Slurm'; ...
    'Torque'; ...
    'Batch'; ...
    };

converters = { ...
    clusterTypeConverter; ...
    jobConverter; ...
    taskConverter; ...
    [allClusterPropConverter; cjsConverter; genericConverter]; ...
    [allClusterPropConverter; cjsConverter; genericConverter]; ...
    [allClusterPropConverter; cjsConverter; hpcsConverter]; ...
    [allClusterPropConverter; cjsConverter]; ...
    [allClusterPropConverter; cjsConverter; lsfConverter]; ...
    [allClusterPropConverter; mjsConverter]; ...

    [allClusterPropConverter; cjsConverter; slurmConverter]; ...
    [allClusterPropConverter; cjsConverter; pbsConverter]; ...
    [allClusterPropConverter; cjsConverter; pbsConverter]; ...
    batchConverter; ...
    };
end
