% ValidationDisplayer - Displayer for Profile Validation

% Copyright 2011-2016 The MathWorks, Inc.

classdef (Hidden, Sealed) ValidationDisplayer
    properties (Constant, GetAccess = private)
        StageSeparatorLength = 40
        StageSeparator = sprintf('%s\n', ...
            repmat('-', 1, parallel.internal.settings.ValidationDisplayer.StageSeparatorLength))
    end
    
    properties (GetAccess = private, SetAccess = immutable)
        % The listeners for the Validator's events
        StartListener
        FinishListener
        StageListener
    end
    
    methods
        function obj = ValidationDisplayer(validator)
            import parallel.internal.settings.ValidationDisplayer
            
            validateattributes(validator, {'parallel.internal.settings.AbstractValidator'}, {'scalar'});
            % Ensure that validation results are displayed to the command 
            % windows when validation is launched through the API.
            obj.StartListener  = event.listener(validator, 'ValidationStarted', ...
                @ValidationDisplayer.displayValidationStarted);
            obj.FinishListener = event.listener(validator, 'ValidationFinished', ...
                @ValidationDisplayer.displayValidationFinished);
            obj.StageListener  = event.listener(validator, 'ValidationStageUpdated', ...
                @ValidationDisplayer.displayStage);
        end
    end

    methods (Static, Access = private)
        function displayValidationStarted(~, eventData)
        % displayValidationStarted(~, eventData) - display Validation started
            import parallel.internal.settings.ValidationDisplayer
            validateattributes(eventData, ...
                {'parallel.internal.settings.ValidationEventData'}, {'scalar'});
            
            profileName = eventData.Profile;
            fprintf('%s', ValidationDisplayer.StageSeparator);
            fprintf('%s\n', ...
                getString(message('parallel:validation:StartingValidation', profileName)));
        end
        
        function displayValidationFinished(~, eventData)
        % displayValidationFinished(~, eventData) - display Validation finished.  Adds
        % a "Rerun" link if appropriate
            import parallel.internal.settings.ValidationDisplayer
            import parallel.internal.types.ValidationStatus
            validateattributes(eventData, ...
                {'parallel.internal.settings.ValidationEventData'}, {'scalar'});
            
            profileName = eventData.Profile;
            fprintf('%s\n', ...
                getString(message('parallel:validation:FinishedValidation', profileName)));
            fprintf('%s\n', ...
                getString(message('parallel:validation:StatusLabel', eventData.Status)));
            
            if eventData.StatusEnum == ValidationStatus.Failed && iShowLinks()
                rerunLink = sprintf(['<a href="matlab: ', ...
                    'parallel.internal.settings.runValidation(''%s'')">%s</a>'], ...
                    profileName, ...
                    sprintf('%s\n', ...
                        getString(message('parallel:validation:RerunValidation', profileName))));
                fprintf('%s\n', rerunLink);
            end
        end

        function displayStage(~, eventData)
        % displayStage(~, eventData) - display information related to a validation stage
            import parallel.internal.settings.ValidationDisplayer
            import parallel.internal.types.ValidationStatus
            validateattributes(eventData, ...
                {'parallel.internal.settings.ValidationEventData'}, {'scalar'});
            
            if eventData.StatusEnum == ValidationStatus.Running
                fprintf('%s', ValidationDisplayer.StageSeparator);
                fprintf('%s\n', ...
                    getString(message('parallel:validation:RunningStageLabel', eventData.Stage.Name)));
                fprintf('%s\n', ...
                    getString(message('parallel:validation:StartTimeLabel', char(eventData.Timestamp))));
            else
                % Must display the stage name if we are skipping the stage.
                if eventData.StatusEnum == ValidationStatus.Skipped
                    fprintf('%s', ValidationDisplayer.StageSeparator);
                    fprintf('%s\n', getString(message('parallel:validation:StageLabel', eventData.Stage.Name)));
                end
                
                fprintf('%s\n', ...
                    getString(message('parallel:validation:StatusLabel', eventData.Status)));
                
                if ~isempty(eventData.Description)
                    fprintf('%s\n', ...
                        getString(message('parallel:validation:DescriptionLabel', eventData.Description)));
                end

                if ~isempty(eventData.ErrorReport)
                    if iShowLinks()
                        errorToPrint = eventData.ErrorReport;
                    else
                        errorToPrint = eventData.ErrorReportNoLinks;
                    end
                    fprintf('%s\n', ...
                        getString(message('parallel:validation:ErrorLabel',  errorToPrint)));
                end
                if ~isempty(eventData.CommandWindowOutput)
                    cmdWndOutput = eventData.CommandWindowOutput;
                    fprintf('%s\n', ...
                        getString(message('parallel:validation:CommandWindowOutputLabel', cmdWndOutput)));
                end
                if ~isempty(eventData.DebugLog)
                    debugLog = eventData.DebugLog;
                    fprintf('%s\n', ...
                        getString(message('parallel:validation:DebugLogLabel', debugLog)));
                end
                fprintf('%s', ValidationDisplayer.StageSeparator);
            end
        end     
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Ensure we check each time we need to know.
function tf = iShowLinks()
    tf = feature('hotlinks');
end
