function configsInPrefs = upgradeConfigurationsToProfiles()
% upgradeConfigurationsToProfiles - Upgrade configurations to profiles
%
% upgradeConfigurationsToProfiles() takes the configurations that are
% stored in preferences and creates the appropriate profiles and components
% from them.  Note that if the upgrade is successful, this function deletes 
% all of the configurations from the preferences so that they cannot be 
% upgraded again.  If the upgrade is not successful, the preferences are 
% preserved.  The time of the last upgrade attempt is stored in Settings 
% and is accessible via the parallel.Settings object.
% 
% configsInPrefs = upgradeConfigurationsToProfiles() returns the
% configurations structure that was stored in preferences.  To restore
% these configurations to the preferences, use the following code:
%
%   configsInPrefs = upgradeConfigurationsToProfiles();
%   prefGroup = 'DCTConfigurations';
%   names = fieldnames(configsInPrefs);
%   for ii = 1:numel(names)
%       currName = names{ii};
%       if ispref(prefGroup, currName)
%           setpref(prefGroup, currName, configsInPrefs.(currName));
%       else
%           addpref(prefGroup, currName, configsInPrefs.(currName));
%       end
%   end
%

%   Copyright 2011 The MathWorks, Inc.

configsInPrefs = struct([]);

% Check Settings to see if an upgrade has already occurred
p = parallel.Settings;
if ~p.hNeedsConfigurationsUpgrade
    return;
end

configPrefGroup = 'DCTConfigurations';
if ~ispref(configPrefGroup)
    return;
end
configsInPrefs = getpref(configPrefGroup);
if isempty(configsInPrefs)
    return;
end

upgradeSuccessful = false;
defaultConfigPrefName = 'current';
defaultProfile = '';
if isfield(configsInPrefs, defaultConfigPrefName)
    defaultProfile = configsInPrefs.(defaultConfigPrefName);
end

configurationsPrefName = 'configurations';
if isfield(configsInPrefs, configurationsPrefName)
    [upgradeSuccessful, defaultProfile] = iUpgradeConfigurations(configsInPrefs.(configurationsPrefName), defaultProfile);
end

if ~isempty(defaultProfile)
    p = parallel.Settings;
    try
        p.DefaultProfile = defaultProfile;
    catch err
        warning(message('parallel:settings:UpgradeConfigurationsFailedToChangeDefault', defaultProfile, err.getReport()));
        upgradeSuccessful = false;
    end
end

% Remove the configs from the preferences so that they don't get
% upgraded again.
if upgradeSuccessful
    rmpref(configPrefGroup);
end

% Put something in Settings to indicate an upgrade occurred.
p.hSetConfigurationsUpgraded();

%--------------------------------------------------------
function [upgradeSuccessful, defaultProfileName] = iUpgradeConfigurations(configurations, defaultProfileName)
% Do the upgrade, returning the name of the default profile.
import parallel.internal.settings.ProfilesConverter
p = parallel.Settings;
numConfs = numel(configurations);
configAndProfNames   = cell(numConfs, 2);
failedToUpgradeIdx   = false(numConfs, 1);
changedNameIdx       = false(numConfs, 1);
localProfile = p.hGetLocalProfile();
localName = 'local';
for ii = 1:numConfs
    currConfig = configurations(ii);
    configName = currConfig.Name;
    % Don't do any upgrading if the configuration is actually empty as 
    % we won't even be able to deduce what type it is.
    if isempty(currConfig.Values)
        continue
    end
    configAndProfNames{ii, 1} = configName;
    try
        % NB the local config can have an empty value struct if local was deleted and 
        % auto-regenerated
        if strcmp(configName, localName) && ~isempty(localProfile)
            % Make sure we never create a new local profile unnecessarily 
            % because it should already defined in the factory.  
            ProfilesConverter.setConfigurationStructOnProfile(localProfile, currConfig);
            configAndProfNames{ii, 2} = localProfile.Name;
        else
            newProfile = ProfilesConverter.createProfileFromConfigurationStruct(currConfig);
            profileName = newProfile.Name;
            configAndProfNames{ii, 2} = profileName;
            if ~strcmp(configName, profileName)
                changedNameIdx(ii) = true;
                % Make sure the default profile name matches the name of the newly created profile
                if strcmp(configName, defaultProfileName)
                    defaultProfileName = profileName;
                end
            end
        end
    catch err %#ok<NASGU>
        % Save up errors for a warning later
        failedToUpgradeIdx(ii) = true;
        % If we failed to upgrade the default profile, then don't try to change it.
        if strcmp(configName, defaultProfileName)
            defaultProfileName = '';
        end
    end
end

if any(failedToUpgradeIdx)
    failedToUpgradeNames = configAndProfNames(failedToUpgradeIdx, 1);
    warning(message('parallel:settings:UpgradeConfigurationsToProfilesFailed', strtrim( sprintf( '%s ', failedToUpgradeNames{ : } ) )));
    upgradeSuccessful = false;
else
    upgradeSuccessful = true;
end

if any(changedNameIdx)
    % Transpose names for easier formatting
    configsWithChangedNames = configAndProfNames(changedNameIdx, :);
    % If any of the original names were not valid varnames, then we should
    % use the "Profiles must be valid variable names" message.
    if all(cellfun(@p.hIsValidName, configAndProfNames(:, 1)))
        msgId = 'parallel:settings:UpgradeConfigurationsNamesChanged';
    else
        msgId = 'parallel:settings:UpgradeConfigurationsNamesChangedNotVarName';
    end
    configsWithChangedNames = configsWithChangedNames';
    warning(message(msgId, sprintf( '\t''%s'' --> ''%s''\n', configsWithChangedNames{ : } )));
end

