classdef ConfigBuildStrategy < coder.connectivity.buildservices.IApplicationBuildStrategy
%CONFIGBUILDSTRATEGY Strategy class to allow coder connectivity
% configurations to customize the XIL application build. This is used by
% rtw.connectivity.Builder and rtw.connectivity.MakefileBuilder to register
% their overridable functions with the instance using registerFunctionOverride
% When rtw.pil.ApplicationBuildManager executes the build with this
% strategy the registered overrides are executed. If no override is
% specified the class reverts to the DefaultBuildStrategy behavior.

%   Copyright 2020 The MathWorks, Inc.
    
    properties (Access=private)
        FunctionOverrideMap containers.Map
        DefaultBuildStrategy coder.connectivity.buildservices.IApplicationBuildStrategy = rtw.pil.ApplicationBuildManager.empty()
    end
    
    properties (SetAccess=private)
        TargetServices coder.connectivity.targetservices.ITargetServices = coder.connectivity.connectivityconfig.TargetServices.empty();
        PILBuildOptions rtw.pil.SILPILBuildOptions
    end
    
    methods        
        
        % This constructor must be default constructable as it is required
        % to be created before the build takes place.
        function this = ConfigBuildStrategy()
            this.FunctionOverrideMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
            this.DefaultBuildStrategy = rtw.pil.ApplicationBuildManager(this);
        end
        
        % Set the target services to the strategy, this contains target
        % specific information for the build.
        function setTargetServices(this, targetServices)
            this.TargetServices = targetServices;
            this.DefaultBuildStrategy.setTargetServices(targetServices);
        end
        
        % Set the PIL build options for the strategy, this contains the
        % application specific information for the build.
        function setPILBuildOptions(this, pilBuildOptions)
            this.PILBuildOptions = pilBuildOptions;
            this.DefaultBuildStrategy.setPILBuildOptions(pilBuildOptions);
        end
        
        % Register a strategy function override with this instance. This
        % function allows rtw.connectivity.Builder instances to inject user
        % overridden methods into the build.
        function registerFunctionOverride(this, functionName, callBack)
            
            this.FunctionOverrideMap(functionName) = callBack;
        end
        
        % Sets the default build strategy if this instance has no override
        % registered
        function setDefaultBehavior(this, buildStrategy)
            this.DefaultBuildStrategy = buildStrategy;
        end
        
        % Gets the default build strategy behaviour for this instance.
        function buildStrategy = getDefaultBehavior(this)
            buildStrategy = this.DefaultBuildStrategy;
        end
        
        function matFileContents = getComponentBuildInfoMATFileContents(this, componentBuildInfoPath)
            
            matFileContents = this.strategyEval('getComponentBuildInfoMATFileContents', componentBuildInfoPath);
        end % BUILDER
        
        function buildInfo = processComponentIntegrationBuildInfo(this, componentBuildInfo)
            
            buildInfo = this.strategyEval('processComponentIntegrationBuildInfo', componentBuildInfo);
        end % BUILDER
        
        function [applicationBuildInfo, appFrameworkUpdated] = createApplicationBuildInfo(this, ...
                                                                                 componentIntegrationBuildInfo, ...
                                                                                 targetApplicationBuildInfo, ...
                                                                                 prevTargetApplicationBuildInfo)
            
            [applicationBuildInfo, appFrameworkUpdated] = this.strategyEval('createApplicationBuildInfo', componentIntegrationBuildInfo, ...
                                                                                                          targetApplicationBuildInfo, ...
                                                                                                          prevTargetApplicationBuildInfo);
        end % BUILDER
                                                                             
        
        function doBuild(this, buildInfo, varargin)
            this.strategyEval('doBuild', buildInfo, varargin{:});
        end % BUILDER
        
        function doUpdateBuild(this, applicationBuildInfo)
            this.strategyEval('doUpdateBuild', applicationBuildInfo);
        end % BUILDER
        
        function applicationPath = getApplicationPath(this)
            applicationPath = this.strategyEval('getApplicationPath');
        end % BUILDER
        
        function componenetRelativePath = getRelativePathFromApplicationToComponent(this) % MAKEFILEBUILDER
            componenetRelativePath = this.strategyEval('getRelativePathFromApplicationToComponent');
        end
        
        % Get the file separator for the target toolchain. 
        function fileSeparator = getFileSeparator(this) % MAKEFILEBUILDER
            fileSeparator = this.strategyEval('getFileSeparator');
        end
        
        function fullFileResult = fullFile(this, varargin)
            fullFileResult = this.strategyEval('fullFile', varargin{:});
        end % MAKEFILEBUILDER
        
        function exeExtension = getExecutableFileExtension(this) % MAKEFILEBUILDER
            exeExtension = this.strategyEval('getExecutableFileExtension');
        end
    end
    
    methods (Access=private)
        
        function varargout = strategyEval(this, functionName, varargin)
            
            if this.FunctionOverrideMap.isKey(functionName)
                [varargout{1:nargout}] = feval(this.FunctionOverrideMap(functionName), varargin{:});
            else
                [varargout{1:nargout}] = this.DefaultBuildStrategy.(functionName)(varargin{:});
            end
        end
    end
end

