classdef InstallTpSoftware1 < matlab.hwmgr.internal.hwsetup.ListTpTools
    % InstallTpSoftware1 - Screen implementation to enable users to download
    % and perform silent install of third party tools.

    %   Copyright 2021-2023 The MathWorks, Inc.

    properties(Access = {?matlab.hwmgr.internal.hwsetup.TemplateBase,...
            ?hwsetuptest.util.TemplateBaseTester})
        ActionSelectionRadioGroup
        FootNote
        InstallButton
        InstallAllButton
        StatusTable
        StatusTableTitle
        screenReady = false;
    end

    properties(Access = private)
        SavedSelectedProcessors
        tiC28xCGTFolder = 'tic28xcodegentools.instrset';
        tiARMCGTFolder = 'tiarmcodegentools.instrset';
        BusySpinner
    end

    methods
        function obj = InstallTpSoftware1(varargin)
            % call to the base class constructor
            obj@matlab.hwmgr.internal.hwsetup.ListTpTools(varargin{:});

            obj.HelpText.Enable = 'on';

            % Disable next until 3Ps are detected
            obj.NextButton.Enable = 'off';

            % Set screen title
            obj.Title.Text = message('TIC2000:hwsetup:AutoInstallTpTitle').getString;

            % Radio button configuration
            obj.ActionSelectionRadioGroup =  matlab.hwmgr.internal.hwsetup.RadioGroup.getInstance(obj.ContentPanel);
            obj.ActionSelectionRadioGroup.Position =[20 290 430 90];
            obj.ActionSelectionRadioGroup.Title =  message('TIC2000:hwsetup:AutoInstallRadioTitle').getString;
            obj.ActionSelectionRadioGroup.Items =  {message('TIC2000:hwsetup:AutoInstallRadioOption1').getString,...
                message('TIC2000:hwsetup:AutoInstallRadioOption2').getString};
            obj.ActionSelectionRadioGroup.SelectionChangedFcn = @obj.radioButtonCallback;

            % Foot note to explain radio button settings
            obj.FootNote = matlab.hwmgr.internal.hwsetup.HTMLText.getInstance(obj.ContentPanel);
            obj.FootNote.Position = [20 240 430 70];

            % 3P Table
            obj.ListTpDownloadTable.Position = [20 140 430 90];

            % Install button properties
            obj.InstallButton = matlab.hwmgr.internal.hwsetup.Button.getInstance(obj.ContentPanel);
            obj.InstallButton.Text = message('TIC2000:hwsetup:Install').getString;
            obj.InstallButton.ButtonPushedFcn = @obj.installButtonCallback;
            obj.InstallButton.Position = [270 20 80 22];
            obj.InstallButton.Color = matlab.hwmgr.internal.hwsetup.util.Color.MWBLUE;
            obj.InstallButton.FontColor = matlab.hwmgr.internal.hwsetup.util.Color.WHITE;

            % Install all button properties
            obj.InstallAllButton = matlab.hwmgr.internal.hwsetup.Button.getInstance(obj.ContentPanel);
            obj.InstallAllButton.Text = message('TIC2000:hwsetup:AutoInstallAlternateButton').getString;
            obj.InstallAllButton.ButtonPushedFcn = @obj.reinstallAllButtonCallback;
            obj.InstallAllButton.Position = [370 20 80 22];
            obj.InstallAllButton.Color = matlab.hwmgr.internal.hwsetup.util.Color.MWBLUE;
            obj.InstallAllButton.FontColor = matlab.hwmgr.internal.hwsetup.util.Color.WHITE;

            % Status table to show success or failure for 3P installation
            obj.StatusTable = matlab.hwmgr.internal.hwsetup.StatusTable.getInstance(obj.ContentPanel);
            obj.StatusTableTitle = matlab.hwmgr.internal.hwsetup.Label.getInstance(obj.ContentPanel);
            obj.StatusTable.Position = [20 70 350 80];
            obj.StatusTable.Visible = 'off';
            obj.StatusTableTitle.Visible = 'off';
            obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Busy};
            obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpprocessingStatus').getString};

            % Busy spinner to handle delays
            obj.BusySpinner = matlab.hwmgr.internal.hwsetup.BusyOverlay.getInstance(obj.ContentPanel);
            obj.BusySpinner.Text = message('TIC2000:hwsetup:Configure3P').getString;
            obj.BusySpinner.Visible = 'on';
            % Calling show here will load the ContentPanel and users can
            % see the BusyOverlay
            obj.show();

            % Find the installed 3P tools
            obj.autoFind3PTools();
            % Set screen default settings based on 3P information
            obj.setScreenDefaults();
            % Set 3P table properties
            obj.update3PTable();
            % Do not place any code below this line in this function
            obj.screenReady = true;

            obj.BusySpinner.Visible = 'off';
        end

        function autoDownloadScreenConfigure(obj)
            % Screen configuration for auto 3P install radio button

            % Foot note updates
            obj.FootNote.Text = [message('TIC2000:hwsetup:AutoInstallTpAutoFootNote').getString];

            % Table updates
            obj.ListTpDownloadTable.ColumnName = {message('TIC2000:hwsetup:Name').getString, ...
                message('TIC2000:hwsetup:Version').getString, ...
                message('TIC2000:hwsetup:Details').getString};
            if obj.Workflow.autoInstall3PTool(1).isInstalled
                tiC28xCGTDetails = [message('TIC2000:hwsetup:Installed').getString ' | ' ...
                    '<a href="' obj.Workflow.autoInstall3PTool(1).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
            else
                tiC28xCGTURL = obj.Workflow.autoInstall3PTool(1).licenseUrl;
                tiC28xCGTHyperlinkText = message('TIC2000:hwsetup:License').getString;
                tiC28xCGTDetails = ['<a href="' tiC28xCGTURL '">' tiC28xCGTHyperlinkText '</a>'];
            end
            % About the screen
            obj.HelpText.AboutSelection = message('TIC2000:hwsetup:AutoInstallTpAutoAboutSelection').getString;


            obj.HelpText.WhatToConsider = message('TIC2000:hwsetup:AutoInstallTpAutoCGTDescription').getString;
            % Table updates
            obj.ListTpDownloadTable.Name = {obj.Workflow.autoInstall3PTool(1).displayName};
            obj.ListTpDownloadTable.Version = {message('TIC2000:hwsetup:TICGTVersion').getString};
            obj.ListTpDownloadTable.Details = {tiC28xCGTDetails};

            % If ARM CGT required
            if isequal(obj.Workflow.required3PToolCount, 2)
                % About the screen
                obj.HelpText.WhatToConsider = message('TIC2000:hwsetup:AutoInstallTpAutoCGTDescriptionwithARM').getString;
                % Table updates
                if obj.Workflow.autoInstall3PTool(2).isInstalled
                    tiARMCGTDetails = [message('TIC2000:hwsetup:Installed').getString ' | ' ...
                        '<a href="' obj.Workflow.autoInstall3PTool(2).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
                else
                    tiARMCGTURL = obj.Workflow.autoInstall3PTool(2).licenseUrl;
                    tiARMCGTHyperlinkText = message('TIC2000:hwsetup:License').getString;
                    tiARMCGTDetails = ['<a href="' tiARMCGTURL '">' tiARMCGTHyperlinkText '</a>'];
                end
                if (~any(strcmp(obj.ListTpDownloadTable.Name, obj.Workflow.autoInstall3PTool(2).displayName)))
                    obj.ListTpDownloadTable.Name{end+1} = obj.Workflow.autoInstall3PTool(2).displayName;
                    obj.ListTpDownloadTable.Version{end+1} = message('TIC2000:hwsetup:ARMCGTVersion').getString;
                    obj.ListTpDownloadTable.Details{end+1} = tiARMCGTDetails;
                else
                    obj.ListTpDownloadTable.Details{end} = tiARMCGTDetails;
                end
            end

            % About the screen - success message with path
            if (obj.Workflow.installed3PToolCount > 0) &&...
                    ~contains(obj.HelpText.WhatToConsider, message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString)
                obj.HelpText.WhatToConsider = [obj.HelpText.WhatToConsider ...
                    '<br>' '<br>' message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString];
            end
        end

        function manualDownloadScreenConfigure(obj)
            % Screen configuration for manual 3P install radio button

            % Foot note update
            obj.FootNote.Text = message('TIC2000:hwsetup:AutoInstallTpManualFootNote').getString;

            % Table updates
            obj.ListTpDownloadTable.ColumnName = {message('TIC2000:hwsetup:Name').getString, ...
                message('TIC2000:hwsetup:Version').getString, ...
                message('TIC2000:hwsetup:Details').getString};
            if obj.Workflow.autoInstall3PTool(1).isInstalled
                tiC28xCGTDetails = [message('TIC2000:hwsetup:Installed').getString ' | ' ...
                    '<a href="' obj.Workflow.autoInstall3PTool(1).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
            else
                tiC28xCGTURL = obj.Workflow.autoInstall3PTool(1).downloadUrl;
                tiC28xCGTHyperlinkText = message('TIC2000:hwsetup:Download').getString;
                tiC28xCGTDetails = ['<a href="' tiC28xCGTURL '">' tiC28xCGTHyperlinkText '</a>' ' | ' ...
                    '<a href="' obj.Workflow.autoInstall3PTool(1).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
            end

            % About the screen
            obj.HelpText.AboutSelection = message('TIC2000:hwsetup:AutoInstallTpManualAboutSelection').getString;

            % About the screen
            obj.HelpText.WhatToConsider = message('TIC2000:hwsetup:AutoInstallTpManualCGTDescription').getString;

            % Table updates
            obj.ListTpDownloadTable.Name = {obj.Workflow.autoInstall3PTool(1).displayName};
            obj.ListTpDownloadTable.Version = {message('TIC2000:hwsetup:TICGTVersion').getString};
            obj.ListTpDownloadTable.Details = {tiC28xCGTDetails};

            if isequal(obj.Workflow.required3PToolCount, 2)
                % About the screen
                obj.HelpText.WhatToConsider = message('TIC2000:hwsetup:AutoInstallTpManualCGTDescriptionWithARM').getString;

                % Table updates
                if obj.Workflow.autoInstall3PTool(2).isInstalled
                    tiARMCGTDetails = [message('TIC2000:hwsetup:Installed').getString ' | ' ...
                        '<a href="' obj.Workflow.autoInstall3PTool(2).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
                else
                    tiARMCGTURL = obj.Workflow.autoInstall3PTool(2).downloadUrl;
                    tiARMCGTHyperlinkText = message('TIC2000:hwsetup:Download').getString;
                    tiARMCGTDetails = ['<a href="' tiARMCGTURL '">' tiARMCGTHyperlinkText '</a>' ' | ' ...
                        '<a href="' obj.Workflow.autoInstall3PTool(2).licenseUrl '">' message('TIC2000:hwsetup:License').getString '</a>'];
                end
                if (~any(strcmp(obj.ListTpDownloadTable.Name, obj.Workflow.autoInstall3PTool(2).displayName)))
                    obj.ListTpDownloadTable.Name{end+1} = obj.Workflow.autoInstall3PTool(2).displayName;
                    obj.ListTpDownloadTable.Version{end+1} = message('TIC2000:hwsetup:ARMCGTVersion').getString;
                    obj.ListTpDownloadTable.Details{end+1} = tiARMCGTDetails;
                else
                    obj.ListTpDownloadTable.Details{end} = tiARMCGTDetails;
                end
            end

            % About the screen - success message with path
            if (obj.Workflow.installed3PToolCount > 0) && ...
                    ~contains(obj.HelpText.WhatToConsider, message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString)
                obj.HelpText.WhatToConsider = [obj.HelpText.WhatToConsider ...
                    '<br>' '<br>' message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString];
            end
        end

        function radioButtonCallback(obj, src, ~)
            % Auto or manual radio button callback
            if src.ValueIndex == 2
                obj.manualDownloadScreenConfigure();
            else
                obj.autoDownloadScreenConfigure();
            end
            % Install/Reinstall all button
            obj.installButtonVisibility();
            % next enable or disable
            obj.nextButtonSetting();
        end

        function installButtonCallback(obj, ~, ~)
            % Install button callback

            % Set status table poisition and entries
            obj.StatusTable.Position = [20 70 350 80];
            obj.StatusTable.Visible = 'on';
            obj.StatusTableTitle.Visible = 'off';
            obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Busy};
            obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpprocessingStatus').getString};

            % Disable all screen properties
            obj.disableScreenProperties();
            restoreOnCleanup = onCleanup(@obj.restoreScreen);

            if (obj.isInternetAccessAvailable())
                % Download and install 3P tools
                exceptionMessage = '';
                try
                    obj.downloadAndInstall3PTools(false);
                catch ME
                    exceptionMessage = ME.message;
                end
                % Update 3P table, install button visibility and status message
                obj.update3PTable();
                obj.installButtonVisibility();
                obj.setInstallStatusMessage(exceptionMessage);
                obj.nextButtonSetting();
            else
                obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Fail};
                obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpInternetFailure').getString};
            end
        end

        function reinstallAllButtonCallback(obj, ~, ~)
            % Reinstall all button callback

            % Set status table poisition and entries
            obj.StatusTable.Position = [20 70 350 80];
            obj.StatusTable.Visible = 'on';
            obj.StatusTableTitle.Visible = 'off';
            obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Busy};
            obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpprocessingStatus').getString};

            % Disable all screen properties
            obj.disableScreenProperties();
            restoreOnCleanup = onCleanup(@obj.restoreScreen);

            if (obj.isInternetAccessAvailable())
                % Download and reinstall all the 3P tools
                exceptionMessage = '';
                try
                    obj.downloadAndInstall3PTools(true);
                catch ME
                    exceptionMessage = ME.message;
                end

                % Update 3P table, install button visibility and status message
                obj.update3PTable();
                obj.installButtonVisibility();
                obj.setInstallStatusMessage(exceptionMessage);
                obj.nextButtonSetting();
            else
                obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Fail};
                obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpInternetFailure').getString};
            end
        end

        function out = isInternetAccessAvailable(~)
            % Returns true if internet access is available
            if ispc
                pingCmd = 'ping  www.mathworks.com -n 4';
            else
                pingCmd = 'ping  www.mathworks.com -c 3';
            end
            [out, ~] = system(pingCmd);
            out = ~logical(out);
        end

        function downloadAndInstall3PTools(obj, reinstallAll)
            % Function to download, install and validate 3P tools

            % Checksum validation commands
            if ispc
                checksumCommandPrefix = 'CertUtil -hashfile ';
                checksumCommandPostfix = ' MD5';
            else
                checksumCommandPrefix = 'md5sum ';
                checksumCommandPostfix = '';
            end

            % Create 3P install and download folders
            if ~isfolder(obj.Workflow.tpInstallPath)
                mkdir(obj.Workflow.tpInstallPath);
            end
            tpDownloadPath = fullfile(obj.Workflow.tpInstallPath, 'Downloads');
            if ~isfolder(tpDownloadPath)
                mkdir(obj.Workflow.tpInstallPath, 'Downloads');
            end

            if reinstallAll
                % Reset the installed 3P tool count
                obj.Workflow.installed3PToolCount = 0;
            end

            % Timeout option for download
            options = weboptions('Timeout',10);

            loopStart = 1;
            loopEnd = obj.Workflow.required3PToolCount;
            for tpCount = loopStart : loopEnd

                % Download and validate checksum
                if ~obj.Workflow.autoInstall3PTool(tpCount).isDownloaded || reinstallAll

                    % Create download directory for each 3P if does not
                    % exists
                    if ~isfolder(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder)
                        [parent, folderNamePart1, folderNamePart2] = ...
                            fileparts(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder);
                        folderName = folderNamePart1;
                        if ~isempty(folderNamePart2)
                            % If folder name has '.' append concatenate
                            % then together
                            folderName = [folderName folderNamePart2]; %#ok<AGROW>
                        end
                        mkdir(parent, folderName);
                    end

                    % Download the 3P to the required folder
                    returnFileName = websave(fullfile(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder, ...
                        obj.Workflow.autoInstall3PTool(tpCount).archive), ...
                        obj.Workflow.autoInstall3PTool(tpCount).downloadUrl, options);

                    % Validate the downloaded 3P checksum
                    if isequal(returnFileName, fullfile(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder, ...
                            obj.Workflow.autoInstall3PTool(tpCount).archive))
                        checsumCommand = [checksumCommandPrefix '"'...
                            fullfile(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder, ...
                            obj.Workflow.autoInstall3PTool(tpCount).archive) '"' checksumCommandPostfix];
                        [~, msg] = system(checsumCommand);
                        obj.Workflow.autoInstall3PTool(tpCount).isDownloaded = contains(msg, ...
                            obj.Workflow.autoInstall3PTool(tpCount).checksum);
                    else
                        % Download failed. Clean the download directory
                        % with its contents silently
                        if isfolder(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder)
                            try
                                rmdir(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder, 's')
                            catch
                                % No errors need to be thrown
                            end
                        end
                    end
                end

                % Extract / install for following scenarios:
                % 1) Downloaded and not installed
                % 2) Downloaded and registerd folder is not same as the
                % default install folder
                % 3) Downloaded and reinstall all
                if obj.Workflow.autoInstall3PTool(tpCount).isDownloaded && ...
                        (~obj.Workflow.autoInstall3PTool(tpCount).isInstalled || ...
                        ~isequal(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder, ...
                        fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, ...
                        obj.Workflow.autoInstall3PTool(tpCount).installFolder)) || ...
                        reinstallAll)

                    % Create install directory for each 3P if does not
                    % exists
                    if ~isfolder(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder)
                        [parent, folderNamePart1, folderNamePart2] = ...
                            fileparts(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder);
                        folderName = folderNamePart1;
                        if ~isempty(folderNamePart2)
                            % If folder name has '.' append concatenate
                            % then together
                            folderName = [folderName folderNamePart2]; %#ok<AGROW>
                        end
                        mkdir(parent, folderName);
                    end

                    % If archive, then extract the 3P
                    if obj.Workflow.autoInstall3PTool(tpCount).isArchive
                        extractedFolder = ...
                            unzip(fullfile(obj.Workflow.autoInstall3PTool(tpCount).downloadFolder, ...
                            obj.Workflow.autoInstall3PTool(tpCount).archive), ...
                            obj.Workflow.autoInstall3PTool(tpCount).installParentFolder); %#ok<NASGU>
                        obj.Workflow.autoInstall3PTool(tpCount).isInstalled =  true;
                        % If installer, then run the executable
                    elseif obj.Workflow.autoInstall3PTool(tpCount).isInstaller
                        if ispc
                            [returnValue, ~]=system(obj.Workflow.autoInstall3PTool(tpCount).installCommand);
                        else
                            command = ['chmod a+x ' obj.Workflow.autoInstall3PTool(tpCount).installCommand];
                            system(command);
                            presentDirectory = pwd;
                            cd (obj.Workflow.autoInstall3PTool(tpCount).installParentFolder);
                            installCommand = [obj.Workflow.autoInstall3PTool(tpCount).installCommand...
                                ' --mode "unattended" --installdir ' obj.Workflow.autoInstall3PTool(tpCount).installParentFolder];
                            [returnValue, ~]=system(installCommand);
                            cd (presentDirectory);
                        end
                        obj.Workflow.autoInstall3PTool(tpCount).isInstalled = ...
                            isequal(returnValue, obj.Workflow.autoInstall3PTool(tpCount).returnCode);
                    end

                    % Validate the installed 3P
                    if obj.Workflow.autoInstall3PTool(tpCount).isInstalled
                        % First check the installed directory which is one
                        % level below
                        folderlist = dir(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder);
                        for count = 1 : length(folderlist)
                            if contains(folderlist(count).name, ...
                                    obj.Workflow.autoInstall3PTool(tpCount).installFolder) && ...
                                    isfolder(fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, ...
                                    folderlist(count).name))
                                installDir = fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, ...
                                    folderlist(count).name);
                            end
                        end
                        % Call the validation function
                        is3PValid = obj.Workflow.autoInstall3PTool(tpCount).validationFunction(installDir);
                        if (is3PValid == 1)
                            % No validation screens required as it is
                            % automatically installed and validated
                            obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = false;
                            obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder = installDir;
                            % Update the installed 3P count
                            obj.Workflow.installed3PToolCount = obj.Workflow.installed3PToolCount + 1;
                        else
                            % Action if the installed 3P validation failed
                            % TBD - Clean the install directory
                            obj.Workflow.autoInstall3PTool(tpCount).isInstalled = false;
                        end
                    else
                        % Install failed for the 3P, maintain the status quo
                        % for the flags
                        % TBD - Clean the install directory
                    end
                end
            end
        end

        function out = getPreviousScreenID(~)
            out = 'codertarget.tic2000.hwsetup.SelectProcessors';
        end

        function out = getNextScreenID(obj)
            if ~isobject(obj) || isempty(obj.screenReady) || ~(obj.screenReady)
                % Placeholder if user clicks next quickly before the screen is
                % populated with options stay in the same screen
                out = [];
            else
                loopStart = 1;
                loopEnd = obj.Workflow.required3PToolCount;
                if isequal(obj.ActionSelectionRadioGroup.Value, message('TIC2000:hwsetup:AutoInstallRadioOption2').getString)
                    % Provide screens for user if they want to use a different
                    % version than the installed one
                    for tpCount = loopStart : loopEnd
                        obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = true;
                    end
                else
                    for tpCount = loopStart : loopEnd
                        if obj.Workflow.autoInstall3PTool(tpCount).isInstalled && ...
                                (isequal(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder, ...
                                fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, ...
                                obj.Workflow.autoInstall3PTool(tpCount).installFolder)) || ...
                                isempty(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder))
                            % If the registered folder is same as default path,
                            % then the validation is also done, the validation
                            % required must have been changed due to manual
                            % selection option
                            obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = false;
                        end
                    end
                end
                out = 'codertarget.tic2000.hwsetup.InstallTpSoftware2';
                % Disable next button to prevent multiple press
                obj.NextButton.Enable = 'off';
            end
        end

        function autoFind3PTools(obj)
            % Detect the already installed 3P at the pre-defined 3P folder.
            % Check and initialize the structure for all the 3Ps
            % irrespective of the processor selection

            % Folder where the 3Ps will be downloaded and installed
            % Windows: C:/ProgramData/MATLAB/tic2000/3P.
            % Linux : HOME\Documents\MATLAB\tic2000\3P
            targetFolder = codertarget.target.getTargetFolder('TI C2000');
            thirdPartyRegistryFolder = codertarget.target.getThirdPartyToolsRegistryFolder(targetFolder);
            installFolder = extractBefore(thirdPartyRegistryFolder,'toolbox');
            if ~(endsWith(installFolder,'MATLAB\') || endsWith(installFolder,'matlab\') ||...
                    endsWith(installFolder,'MATLAB/') || endsWith(installFolder,'matlab/'))
                % Remove version if installFolder has version in it for
                % windows and linux
				% installFolder = 'C:\ProgramData\MATLAB\R2023bPrerelease\';
			    % fileparts(installFolder)  ->  'C:\ProgramData\MATLAB\R2023bPrerelease'
			    % fileparts(fileparts(installFolder)) -> 'C:\ProgramData\MATLAB'
                installFolder = fileparts(fileparts(installFolder));
            else
                % Do nothing
                % For sandbox workflows and installed MATLAB when release version is not 
                % associated with installFolder
            end
            spkgFolder  = fullfile(installFolder,'tic2000');
            prefSettings = getpref('MathWorksTIC2000Preferences');
            % Use preference to override the default path selection for 3P
            % installation
            if isfield(prefSettings, 'overridePathFor3PInstall') && ~isempty(prefSettings.('overridePathFor3PInstall'))
                obj.Workflow.tpInstallPath = fullfile(prefSettings.('overridePathFor3PInstall'), '3P.instrset');
            else
                obj.Workflow.tpInstallPath = fullfile(spkgFolder, '3P.instrset');
            end

            % Read the 3P xml file to get the 3P details required for
            % download and install
            obj.Workflow.autoInstall3PTool = obj.getAutoInstall3PToolInfo(obj.Workflow.tpInstallPath);
            % Get previously 3P installation details installed using HW
            % setup screen by this or any other support package
            obj.getInstalled3PDetails();
            % Get previously registerd 3P details by this support package
            obj.getRegistered3PDetails();
        end

        function getInstalled3PDetails(obj)
            % Search if 3p already installed in the default path and update
            % the details. isInstalled, validation ScreenRequired and
            % registeredinstallFolder will be updated

            % Initialize to 0 before starting to check the installed tools
            obj.Workflow.installed3PToolCount = 0;
            for tpCount = 1 : 2
                % Check all the 3P installed previously irrespective of
                % processor selection.

                % Check if 3P install directory for
                % each 3P exists
                if isfolder(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder)
                    % Get the 3P folder which is one level below
                    installDir = fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, obj.Workflow.autoInstall3PTool(tpCount).installFolder);
                    if ~isfolder(installDir)
                        installDir = '';
                    end

                    % Validate the installed 3P
                    is3PValid = obj.Workflow.autoInstall3PTool(tpCount).validationFunction(installDir);
                    if is3PValid == 1
                        % No validation screens required as it is
                        % automatically installed and validated
                        obj.Workflow.autoInstall3PTool(tpCount).isInstalled = true;
                        obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = false;
                        obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder = installDir;
                        obj.Workflow.installed3PToolCount = obj.Workflow.installed3PToolCount + 1;
                    else
                        % No action if the installed 3P failed
                        % validation
                    end
                else
                    % 3P not installed, need to install them, the default
                    % holds good
                end
            end
        end

        function getRegistered3PDetails(obj)
            % Function to check if 3Ps were configured in previous setup
            % screen run. isInstalled, validationScreenRequired and
            % registeredInstallFolder will be updated based on the previous
            % registered paths selected by user

            prefSettings = getpref('MathWorksTIC2000Preferences');
            for tpCount = 1 : 2
                % Check all the 3P preferences registered previously
                % irrespective of processor selection
                tpPreferenceName = strrep(obj.Workflow.autoInstall3PTool(tpCount).displayName, ' ', '_');
                if isfield(prefSettings, tpPreferenceName) && isfolder(prefSettings.(tpPreferenceName))
                    if ~isequal(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder, prefSettings.(tpPreferenceName))
                        % If the installed folder path is not same as the
                        % path in saved preference then user may have 3P
                        % installed in a different path. Update registered
                        % path accordingly
                        [is3PValid, version] = obj.Workflow.autoInstall3PTool(tpCount).validationFunction(prefSettings.(tpPreferenceName));
                        if (is3PValid == 1) && isequal(version, obj.Workflow.autoInstall3PTool(tpCount).version)
                            % If it is a valid and recommended 3P then show
                            % as installed but provide validation screen
                            if ~obj.Workflow.autoInstall3PTool(tpCount).isInstalled
                                obj.Workflow.autoInstall3PTool(tpCount).isInstalled = true;
                                obj.Workflow.installed3PToolCount = obj.Workflow.installed3PToolCount + 1;
                            end
                            obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder = prefSettings.(tpPreferenceName);
                            obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = true;
                        elseif (is3PValid == -2)
                            % User registered a different version than the
                            % installed version, Populate that path if
                            % manual option is selected
                            if ~obj.Workflow.autoInstall3PTool(tpCount).isInstalled
                                % Update the registered path only if
                                % 3P is not installed, otherwise default
                                % installed path should be preferred over
                                % the user selected choice
                                obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder = prefSettings.(tpPreferenceName);
                                obj.Workflow.autoInstall3PTool(tpCount).validationScreenRequired = true;
                            end
                        else
                            % If it is not a valid 3P path the default
                            % structure value holds good
                        end
                    else
                        % The value set in the function
                        % getInstalled3PDetails holds good for isInstalled,
                        % validationScreenRequired and registeredInstallFolder
                    end
                end
            end
        end

        function autoInstall3PTool = getAutoInstall3PToolInfo(obj, tpInstallPath)
            % Get the information for 3p tools from 3P xml
            spkgRootFolder = codertarget.tic2000.hwsetup.getTIC2000Root;
            targetFolder = fullfile(spkgRootFolder, 'registry', 'thirdpartytools', 'instrset');
            if ispc
                tiC28xCGTFile = fullfile(targetFolder, obj.tiC28xCGTFolder, 'win64.xml');
                tiARMCGTFile = fullfile(targetFolder, obj.tiARMCGTFolder, 'win64.xml');
            elseif ismac
                tiC28xCGTFile = ''; %fullfile(targetFolder, tiC28xCGTFolder, 'mac.xml');
                tiARMCGTFile = ''; %fullfile(targetFolder, tiARMCGTFolder, 'mac.xml');
            else
                tiC28xCGTFile = fullfile(targetFolder, obj.tiC28xCGTFolder, 'linux.xml');
                tiARMCGTFile =  fullfile(targetFolder, obj.tiARMCGTFolder, 'linux.xml');
            end

            % Directory where the 3Ps will be downloaded
            tpDownloadPath = fullfile(tpInstallPath, 'Downloads');

            % Extract TI C28x CGT information
            autoInstall3PTool = obj.createAutoInstall3PStruct();
            autoInstall3PTool.downloadFolder = fullfile(tpDownloadPath, obj.tiC28xCGTFolder);
            autoInstall3PTool.installParentFolder = fullfile(tpInstallPath, obj.tiC28xCGTFolder);
            autoInstall3PTool.installFolder = ['ti-cgt-c2000_', message('TIC2000:hwsetup:TICGTVersion').getString, '.LTS'];
            autoInstall3PTool.validationFunction = @(varargin)obj.Workflow.HardwareInterface.validateTIC28xCGT(varargin{:});
            autoInstall3PTool.version = message('TIC2000:hwsetup:TICGTVersion').getString;

            % Extract the third party tool information
            import matlab.io.xml.dom.*
            thirdPartyTree = parseFile(Parser, tiC28xCGTFile);
            thirdPartyNode = thirdPartyTree.getElementsByTagName('instructions');
            if ~isempty(thirdPartyNode.TextContent)
                thirdPartyNode = thirdPartyTree.getElementsByTagName('downloadInstruction');
                if ~isempty(thirdPartyNode.TextContent)
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('downloadUrl');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.downloadUrl = thirdPartyNode.TextContent;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archive');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.archive = thirdPartyNode.TextContent;
                    end
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('installInstructions');
                if ~isempty(thirdPartyNode.TextContent)
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archiveType');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.archiveType = thirdPartyNode.TextContent;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archiveName');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.archiveName = thirdPartyNode.TextContent;
                        autoInstall3PTool.isArchive = true;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('command');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.isInstaller = true;
                        if ispc
                            autoInstall3PTool.installCommand = ...
                                ['"' fullfile(autoInstall3PTool.downloadFolder, autoInstall3PTool.archive) '"' ...
                                ' --prefix ' '"' autoInstall3PTool.installParentFolder '"' ' --mode' ' unattended'];
                        else
                            autoInstall3PTool.installCommand = fullfile(autoInstall3PTool.downloadFolder, autoInstall3PTool.archive);
                        end
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('passingReturnCodes');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool.returnCode = str2double(thirdPartyNode.TextContent);
                    end
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('displayName');
                if ~isempty(thirdPartyNode.TextContent)
                    autoInstall3PTool.displayName = thirdPartyNode.TextContent;
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('licenseUrl');
                if ~isempty(thirdPartyNode.TextContent)
                    autoInstall3PTool.licenseUrl = thirdPartyNode.TextContent;
                    autoInstall3PTool.licenseUrl = fullfile(strrep(autoInstall3PTool.licenseUrl, '$(MATLAB_ROOT)', matlabroot));
                    autoInstall3PTool.licenseUrl = char(strcat("matlab:open('", (autoInstall3PTool.licenseUrl),"')"));
                end
            end

            % Extract TI ARM CGT information
            autoInstall3PTool(2) = obj.createAutoInstall3PStruct();
            autoInstall3PTool(2).downloadFolder = fullfile(tpDownloadPath, obj.tiARMCGTFolder);
            autoInstall3PTool(2).installParentFolder = fullfile(tpInstallPath, obj.tiARMCGTFolder);
            autoInstall3PTool(2).installFolder = ['ti-cgt-arm_', message('TIC2000:hwsetup:ARMCGTVersion').getString, '.LTS'];
            autoInstall3PTool(2).validationFunction = @(varargin)obj.Workflow.HardwareInterface.validateTIARMCGT(varargin{:});
            autoInstall3PTool(2).version = message('TIC2000:hwsetup:ARMCGTVersion').getString;
            thirdPartyTree = parseFile(Parser,tiARMCGTFile);
            thirdPartyNode = thirdPartyTree.getElementsByTagName('instructions');
            if ~isempty(thirdPartyNode.TextContent)
                thirdPartyNode = thirdPartyTree.getElementsByTagName('downloadInstruction');
                if ~isempty(thirdPartyNode.TextContent)
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('downloadUrl');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).downloadUrl = thirdPartyNode.TextContent;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archive');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).archive = thirdPartyNode.TextContent;
                    end
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('installInstructions');
                if ~isempty(thirdPartyNode.TextContent)
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archiveType');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).archiveType = thirdPartyNode.TextContent;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('archiveName');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).archiveName = thirdPartyNode.TextContent;
                        autoInstall3PTool(2).isArchive = true;
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('command');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).isInstaller = true;
                        if ispc
                            autoInstall3PTool(2).installCommand = ...
                                ['"' fullfile(autoInstall3PTool(2).downloadFolder, autoInstall3PTool(2).archive) '"'...
                                ' --prefix ' '"' autoInstall3PTool(2).installParentFolder '"' ' --mode' ' unattended'];
                        else
                            autoInstall3PTool(2).installCommand = fullfile(autoInstall3PTool(2).downloadFolder, autoInstall3PTool(2).archive);
                        end
                    end
                    thirdPartyNode = thirdPartyTree.getElementsByTagName('passingReturnCodes');
                    if ~isempty(thirdPartyNode.TextContent)
                        autoInstall3PTool(2).returnCode = str2double(thirdPartyNode.TextContent);
                    end
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('displayName');
                if ~isempty(thirdPartyNode.TextContent)
                    autoInstall3PTool(2).displayName = thirdPartyNode.TextContent;
                end
                thirdPartyNode = thirdPartyTree.getElementsByTagName('licenseUrl');
                if ~isempty(thirdPartyNode.TextContent)
                    autoInstall3PTool(2).licenseUrl = thirdPartyNode.TextContent;
                    autoInstall3PTool(2).licenseUrl = fullfile(strrep(autoInstall3PTool(2).licenseUrl, '$(MATLAB_ROOT)', matlabroot));
                    autoInstall3PTool(2).licenseUrl = char(strcat("matlab:open('", (autoInstall3PTool(2).licenseUrl),"')"));
                end
            end
        end

        function outStruct = createAutoInstall3PStruct(~)
            % Structure to store 3P data
            outStruct = struct('downloadUrl', '', 'downloadFolder', '', 'archive', '', 'archiveType', '', ...
                'archiveName', '', 'isArchive', false, 'installCommand', '', 'returnCode', '', 'message', '', ...
                'isInstaller', false, 'installParentFolder', '', 'installFolder', '', 'registeredInstallFolder', '', 'displayName', '', 'licenseUrl', '', ...
                'checksum', '', 'isInstalled', false, 'isDownloaded', false, 'validationScreenRequired', true, 'validationFunction', '', 'version', '');
        end

        function setScreenDefaults(obj)
            % Function to evaluate and select screen defaults

            isInstalled = true;
            isPathSame = true;
            isFirstTime = true;
            isRegPathValid = true;
            loopStart = 1;
            loopEnd = obj.Workflow.required3PToolCount;
            for tpCount = loopStart : loopEnd
                isInstalled = isInstalled && obj.Workflow.autoInstall3PTool(tpCount).isInstalled;
                isPathSame = isPathSame && ...
                    isequal(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder, ...
                    fullfile(obj.Workflow.autoInstall3PTool(tpCount).installParentFolder, ...
                    obj.Workflow.autoInstall3PTool(tpCount).installFolder));
                isRegPathValid = isRegPathValid && isfolder(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder);
                isFirstTime = isFirstTime && ...
                    isempty(obj.Workflow.autoInstall3PTool(tpCount).registeredInstallFolder);
            end
            % Set radio button default
            if isFirstTime
                obj.ActionSelectionRadioGroup.ValueIndex = 1;
            else
                if isInstalled
                    if isPathSame
                        obj.ActionSelectionRadioGroup.ValueIndex = 1;
                    elseif isRegPathValid
                        % if any registered path is not same as install
                        % path then user may have selected manual option.
                        obj.ActionSelectionRadioGroup.ValueIndex = 2;
                    else
                        % Not a valid registration folder, give auto
                        % install as default.
                        obj.ActionSelectionRadioGroup.ValueIndex = 1;
                    end
                else
                    obj.ActionSelectionRadioGroup.ValueIndex = 1;
                end
            end

            % 3P table and help content update based on radio button
            if isequal(obj.ActionSelectionRadioGroup.Value, message('TIC2000:hwsetup:AutoInstallRadioOption2').getString)
                obj.manualDownloadScreenConfigure();
            else
                obj.autoDownloadScreenConfigure();
            end
            % Set install and reinstall button visibility
            obj.installButtonVisibility();
            % If all 3P installed by setup screen provide default path
            if isInstalled && isPathSame
                if ~contains(obj.HelpText.WhatToConsider, message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString)
                    obj.HelpText.WhatToConsider = [obj.HelpText.WhatToConsider ...
                        '<br>' '<br>' message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString];
                end
            end

            % Enable or disable next button based on 3P install status and
            % radio button selection
            obj.nextButtonSetting();
        end

        function update3PTable(obj)
            % Function to update the 3P table with proper values
            if isequal(obj.ActionSelectionRadioGroup.Value, message('TIC2000:hwsetup:AutoInstallRadioOption2').getString)
                obj.manualDownloadScreenConfigure();
            else
                obj.autoDownloadScreenConfigure();
            end
            obj.installButtonVisibility();
        end

        function setInstallStatusMessage(obj, setInstallStatusMessage)
            % Set the status table based on success or failure of 3P
            % installation
            if isempty(setInstallStatusMessage)
                failCount = 0;
                if isequal(obj.Workflow.installed3PToolCount, obj.Workflow.required3PToolCount)
                    % Provide status message for successful installation
                    obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Pass};
                    obj.StatusTable.Steps = {message('TIC2000:hwsetup:AutoInstallTpSuccessStatus').getString};
                else
                    % Provide status message for installation failure
                    obj.StatusTable.Position = [20 50 350 80];
                    obj.StatusTableTitle.Position = [20 130 380 20];
                    obj.StatusTableTitle.Text = message('TIC2000:hwsetup:AutoInstallTpFailureStatus').getString;
                    obj.StatusTableTitle.Visible = 'on';

                    loopStart = 1;
                    loopEnd = obj.Workflow.required3PToolCount;
                    for tpCount = loopStart : loopEnd
                        if ~obj.Workflow.autoInstall3PTool(tpCount).isDownloaded || ...
                                ~obj.Workflow.autoInstall3PTool(tpCount).isInstalled
                            failCount = failCount + 1;
                            obj.StatusTable.Status(failCount) = {matlab.hwmgr.internal.hwsetup.StatusIcon.Fail};
                            obj.StatusTable.Steps(failCount) = ...
                                {obj.Workflow.autoInstall3PTool(tpCount).displayName};
                        end
                    end
                end
                % Update what to consider with install path
                if (obj.Workflow.installed3PToolCount > 0) && ...
                        ~contains(obj.HelpText.WhatToConsider, message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString)
                    obj.HelpText.WhatToConsider = [obj.HelpText.WhatToConsider ...
                        '<br>' '<br>' message('TIC2000:hwsetup:AutoInstallTpSucccessDescription',obj.Workflow.tpInstallPath).getString];
                end
            else
                obj.StatusTable.Status = {matlab.hwmgr.internal.hwsetup.StatusIcon.Fail};
                obj.StatusTable.Steps = {[message('TIC2000:hwsetup:AutoInstallExceptionStatus').getString ' ' setInstallStatusMessage]};
            end
        end

        function installButtonVisibility(obj)
            % Install and Reinstall All button visibility
            if isequal(obj.ActionSelectionRadioGroup.Value, message('TIC2000:hwsetup:AutoInstallRadioOption1').getString)
                if (obj.Workflow.installed3PToolCount == 0)
                    % No 3P installed show install button
                    obj.InstallButton.Position = [370 20 80 22];
                    obj.InstallButton.Visible = 'on';
                    obj.InstallAllButton.Visible = 'off';
                elseif (obj.Workflow.installed3PToolCount > 0) && (obj.Workflow.installed3PToolCount < obj.Workflow.required3PToolCount)
                    % Some 3P installed show install and reinstall all
                    % button
                    obj.InstallButton.Position = [270 20 80 22];
                    obj.InstallButton.Visible = 'on';
                    obj.InstallAllButton.Visible = 'on';
                else
                    % All 3P installed show only reinstall all button
                    obj.InstallButton.Visible = 'off';
                    obj.InstallAllButton.Visible = 'on';
                end
            else
                % Manual download and install
                obj.InstallButton.Visible = 'off';
                obj.InstallAllButton.Visible = 'off';
            end
        end

        function nextButtonSetting(obj)
            % Install and Reinstall All button visibility
            if isequal(obj.ActionSelectionRadioGroup.Value, message('TIC2000:hwsetup:AutoInstallRadioOption1').getString)
                if (obj.Workflow.installed3PToolCount >= obj.Workflow.required3PToolCount)
                    obj.NextButton.Enable = 'on'; % Enable Next
                else
                    % Partial or no 3P installed
                    obj.NextButton.Enable = 'off'; % Disable Next
                end
            else
                % Manual download and install
                obj.NextButton.Enable = 'on'; % Enable Next
            end
        end

        function reinit(obj)
            obj.BusySpinner.Visible = 'on';
            % Set 3P table properties
            obj.update3PTable();
            % Turn off the status table
            obj.StatusTable.Visible = 'off';
            obj.StatusTableTitle.Visible = 'off';
            obj.BusySpinner.Visible = 'off';
            % next enable or disable
            obj.nextButtonSetting();
        end

        function disableScreenProperties(obj)
            % Disable all screen options before installation
            obj.ActionSelectionRadioGroup.Enable = 'off';
            obj.InstallButton.Enable = 'off';
            obj.InstallAllButton.Enable = 'off';
            obj.FootNote.Enable = 'off';
            obj.disableScreen({'StatusTable', 'CancelButton'});
        end

        function restoreScreen(obj)
            % Restore the screen options after installation is done
            obj.enableScreen();
            obj.ActionSelectionRadioGroup.Enable = 'on';
            obj.FootNote.Enable = 'on';
            obj.InstallButton.Enable = 'on';
            obj.InstallAllButton.Enable = 'on';
            obj.nextButtonSetting();
        end
    end
end