classdef Config < handle
%CONFIG ties individual components together in a configuration
%
%   CONFIG(COMPONENTARGS,BUILDER,LAUNCHER,COMMUNICATOR) collects together
%   instances of a BUILDER, a LAUNCHER and a COMMUNICATOR to create a complete
%   target connectivity configuration.
%
%   You must make a subclass that provides the BUILDER, LAUNCHER and
%   COMMUNICATOR arguments.  The subclass must create instances of these classes
%   and instantiate this super class with them.
%
%   See also RTW.CONNECTIVITY.COMPONENTARGS, RTW.CONNECTIVITY.MAKEFILEBUILDER,
%   RTW.CONNECTIVITY.LAUNCHER, RTW.CONNECTIVITY.RTIOSTREAMHOSTCOMMUNICATOR,
%   CODER.MYPIL.CONNECTIVITYCONFIG

%   Copyright 2007-2018 The MathWorks, Inc.
%   

   % private properties
   properties(SetAccess = 'private', GetAccess = 'private')
        ComponentArgs;
        % documented components
        Builder;
        Launcher;
        Timer;
        % partially documented components
        Communicator;
        % undocumented components
        ExtendedHardwareConfig;
        
        % documented feature
        % remove the overhead introduced from the profiling instrumentation
        % The overhead can be estimated by running a benchmark when the
        % simulation starts or the average values can be hand coded
        ProfilingOverheadFilter;
        % ask to run the benchmark and specify the number of iterations
        ProfilingOverheadRunBenchmark;
        ProfilingOverheadBenchmarkSteps;
        % average overheads for Task, Function and Filter profiling
        ProfilingTaskOverhead;
        ProfilingFunctionOverhead;
        ProfilingFreezingOverhead;
    end

    methods
        % constructor
        function this = Config(componentArgs, ...
                               builder, ...
                               launcher, ...
                               communicator)
            narginchk(4, 4);
            % validate args
            rtw.connectivity.Utils.validateArg(componentArgs, ...
                'coder.connectivity.ComponentArgs');
            rtw.connectivity.Utils.validateArg(builder, ...
                'rtw.connectivity.Builder');
            rtw.connectivity.Utils.validateArg(launcher, ...
                'rtw.connectivity.Launcher');
            rtw.connectivity.Utils.validateArg(communicator, ...
                'rtw.connectivity.Communicator');
            % store properties
            this.ComponentArgs = componentArgs;
            this.Builder = builder;
            this.Launcher = launcher;
            this.Communicator = communicator;
            this.ProfilingOverheadFilter = false;
            this.ProfilingOverheadRunBenchmark = false;
            this.ProfilingTaskOverhead = 0;
            this.ProfilingFunctionOverhead = 0;
            this.ProfilingFreezingOverhead = 0;
            this.ProfilingOverheadBenchmarkSteps = 100;
            % create default hardware config
            this.setExtendedHardwareConfig(rtw.connectivity.ExtendedHardwareConfig);
        end
   
        % property set function for extendedHardwareConfig because
        % it is set from multiple code locations
        function set.ExtendedHardwareConfig(this, value)
            narginchk(2, 2);         
            % validate args
            rtw.connectivity.Utils.validateArg(value, ...
                'rtw.connectivity.ExtendedHardwareConfig');     
            this.ExtendedHardwareConfig = value;            
        end
        
        % property set function for Timer 
        % this provides a way to switch on execution profiling
        function set.Timer(this, value)
            narginchk(2, 2);         
            % validate args
            if ~isempty(value)
                if ~isa(value, 'coder.profile.Timer')
                    rtw.connectivity.Utils.validateArg...
                        (value, 'RTW.TflTable');
                end
                this.Timer = coder.profile.private.TimerWrap(value);
            else 
                this.Timer = value;
            end
        end
    
        % enable the filtering of the overhead for profiling API
        function activateOverheadFiltering (this, val)
            narginchk(2, 2);
            rtw.connectivity.Utils.validateArg(val, 'logical');
            this.ProfilingOverheadFilter = val;
        end
        function res = isOverheadFilteringActive (this)
            narginchk(1, 1);
            res = this.ProfilingOverheadFilter;
        end

        % estimate the overhead by running a benchmark
        function runOverheadBenchmark (this, val)
            narginchk(2, 2);
            rtw.connectivity.Utils.validateArg(val, 'logical');
            this.ProfilingOverheadRunBenchmark = val;
        end
        function res = isOverheadBenchmarkExecuted (this)
            narginchk(1, 1);
            res = this.ProfilingOverheadRunBenchmark;
        end

        % provide the number of iteration for the benchmark
        function setOverheadBenchmarkSteps (this, steps)
            narginchk(2, 2);
            assert(steps == floor(steps) && steps > 0, 'Number of steps must be an integer');
            this.ProfilingOverheadBenchmarkSteps = steps;
        end
        function steps = getOverheadBenchmarkSteps (this)
            narginchk(1, 1);
            steps = this.ProfilingOverheadBenchmarkSteps;
        end

        % provide hand-coded average overheads
        function setOverheads (this, taskInstr, functionInstr, freezingInstr)
            narginchk(4, 4);
            assert(taskInstr == floor(taskInstr) && taskInstr >= 0, ...
                'The overhead must be an integer');
            assert(functionInstr == floor(functionInstr) && functionInstr >= 0, ...
                'The overhead must be an integer');
            assert(freezingInstr == floor(freezingInstr) && freezingInstr >= 0, ...
                'The overhead must be an integer');
            this.ProfilingTaskOverhead = taskInstr;
            this.ProfilingFunctionOverhead = functionInstr;
            this.ProfilingFreezingOverhead = freezingInstr;
        end
        function [tsk, fcn, frz] = getOverheads (this)
            narginchk(1, 1);
            tsk = this.ProfilingTaskOverhead;
            fcn = this.ProfilingFunctionOverhead;
            frz = this.ProfilingFreezingOverhead;
        end
    end

    methods (Sealed)
      function componentArgs = getComponentArgs(this)
         narginchk(1, 1);
         componentArgs = this.ComponentArgs;
      end
        
      function builder = getBuilder(this)
         narginchk(1, 1);
         builder = this.Builder;
      end 
   
      function launcher = getLauncher(this)
         narginchk(1, 1);   
         launcher = this.Launcher;
      end

      function timer = getTimer(this)
         narginchk(1, 1);   
         timer = this.Timer;
      end

      function communicator = getCommunicator(this)
         narginchk(1, 1);
         communicator = this.Communicator;
      end
            
      function setTimer(this, timer)
          narginchk(2, 2);
          this.Timer = timer;
      end            
    end
    
    methods (Sealed, Hidden)
        function extendedHardwareConfig = getExtendedHardwareConfig(this)
            narginchk(1, 1);
            extendedHardwareConfig = this.ExtendedHardwareConfig;
        end
        
        % unpublished function allowing (internal) override of the default
        % extended hardware configuration settings
        %
        % once this information is available via the configuration set
        % then the extended hardware configuration settings will no longer
        % be required
        function setExtendedHardwareConfig(this, extendedHardwareConfig)
            narginchk(2, 2);
            % allow access to ComponentArgs
            extendedHardwareConfig.setComponentArgs(this.ComponentArgs);
            this.ExtendedHardwareConfig = extendedHardwareConfig;
        end
    end
end
