classdef CollectionVerificationStrategy < fxptds.WorkflowTopology.Strategy
    %% COLLECTIONVERIFICATIONSTRATEGY class
    
    % Copyright 2019 The MathWorks, Inc.
    
    properties(SetAccess = private, GetAccess = public)
        ReportBuilder = fxptds.WorkflowTopology.utility.ActionReportBuilder();
    end
    
    properties(Dependent)
        VerificationFPTRunID
        BaselineFPTRunID
        BaselineSettings
    end
    
    methods
        function value = get.VerificationFPTRunID(this)
            % FPTRunID is given a double so because its value is used as a
            % name to create nodes, convert the number to a string
            value = num2str(this.WorkflowContext.FPTRunID);
        end
        
        function value = get.BaselineFPTRunID(this)
            % FPTRunID is given a double so because its value is used as a
            % name to create nodes, convert the number to a string
            value = num2str(this.WorkflowContext.BaselineFPTRunID);
        end
        
        function value = get.BaselineSettings(this)
            % Return the settings from the WorkflowContext
            value = this.WorkflowContext.Settings;
        end
    end
    
    % Access is protected and extended to Facade and to the test class
    methods (Access = {?fxptds.WorkflowTopology.Strategy, ?fxptds.WorkflowTopology.Facade, ?WorkflowTopologyTestCase})
        
        function execute(this)
            
            % get the DesignStore objects for the given baseline and
            % verification run IDs
            baselineMergeObject = this.Store.getNodeObject(this.BaselineFPTRunID);
            verificationMergeObject = this.Store.getNodeObject(this.VerificationFPTRunID);
            
            % reset the verification report
            this.resetMergedVerificationReport(verificationMergeObject)
            
            % check if the baseline run is in fact the merged baseline run
            % from multi simulation scenario
            if baselineMergeObject.isMultipleScenario
                [baselineScenarioNodes, verificationScenarioNodes] = this.getScenarioNodes();
                
                % if so, for each baseline scenario, merge scenario pair
                for idx = 1:numel(verificationScenarioNodes)
                    baselineScenarioNode = baselineScenarioNodes(idx);
                    verificationScenarioNode = verificationScenarioNodes(idx);
                    
                    % update the verification scenario with its respective
                    % baseline scenario
                    this.updateVerificationReport(verificationScenarioNode, baselineScenarioNode);
                    
                    % update the merged verification result given the
                    % status of the scenario verification result
                    this.updateMergedWithScenario(verificationScenarioNode, verificationMergeObject);
                    
                end
            else
                % otherwise update the given baseline to the given
                % verification only
                this.updateVerificationReport(verificationMergeObject, baselineMergeObject);
            end
            
        end
        
    end
    
    methods (Access = {?fxptds.WorkflowTopology.Strategy, ?WorkflowTopologyTestCase})
        
        function [baselineScenarioNodes, verificationScenarioNodes] = getScenarioNodes(this)
            % generate a query to get the nodes pointing into the merged
            % nodes
            query = this.createDefaultQuery();
            query.Type = "Collection";
            query.Search = 'parents';
            query.SortDirection = 'ascend';
            
            % convert the given baseline scenario names into node objects
            baselineScenarioNames = this.executeQuery(this.BaselineFPTRunID, query);
            baselineScenarioNodes = this.Store.getNodeObject(baselineScenarioNames);
            
            % convert the given verification scenario names into node objects
            verificationScenarioNames = this.executeQuery(this.VerificationFPTRunID, query);
            verificationScenarioNodes = this.Store.getNodeObject(verificationScenarioNames);
        end
        
        function resetMergedVerificationReport(this, verificationNode)
            % clear the merged VerificationReport to start fresh
            clearedReport = verificationNode.Report;
            clearedReport = this.ReportBuilder.resetVerificationStatus(clearedReport);
            clearedReport = this.ReportBuilder.resetScenarioReport(clearedReport);
            verificationNode.updateReport(clearedReport);
        end
        
        function updateVerificationReport(this, verificationNode, baselineScenarioNode)
            % given the verification node and baseline node and settings
            % used between them, build the report
            
            verificationReport = verificationNode.Report;
            verificationSDIRun = verificationNode.SDIRunID;
            constraintSettings = this.BaselineSettings.ConstraintSettings;
            
            % create comparisonUtil
            baselineComparisonUtil = DataTypeOptimization.SDIBaselineComparison();
            
            verificationReport = this.ReportBuilder.setConstraints(verificationReport, constraintSettings);
            verificationReport = this.ReportBuilder.setBaselineFPTRunID(verificationReport, baselineScenarioNode.FPTRunID);
            verificationReport = this.ReportBuilder.setVerificationStatus(verificationReport, baselineScenarioNode, verificationSDIRun, baselineComparisonUtil);
            verificationReport = this.ReportBuilder.setVerificationDetails(verificationReport, baselineScenarioNode, verificationSDIRun, baselineComparisonUtil);
            
            % set the result on the verification node
            verificationNode.updateReport(verificationReport);
        end
        
        function updateMergedWithScenario(this, scenarioNode, mergeNode)
            
            scenarioReport = scenarioNode.Report;
            mergeReport = mergeNode.Report;
            
            % get the VerificationStatus for each node to compare and
            % insert into statuses array
            mergeReport = this.ReportBuilder.setDominantVerificationStatus(scenarioReport, mergeReport);
            
            % set the max
            mergeReport = this.ReportBuilder.setMaxDifference(scenarioReport, mergeReport);
            
            % add the scenario's Report to the merged node's list of
            % related scenario's reports
            mergeReport = this.ReportBuilder.addScenarioReport(scenarioReport, mergeReport);
            
            mergeNode.updateReport(mergeReport);
            
        end
        
        function setReportBuilder(this, builder)
            this.ReportBuilder = builder;
        end
        
        
    end
    
end

