%OutputFolderCheckTask
% Class for holding all the details necessary for checking whether the output folder exists.
% This should be both serializable and immutable.

%   Copyright 2015-2016 The MathWorks, Inc.

classdef (Sealed, Hidden) OutputFolderCheckTask < parallel.internal.mapreduce.AbstractTask
    properties (GetAccess = private, SetAccess = immutable)
        OutputFolder = []; %Path of the final output folder.
    end
    
    methods
        % Create a task that checks whether the output folder is writable.
        % Syntax:
        % OutputFolderCheckTask(outputFolder, shuffleSortStrategy)
        % OutputFolderCheckTask(outputFolder, remoteMapReduceDetails)
        function obj = OutputFolderCheckTask(outputFolder, shuffleSortStrategyInput)
            obj = obj@parallel.internal.mapreduce.AbstractTask(shuffleSortStrategyInput);
            obj.OutputFolder = outputFolder;
        end
        
        % Runs the given map task.
        function results = run(obj)
            import parallel.internal.mapreduce.OutputFolderCheckResult;
            results = OutputFolderCheckResult(obj.isOutputAnExistingWritableFolder());
        end
        
    end
    
    methods (Access = private)
        % Checks whether the output folder exists and is writable.
        function isValidOutputFolder = isOutputAnExistingWritableFolder(obj)
            
            % The check is done via writing a file to the location.
            uniquepart   = char( net.jini.id.UuidFactory.generate );
            testFilename = sprintf( 'dct_test_file.%s.test', uniquepart );
            testPath = fullfile(obj.OutputFolder, testFilename);

            % Check to see if the file exists already. This is unlikely as
            % UuidFactory.generate is highly likely to be unique with respect
            % to other UUIDs generated by the same method over space and time.
            requiresDelete = ~exist(testPath, 'file');
            
            fid = fopen(testPath, 'a+');
            if fid < 0
                isValidOutputFolder = false;
                return;
            else
                isValidOutputFolder = true;
            end
            fclose(fid);
            
            if requiresDelete
                delete(testPath);
            end
        end
    end
    
    methods (Hidden)
        % Launch a task on the given pool.
        % Visitor will be an object/struct with both a runOnSingle and a 
        % runOnAll method. This should call one of those and return the
        % result.
        function future = hLaunchTask(obj, visitor)
            future = visitor.runOnAll(obj);
        end
    end
end
