function settings = importXMLCloudClusterProfile(filename)
%importXMLCloudClusterProfile Returns a matlab.settings.SettingsGroup from
%   an XML MJSComputeCloud profile (legacy settings format). This is to be
%   consumed by parallel.Settings.

%   Copyright 2022-2023 The MathWorks, Inc.

    try
        settings = iGetEmptyParallelSettingsGroup();
        xmlsettings = iReadXMLSettings(filename);
    catch
        % If the XML parsing fails, we cannot know for sure if this is an
        % XML file (we cannot trust extensions). We just return empty, as it does
        % matlab.settings.importSettings in the same situation.
        settings = matlab.settings.SettingsGroup.empty();
        return
    end

    try
        settings = iBuildMJSCCSchedulerComponents(settings, xmlsettings);
        settings = iBuildMJSCCProfiles(settings, xmlsettings);
    catch err
        % At this point we know it is an XML settings file (legacy format),
        % so we can let the user know with a more informative message.
        ex = MException(message('parallel:settings:ImportProfileFailedToImportSettings', filename));
        ex = ex.addCause(err);
        throw(ex)
    end
end

function group = iGetEmptyParallelSettingsGroup()
    import parallel.internal.apishared.FilenameUtils
    % There is no MATLAB Settings API to construct an empty
    % matlab.settings.SettingsGroup, so we load a settings file which has just a
    % SettingsGroup called 'parallel' which is to be populated.
    filename = fullfile(toolboxdir('parallel'), ...
        'cluster/+parallel/@Settings/private/parallel.mlsettings');
    group = matlab.internal.importSettings(filename);
end

function xmlsettings = iReadXMLSettings(filename)
    import parallel.internal.apishared.FilenameUtils

    filename = FilenameUtils.getAbsolutePath(filename);
    xmlsettings = readstruct(filename, 'FileType', 'xml');

    % Get <settings name="parallel" ...>
    assert(xmlsettings.nameAttribute == "parallel");
    xmlsettings = xmlsettings.settings;
end

function settings = iBuildMJSCCSchedulerComponents(settings, xmlsettings)
    import parallel.internal.settings.ParallelSettingsTree

    % Get <settings name="schedulercomponents">
    allSchedCompsXML = xmlsettings(contains([xmlsettings.nameAttribute], ...
        ParallelSettingsTree.SchedulerComponentsNodeName));
    allSchedCompsSettings = settings.addGroup(ParallelSettingsTree.SchedulerComponentsNodeName);

    %Get <settings name="MJSComputeCloud" visible="true">
    mjsComputeCloudXML = allSchedCompsXML.settings;
    % We only support MJSComputeCloud XML settings profiles.
    if mjsComputeCloudXML.nameAttribute ~= "MJSComputeCloud"
        error(message('parallel:settings:ImportLegacyProfileInvalidClusterType', ...
            mjsComputeCloudXML.nameAttribute))
    end
    mjsComputeCloudSettings= allSchedCompsSettings.addGroup(mjsComputeCloudXML.nameAttribute);

    % <settings name="MyCluster" visible="true">
    clusterXML = mjsComputeCloudXML.settings;
    clusterSettings= mjsComputeCloudSettings.addGroup(clusterXML.nameAttribute);

    % Get all "key" tags. The ones listed below will be always present for MJSComputeCloud:
    %   <key name="Alias" visible="true">
    %   <key name="Certificate" visible="true">
    %   <key name="Identifier" visible="true">
    %   <key name="matlabRelease" visible="true">
    arrayfun(@(prop) clusterSettings.addSetting(prop.nameAttribute, "PersonalValue", ...
        convertStringsToChars(prop.string.value)), clusterXML.key);
end

function settings = iBuildMJSCCProfiles(settings, xmlsettings)
    import parallel.internal.settings.ParallelSettingsTree

    % Get <settings name="profiles">
    allProfilesXML = xmlsettings(contains([xmlsettings.nameAttribute], ...
        ParallelSettingsTree.ProfilesNodeName));
    allProfilesSettings = settings.addGroup(ParallelSettingsTree.ProfilesNodeName);

    % Get <settings name="ClusterName" visible="true">
    clusterXML = allProfilesXML.settings;
    profileSettings = allProfilesSettings.addGroup(clusterXML.nameAttribute);

    % Get all "key" tags. The ones listed below will be always present for MJSComputeCloud:
    %    <key name="Alias" visible="true">
    %    <key name="Description" visible="true">
    %    <key name="SchedulerComponent" visible="true">
    arrayfun(@(prop) profileSettings.addSetting(prop.nameAttribute, "PersonalValue", ...
        convertStringsToChars(prop.string.value)), clusterXML.key);
end
