function workerFolder = getAttachedFilesFolder( attachedFileName )
% getAttachedFilesFolder Get the path of any attached file or folder on
% the worker
%
%   folder = getAttachedFilesFolder returns a character vector identifying
%   the path name of the local folder into which AttachedFiles are written.
%
%   folder = getAttachedFilesFolder(attachedFileName) returns the path name
%   to the specified folder on the worker, or the folder containing the
%   specified file. attachedFileName can match on any part of the folder or
%   file name. Multiple match results are returned as a cell array.
%
%
% This function returns an empty array if called in a MATLAB session that is not a worker.
%
%   Example 1:
%
%   % Attach a folder to a parallel pool
%   myPool = parpool;
%   addAttachedFiles(myPool,'mydir');
%   spmd
%       % Find the corresponding mydir folder on the worker
%       folder = getAttachedFilesFolder('mydir');
%
%       % Change to that folder to invoke an executable
%       oldFolder = cd(folder);
%
%       % Invoke an executable file
%       [OK, output] = system('myExecutable');
%
%       % Change back to the original folder
%       cd(oldFolder);
%   end
%
%   Example 2:
%   % Attach an executable to a parallel pool
%   % And CD into the executable folder to retrieve some data
%   myPool = parpool;
%   addAttachedFiles(myPool,'myExecutable');
%   spmd
%       % Run myExecutable (which is now on the MATLAB path)
%       system('myExecutable');
%
%       % Find myExecutable folder
%       folder = getAttachedFilesFolder('myExecutable');
%
%       % Change to myExecutable folder to retrieve the data produced
%       oldFolder = cd(folder);
%
%       % open and process data
%       fid = open('myData.txt');
%       % process fid
%       close(fid)
%
%       % Change back to the original folder
%       cd(oldFolder);
%   end
%
%
% See also getCurrentCluster, getCurrentWorker,
%          getCurrentJob, getCurrentTask, AttachedFiles.

%  Copyright 2006-2019 The MathWorks, Inc.


% Input validation
narginchk( 0, 1 );

if nargin == 1

    % Convert any string inputs to character vectors
    attachedFileName = convertStringsToChars(attachedFileName);

    % We clearly state we do not support cell arrays
    if iscellstr( attachedFileName )
        error( message( 'parallel:cluster:GetAttachedFilesFolderStringRequired' ) );
    end

    % If it is not a cell array, it must be a non-empty string
    validateattributes( attachedFileName, {'char'}, {'nonempty', 'row'} );
end


try
    % Get the runtime properties of the cluster
    root = distcomp.getdistcompobjectroot;
    runprop = root.CurrentRunprop;
    attachedFilesFolder = runprop.getAttachedFilesFolder();

    if nargin == 1 % Passing an attachedFileName

        attachedFileName = strrep( attachedFileName, '\', '/' ); % Unix style

        % Take into account that the user could specify directories by
        % adding a final slash '/'. For instance, the user could ask for
        % 'afolder' or 'afolder/'. However, do not strip the "trailing"
        % slash for '/', in the unlikely event the user has attached it...
        attachedFileName = [ attachedFileName(1) regexprep( attachedFileName(2:end), '/+$', '' ) ];

        allKeys = runprop.AttachedFilesPathMap.keys;
        endsWithAttachedFileName = @(str) length( str ) >= length( attachedFileName ) && strcmp( str(end-length(attachedFileName)+1:end), attachedFileName );
        keysToConsider = allKeys( :, cellfun( endsWithAttachedFileName, allKeys ) ); % Two subscripts for a consistent 1x0 cell array for no matches

        pathsToReturn = cell( size( keysToConsider ) );

        % In the common case, this should return a single value. But in the
        % case of multiple matches we return a cell array with all the
        % worker folders

        for k = 1:numel( keysToConsider )

            absPath = fullfile( attachedFilesFolder, runprop.AttachedFilesPathMap.get( keysToConsider{k} ) );

            if parallel.internal.apishared.FilenameUtils.fileExists( absPath )
                % pathMap contains a file->file mapping. Since we want the
                % directory, let's strip the file name.
                absPath = fileparts( absPath );
            end

            pathsToReturn{k} = absPath;
        end

        % Convert to a string if the cell array contains only one cell
        if numel( pathsToReturn ) == 1
            workerFolder = pathsToReturn{1};
        else
            workerFolder = pathsToReturn;
        end

    else
        % Default behaviour
        workerFolder = attachedFilesFolder;
    end


catch E %#ok<NASGU>
    % We expect workers to have a JVM, but this function may have 
    % been called on a client.
    dctErrorIfNoJVM();
    
    if feature('isdmlworker')
        warning( message( 'parallel:cluster:GetAttachedFilesFolderFailed' ) );
    else
        warning( message( 'parallel:cluster:GetAttachedFilesFolderCalledOnClient' ) );
    end
    
    workerFolder = '';
end
