classdef (Hidden = true) OutOfProcessExecUtils < handle
% Utility class for C Caller out-of-process execution

% Copyright 2018 The MathWorks, Inc.

    methods (Static = true)
        function [exePID, exeOutputFile, exeErrorFile, serverPort] = launchProcess(command, argString)
            % Launch the process
            [exePIDNum, exeOutputFile, exeErrorFile] = rtw.connectivity.Utils.launchProcess(command, argString);
            exePID = int2str(exePIDNum);
            
            % Retrieve the server port information
            nRetry=1;
            % nRetry value for maca64 to be reconsidered when g3082691 is addressed
            if isequal(computer('arch'), 'maca64')
                nRetry = nRetry*50;
            end

            while nRetry > 0
                [portCell, outputFileContents] = coder.connectivity.PILCommunication.parseOutputFileForHostServerPort(exePID, exeOutputFile);
                %check if port is not empty
                if ~isempty(portCell)
                    break;
                end
                % pause then try again
                pause(0.1);
                nRetry = nRetry - 1;
            end

            timeout = 50;
            if isempty(portCell)
                while timeout > 0
                    if ~rtw.connectivity.Utils.isAlive(exePIDNum)
                        exception = MException(message('Simulink:CustomCode:OOPExeLaunchFailure', command));
                        exception.throwAsCaller;
                    end
                    % pause then try again - g3017231
                    pause(0.1);
                    timeout = timeout - 1;
                end
                rtw.connectivity.ProductInfo.error('target', 'UnknownServerPort', ...
                    outputFileContents, [command ' ' argString]);
            end
            serverPort = portCell;
        end

        function isOK = isDebuggingEnabledAndExeAlive(~, exePID)
            % The first input argument is modelHandle, which is reserved
            % for future use.
            narginchk(2, 2);
            isOK = 0;
            if slfeature('OutOfProcessExecution') > 0 && psUtils('isalive', exePID)
                isOK = 1;
                if strcmp(getenv('DebugSILWithMSVCTesting'),'1')
                    [silDebugger, breakpoints] = SLCC.OOP.slccOOPExternalDebuggerInfo.getInstance().getSLCCOOPSILDebugger(char(string(exePID)));
                    if ~isempty(silDebugger) 
                        fileName = 'SILDebugTestLogs.txt';
                        for idx=1:length(breakpoints)
                            if silDebugger.stoppedAtBreakpoint(breakpoints(idx))
                                % log some data into a file in the current dir
                                fid = fopen(fileName, 'a');
                                fwrite(fid, sprintf('Hit Breakpoint\n'));
                                fclose(fid);
                                silDebugger.continueExecution();
                                break;
                            end
                        end
                        if ismac
                            % due to lldb issue, it will stuck in
                            % exc_bad_access forever
                            % we need to stop debugger manually
                           silDebugger.stopApplication(); 
                        end
                    end
                end
            end
        end
    end
    
    methods (Static = true, Access = private)
        function [portCell, outputFileContents] = readServerPortNumber(outputFile)
            nRetry=150;
           
            while nRetry > 0
                outputFileContents = fileread(outputFile);
                portCell = regexp(outputFileContents, ...
                    'Server Port Number: (\d*)', 'tokens', 'once');
                if ~isempty(portCell)
                    % found server port number
                    break;
                end
                % Pause then try again
                pause(0.1);
                nRetry = nRetry - 1;
            end
        end
    end
end
