classdef Launcher < rtw.connectivity.Component
%LAUNCHER launches the application built by a BUILDER object
%
%   LAUNCHER(COMPONENTARGS,BUILDER) instantiates a LAUNCHER object that you can
%   use to control starting and stopping of an application on the target
%   processor.
%
%   The LAUNCHER supports starting and stopping of the application associated
%   with a BUILDER object.
%
%   You must make a subclass of LAUNCHER and implement the startApplication and
%   stopApplication methods.
%
%   Launcher abstract methods:
%
%       STARTAPPLICATION - called when a target application must be started. In
%                          this class it is an abstract method. When you make a
%                          subclass of LAUNCHER, you must provide an
%                          implementation of this method that starts the
%                          application.
%
%       STOPAPPLICATION  - called when a target application must be stopped. In 
%                          this class it is an abstract method. When you make a 
%                          subclass of LAUNCHER, you provide an 
%                          implementation of this method that stops the 
%                          application.
%  
%   Optionally, you can provide the following method:
%
%     GETAPPLICATIONSTATUS - called to detect the current status of the target application.
%                            When you make a subclass of LAUNCHER, you can provide an
%                            implementation of this method. 
%                            The expected return values are:
%                            - rtw.connectivity.LauncherApplicationStatus.UNKNOWN
%                            - rtw.connectivity.LauncherApplicationStatus.NOT_RUNNING
%                            - rtw.connectivity.LauncherApplicationStatus.RUNNING
%                            If you do not implement this method, the default return value is
%                            rtw.connectivity.LauncherApplicationStatus.UNKNOWN
% 
%
%   See also RTW.CONNECTIVITY.COMPONENTARGS, RTW.CONNECTIVITY.MAKEFILEBUILDER,
%   CODER.MYPIL.LAUNCHER

%   Copyright 2007-2023 The MathWorks, Inc.
%   

    % private properties
    properties (SetAccess = 'private', GetAccess = 'private')
        builder;
        internalData;
        exe = '';
        CoreClientInterface;
    end      
        
    methods
        % constructor
        function this = Launcher(componentArgs, ...
                                 builder)
            narginchk(1, 2);
            % call super class constructor                             
            this@rtw.connectivity.Component(componentArgs);                                         
            % validate arg
            if (nargin == 2)
                rtw.connectivity.Utils.validateArg(builder, ...
                                                   'rtw.connectivity.Builder');
                % store property
                this.builder = builder;
            end
            % create and store CoreClientInterface
            this.CoreClientInterface =...
                componentArgs.getClientInterface.createCoreClientInterface;
        end
    end        

    % methods can't be overridden
    methods (Sealed)
        function builder = getBuilder(this)
            narginchk(1, 1);
            
            if isempty(this.builder)
                rtw.connectivity.ProductInfo.error('target', ...
                                                   'EmptyBuilderError');
            end
            
            builder = this.builder;
        end
          
        function setExe(this, exe)
            narginchk(2, 2);
            this.exe = exe;
        end

        function exe = getExe(this)
            narginchk(1, 1);
            
            if isempty(this.exe)
                rtw.connectivity.ProductInfo.error('target', ...
                                                   'EmptyExeError');
            end
            
            exe = this.exe;
        end
    end
    
    methods (Sealed, Hidden)        
        function setInternalData(this, internalData)
            narginchk(2, 2);
            this.internalData = internalData;
        end
        
        function internalData = getInternalData(this)
            narginchk(1, 1);
            internalData = this.internalData;
        end                
    end
    
    methods (Sealed, Static)
        function setStartApplicationPause(pauseAmount)
            % enable start application pause support for this session
            %
            % validate arg
            rtw.connectivity.Utils.validateArg(pauseAmount, 'double');   
            rtw.connectivity.Launcher.persistentPause(pauseAmount);
        end   
    end
    
    methods (Sealed, Static, Hidden)        
        function pauseAmount = getPause
           pauseAmount = rtw.connectivity.Launcher.persistentPause; 
        end
    end        
   
    methods (Sealed=true, Access='protected')
       function startApplicationPause(this)
            % implement pause associated with setStartApplicationPause
            nl = newline;           
            pauseAmount = rtw.connectivity.Launcher.persistentPause;            
            if pauseAmount > 0                                       
                linkText = 'rtw.connectivity.Launcher.setStartApplicationPause(0)';
                link = targets_hyperlink_manager('new', linkText, linkText);
                
                msg = message('Connectivity:target:LauncherRemovePause');                
                this.dispInfo([nl '### ' msg.getString ' >> ' link nl]);                
                msg = message('Connectivity:target:LauncherPause', pauseAmount);                
                title = message('Connectivity:target:LauncherPauseTitle');                
                h = msgbox(msg.getString, title.getString);
                uiwait(h, pauseAmount);
                if ishandle(h)
                    close(h);
                end
            else
                % default pause is 2 minutes
                linkText = 'rtw.connectivity.Launcher.setStartApplicationPause(120)';
                link = targets_hyperlink_manager('new', linkText, linkText);
                msg = message('Connectivity:target:LauncherPauseDefault');
                this.dispInfo([nl '### ' msg.getString ' >> ' link nl]);
            end
        end 
    end
    
    methods (Static, Access = 'private')
        function pauseAmountOut = persistentPause(pauseAmountNew)
            % no support for static / class properties so we use a 
            % persistent variable instead
            persistent pauseAmount;
            if isempty(pauseAmount)
                pauseAmount = 0;
            end
            if nargin > 0
                pauseAmount = pauseAmountNew;
            end
            pauseAmountOut = pauseAmount;
        end
    end
    
    % abstract methods
    methods (Abstract)        

    startApplication(this)
    %STARTAPPLICATION - called when a target application must be started
    %
    %   STARTAPPLICATION 
    

    stopApplication(this)
    %STOPAPPLICATION  - called when a target application must be stopped
    %
    %   
    end

    % optional methods (not supported by default)
    methods (Access=public)        
        function status = getApplicationStatus(~)
            status = rtw.connectivity.LauncherApplicationStatus.UNKNOWN;
        end
    end
        
    methods (Hidden, Sealed=true, Access=protected)        
        function dispInfo(this, str)
            this.CoreClientInterface.dispInfo(str);
        end
    end            

    methods (Hidden, Access=public)
        function timeOut = getTimeoutForTermination(~)
            % getTimeoutForTermination - get the wait time based on type of Launcher
            assert(false, 'getTimeoutForTermination method should not be invoked on non-host-based launchers');
        end
    end
end
