function distcomp_evaluate_filetask(varargin)
%

% Copyright 2005-2020 The MathWorks, Inc.

try
    logLevel = parallel.internal.logging.getWorkerLogLevel();
    debugEnabled = logLevel > 0;
    setSchedulerMessageHandler(iMessageHandler(logLevel));

    syncTaskEvaluation = getenv('MDCE_SYNCHRONOUS_TASK_EVALUATION');
    % Synchronous task evaluation is enabled if MDCE_SYNCHRONOUS_TASK_EVALUATION 
    % is defined and is set to true
    useSyncEvaluation = ~isempty(syncTaskEvaluation) && strcmpi(syncTaskEvaluation, 'true');

    % Initialize MatlabRefStore
    com.mathworks.toolbox.distcomp.util.MatlabRefStore.initMatlabRef();

    % If this a deployed (local) worker then we need to tell the deployed 
    % application not to simply exit when distcomp_evaluate_filetask returns - 
    % if the task is part of a parallel pool then the worker needs to remain
    % alive after this function returns
    iPreventDeployedWorkerExiting();

    if useSyncEvaluation
        % TODO: This is a workaround for a problem with SOA jobs. See g846800 and g846801.
        dctSchedulerMessage(6, 'Using synchronous task evaluation: calling distcomp_evaluate_filetask_core directly');
        % distcomp_evaluate_filetask_core expects an outputWriterStack.
        outputWriterStack = com.mathworks.toolbox.distcomp.cwo.WriterStack();
        distcomp_evaluate_filetask_core(outputWriterStack, debugEnabled, useSyncEvaluation, varargin{:});
    else
        dctSchedulerMessage(4, 'About to evaluate task with DistcompEvaluateFileTask');
        argsForTaskEvaluation = [useSyncEvaluation, varargin];
        % This serializes the arguments, and uses the MVM feval to call
        % distcomp_evaluate_filetask_core.
        e = com.mathworks.toolbox.distcomp.cwo.DistcompEvaluateFileTask;
        e.evaluate(debugEnabled, argsForTaskEvaluation);
    end
catch err
    dctSchedulerMessage(0, 'Evaluating task with DistcompEvaluateFileTask failed, the error was: ', err);
    iAllowDeployedWorkerToExit();
    parallel.internal.cluster.exitOnException(1);
end
end

%--------------------------------------------------------------------------
%
%--------------------------------------------------------------------------
function handler = iMessageHandler(desiredLevel)

loglvl = com.mathworks.toolbox.parallel.pctutil.logging.DistcompLevel.getLevelFromValue(desiredLevel);
LOGGER = com.mathworks.toolbox.parallel.pctutil.logging.RootLog.LOG;
LOGGER.setLevel(loglvl);

handler = @nHandler;

    function nHandler(msg, messageLevel)    
    
    if messageLevel > desiredLevel
        return;
    end    
    
    % This handler puts messages to two places - stdout (via fprintf)
    fprintf('%s | %s\n', datestr(now, 31), msg)
    
    % And to the java logger
    level = com.mathworks.toolbox.parallel.pctutil.logging.DistcompLevel.getLevelFromValue(messageLevel);
    LOGGER.log(level, ['MATLAB: ', msg]);
    end
end

%--------------------------------------------------------------------------
%
%--------------------------------------------------------------------------
function iPreventDeployedWorkerExiting()
% If this is a parallel pool job then we need the deployed worker process
% to remain alive after distcomp_evaluate_filetask returns - the default behaviour
% is for a deployed application to exit when the main function returns.
if isdeployed
    parallel.internal.cluster.workerShutdown('prevent');
end
end

%--------------------------------------------------------------------------
%
%--------------------------------------------------------------------------
function iAllowDeployedWorkerToExit()
% Allow the deployed worker to exit. 
% If this was a parallel pool job this means the worker process can now exit. If 
% it was a normal job then the worker process will exit when 
% distcomp_evaluate_filetask returns.
if isdeployed
    parallel.internal.cluster.workerShutdown('allow');
end
end
