%MATLABDriveUtils - a collection of utilities for using MATLAB Drive on clusters.
%
% See also MATLABDrivePathMap

% Copyright 2016-2020 The MathWorks, Inc.

classdef ( Hidden, Sealed ) MATLABDriveUtils
    
    methods ( Static )
        % -----------------------------------------------------------------
        % Functions for use on clients or workers.
        
        function [ hasMATLABDrive, canonicalMATLABDriveFolder ] = getCanonicalMATLABDriveFolder()
            %getCanonicalMATLABDriveFolder   Returns a canonical path to MATLAB Drive folder if available.
            %  Checks if MATLAB has access to MATLAB Drive, 
            %  and returns a canonical path to the MATLAB Drive folder if we have one.
            MATLABDriveFolder = safeCallmatlabdrive();
            hasMATLABDrive = ~isempty( MATLABDriveFolder );
            if hasMATLABDrive
                canonicalMATLABDriveFolder = parallel.internal.apishared.FilenameUtils.getCanonicalPath( MATLABDriveFolder );
            else
                canonicalMATLABDriveFolder = '';
            end
        end
        
        % -----------------------------------------------------------------
        % Functions for use on workers
       
        function isEnabled = isMATLABDriveEnabledOnWorker()
            %isMATLABDriveEnabledOnWorker   Checks if MATLAB Drive has been enabled on a worker.
            root = distcomp.getdistcompobjectroot;
            runprop = root.CurrentRunprop;
            isEnabled = runprop.MATLABDriveEnabled;
        end        
    end
    
    methods ( Static, Hidden )
        % -----------------------------------------------------------------
        % Functions for use on clients
        
        function [ isInMATLABDrive, relativeClientPath ] = getRelativeClientPath( rawClientPath )
            %getRelativeClientPath   Checks if rawClientPath is in MATLAB Drive, and returns
            %  relativeClientPath, a path relative to the MATLAB Drive,
            %  with path separators of the client operating system.
            [ hasMATLABDrive, canonicalMATLABDriveFolder ] = parallel.internal.apishared.MATLABDriveUtils.getCanonicalMATLABDriveFolder();
            if ~hasMATLABDrive
                isInMATLABDrive = false;
                relativeClientPath = '';
                return;
            end
            
            canonicalPath = parallel.internal.apishared.FilenameUtils.getCanonicalPath( rawClientPath );
            % We must check if canonicalPath is identical to canonicalMATLABDriveFolder, because
            % parallel.internal.apishared.FilenameUtils.isRelativePath
            % does not consider canonicalPath to be relative to canonicalMATLABDriveFolder if they are the same.
            if strcmp( canonicalMATLABDriveFolder, canonicalPath )
                isInMATLABDrive = true;
                relativeClientPath = '';
            else
                isInMATLABDrive = parallel.internal.apishared.FilenameUtils.isRelativePath( canonicalMATLABDriveFolder, canonicalPath );
                if isInMATLABDrive
                    relativeClientPath = parallel.internal.apishared.FilenameUtils.getRelativePath( canonicalMATLABDriveFolder, canonicalPath );
                else
                    relativeClientPath = '';
                end
            end
        end
        
        % -----------------------------------------------------------------
        % Functions for use on workers
        
        function [ hasMATLABDriveFolder, MATLABDriveClusterPath ] = getMATLABDriveClusterPath( relativeClientPath )
            %getMATLABDriveClusterPath   Generates a MATLABDriveClusterPath from a relativeClientPath.
            %  Called on a worker with parallel.internal.apishared.MATLABDrivePathMap.
            [ hasMATLABDriveFolder, MATLABDriveFolder ] = parallel.internal.apishared.MATLABDriveUtils.getCanonicalMATLABDriveFolder();
            if hasMATLABDriveFolder
                relativeClusterPath = parallel.internal.apishared.FilenameUtils.fixSlashes( relativeClientPath );
                MATLABDriveClusterPath = fullfile( MATLABDriveFolder, relativeClusterPath );
            else
                MATLABDriveClusterPath = '';
            end
        end
        
        function tf = forcePathTranslation( enabled )
            %forcePathTranslation    Force path translation to always occur.
            % Call with no arguments to check if path translation should be forced.
            % Call with true to force path translation to occur.
            % Defaults to false.
            persistent forcePathTraslation;
            if nargin == 1
                forcePathTraslation = enabled;
            elseif isempty(forcePathTraslation)
                forcePathTraslation = false;
            end
            tf = forcePathTraslation;
        end
    end
end

% Calls matlabdrive but returns an empty path
% if the NotSupported error is thrown.
function path = safeCallmatlabdrive()
path = '';
try
    path = matlabdrive();
catch ME
    if (~strcmp(ME.identifier, 'matlab:MATLABDrive:NotSupported'))
        rethrow(ME)
    end
end
end
