classdef ActionsHandler
    %ACTIONSHANDLER Summary of this class goes here
    %   Detailed explanation goes here
    
    %   Copyright 2019 The MathWorks, Inc.
    
    properties(Abstract, Constant)
        ActionID
    end
    
    methods(Sealed)
        
        function response = handle(this, clientData)
            % add response for the current workflow action
            response = struct;
            response.isSuccess = false;
            
            % get the current model from the fptInstance
            fptInstance = fxptui.FixedPointTool.getExistingInstance();
            model = fptInstance.getModel;
            
            % get the current Workflow from DataLayer
            dataLayer = fxptds.DataLayerInterface.getInstance();
            workflow = dataLayer.getCurrentWorkflow(model);
            workflowSetting = workflow.WorkflowSetting;
            
            try
                % check if the workflow can be executed
                [~, diagnostic] = this.check();
                if ~isempty(diagnostic)
                    throw(diagnostic);
                end
                
                % use the client data if provided to set the workflow
                % settings
                this.prepare(fptInstance, workflowSetting, clientData);
                
                % execute actions
                this.executeActions(workflow);
                this.handleSuccess(fptInstance, workflowSetting);
                
                % set the response to 'success'
                response.isSuccess = true;
            catch e
                this.handleError(e, fptInstance, workflowSetting);
            end
            
            this.cleanup(fptInstance);
        end
        
        function [canProceed, diagnostic] = check(this)
            
            % get the current model from the fptInstance
            fptInstance = fxptui.FixedPointTool.getExistingInstance();
            model = fptInstance.getModel;
            
            % get the current Workflow from DataLayer
            dataLayer = fxptds.DataLayerInterface.getInstance();
            workflow = dataLayer.getCurrentWorkflow(model);
            
            [canProceed, diagnostic] = this.checkConflictDetectors(workflow);
            
        end
        
    end
    
    methods(Sealed, Hidden)
        
        function refreshRunBrowser(~, fptInstance, isError)
            % clicking on a callback button will change the state of
            % FPT to show that current view. if the callback was
            % unsuccessful, before getting into the execution, we need
            % to let the WorkflowBrowser know to update the view to the
            % last known good
            dataController = fptInstance.getDataController();
            runBrowserController = dataController.getRunBrowserController();
            
            runInfo = dataController.getRunBrowserData();
            runInfo.isError = isError;
            runBrowserController.updateRunBrowser(runInfo);
        end
        
        function executeActions(this, workflow)
            
            % get the concrete handler's actionID
            actionID = this.ActionID;
            
            % create an instance of the engine for the given action
            engine = fxptui.internal.WorkflowEngineFactory.getWorkflowEngine(actionID, workflow.WorkflowSetting);
            
            % gather all the actions from the given ID
            actions = workflow.getActions(actionID);
            
            workflowSetting = workflow.WorkflowSetting;
            
            % for each action, execute
            for idx = 1:numel(actions)
                action = actions(idx);
                action.execute(engine, workflowSetting);
            end
            
        end
        
        function [canProceed, diagnostic] = checkConflictDetectors(this, workflow)
            % define the default outputs
            canProceed = true;
            diagnostic = MException.empty();
            
            % get the concrete handler's actionID
            actionID = this.ActionID;
            
            % gather all the actions from the given ID
            conflictDetectors = workflow.getConflictDetectors(actionID);
            
            % get the current workflowSetting and facade
            dataLayer = fxptds.DataLayerInterface.getInstance();
            workflowSetting = workflow.WorkflowSetting;
            designSetting = workflowSetting.getSettingValue('DesignSetting');
            facade = dataLayer.getWorkflowTopologyFacade(designSetting.TopModel);
            
            % for each conflict detector, detect a possible error
            for idx = 1:numel(conflictDetectors)
                detector = conflictDetectors(idx);
                detectedError = detector.detect(workflowSetting, facade);
                if detectedError
                    % if detected an error return that it can not proceed,
                    % save the diagnostic and break
                    canProceed = false;
                    diagnostic = detector.getDiagnostic();
                    break;
                end
            end
            
        end
        
    end
    
    methods(Abstract)
        % execute actions
        prepare(this, varargin)
        handleSuccess(this, varargin);
        handleError(this, varargin);
        cleanup(this, varargin);
    end
end

