classdef (Sealed) ManifestBuilder < handle
% ManifestBuilder creates ApplicationInstallerManifest.xml in bundle.zip

% Copyright 2021 MathWorks, Inc.

    properties (Constant)
        ROOT = 'ApplicationInstallerManifest';
        APPLICATION_NAME_ELEMENT_NAME = 'ApplicationName';
        DEFAULT_INSTALLATION_DIRECTORY_ELEMENT_NAME = 'DefaultInstallationDirectory';
        EXECUTABLE_NAME_ELEMENT_NAME = 'ExecutableName';
        GUID_ELEMENT_NAME = 'GUID';
        APP_ICON_ELEMENT_NAME = 'ApplicationIcon';
        LOGO_ELEMENT_NAME = 'Logo';
        VERSION_ELEMENT_NAME = 'Version';
        INSTALLATION_NOTES_ELEMENT_NAME = 'InstallationNotes';
        AUTHOR_ORGANIZATION_ELEMENT_NAME = 'AuthorOrganization';
        SUMMARY_ELEMENT_NAME = 'Summary';
        WELCOME_PANEL_TEXT_ELEMENT_NAME = 'WelcomePanelText';
        PROGRAM_ICON_ELEMENT_NAME = 'AddRemoveProgramIcon';
        MCR_PRODUCTS= 'MCRProducts';
        MCR_PRODUCT= 'MCRProduct';
        MCR_PRODUCT_IDENTIFIER= 'ExternalProductIdentifier';
    end
    
    properties (Access = private)
        installationNotes = '';
        authorOrganization = '';
        applicationSummary = '';
        welcomePanelText = '';
        addRemoveProgramIcon = '';
        userApplicationName
        modifiedExecutablePath
        guid
        defaultInstallDirectory
        applicationIcon
        applicationLogo
        version
        mcrExternalProductIdentifiers = [];
    end
    
    methods (Access = public)
        function obj = ManifestBuilder(parameters)    
            obj.userApplicationName = parameters.userApplicationName;
            obj.modifiedExecutablePath = parameters.modifiedExecutablePath;
            obj.guid = parameters.guid;
            obj.defaultInstallDirectory = parameters.defaultInstallDirectory;
            obj.applicationIcon = parameters.applicationIcon;
            obj.applicationLogo = parameters.applicationLogo;
            obj.version = parameters.version;
            obj.mcrExternalProductIdentifiers = parameters.mcrExternalProductIdentifiers;
        end

        function setInstallationNotes(obj, installationNotes)
            obj.installationNotes = installationNotes;
        end

        function setAuthorOrganization(obj, authorOrganization)
            obj.authorOrganization = authorOrganization;
        end

        function setApplicationSummary(obj, applicationSummary)
            obj.applicationSummary = applicationSummary;
        end

        function setWelcomePanelText(obj, welcomePanelText)
            obj.welcomePanelText = welcomePanelText;
        end

        function setAddRemoveProgramIcon(obj, addRemoveProgramIcon)
            obj.addRemoveProgramIcon = addRemoveProgramIcon;
        end

        function build(obj, manifestFile)
            import matlab.io.xml.dom.*
            import compiler.internal.ManifestBuilder
            doc = Document(ManifestBuilder.ROOT);
            docRootNode = getDocumentElement(doc);

            function newElement = createAndAppendChild(node, element, value)
                if ~isempty(value)
                    newElement = createElement(doc, element);
                    appendChild(newElement, createTextNode(doc, value));
                    appendChild(node, newElement);
                end
            end

            content = { ...
                {ManifestBuilder.DEFAULT_INSTALLATION_DIRECTORY_ELEMENT_NAME, obj.defaultInstallDirectory};
                {ManifestBuilder.APPLICATION_NAME_ELEMENT_NAME, obj.userApplicationName};
                {ManifestBuilder.EXECUTABLE_NAME_ELEMENT_NAME, obj.modifiedExecutablePath};
                {ManifestBuilder.GUID_ELEMENT_NAME, obj.guid};
                {ManifestBuilder.APP_ICON_ELEMENT_NAME, obj.applicationIcon};
                {ManifestBuilder.LOGO_ELEMENT_NAME, obj.applicationLogo};
                {ManifestBuilder.VERSION_ELEMENT_NAME, obj.version};
                {ManifestBuilder.INSTALLATION_NOTES_ELEMENT_NAME, obj.installationNotes};
                {ManifestBuilder.PROGRAM_ICON_ELEMENT_NAME, obj.addRemoveProgramIcon};
                {ManifestBuilder.AUTHOR_ORGANIZATION_ELEMENT_NAME, obj.authorOrganization};
                {ManifestBuilder.SUMMARY_ELEMENT_NAME, obj.applicationSummary};
                {ManifestBuilder.WELCOME_PANEL_TEXT_ELEMENT_NAME, obj.welcomePanelText}
                };

            cellfun(@(c)createAndAppendChild(docRootNode, c{1}, c{2}), content, ...
                'UniformOutput', false);
            
            if isempty(obj.mcrExternalProductIdentifiers)
                createAndAppendChild(docRootNode, ManifestBuilder.MCR_PRODUCTS, '');
            else
                mcrProductsElement = createElement(doc, ManifestBuilder.MCR_PRODUCTS);
                appendChild(docRootNode, mcrProductsElement);
                for i = 1:numel(obj.mcrExternalProductIdentifiers)
                    mcrProductElement = createElement(doc, ManifestBuilder.MCR_PRODUCT);
                    appendChild(mcrProductsElement, mcrProductElement);

                    identifierElement = createElement(doc, ManifestBuilder.MCR_PRODUCT_IDENTIFIER);
                    appendChild(identifierElement, createTextNode(doc, num2str(obj.mcrExternalProductIdentifiers(i))));
                    appendChild(mcrProductElement, identifierElement);                    
                end
            end

            domWriter = matlab.io.xml.dom.DOMWriter;
            domWriter.Configuration.FormatPrettyPrint = true;
            domWriter.writeToFile(doc, manifestFile);
        end
    end
end