function upgradedObjects = upgrade(upgrader, varargin, options)
% UPGRADE Internal implementation of TARGET.UPGRADE.

%   Copyright 2021 The MathWorks, Inc.

    arguments
        upgrader
    end
    arguments (Repeating)
        varargin
    end
    arguments
        options.ExportToMATLABFunction
        options.ExportFileName
        options.Overwrite
    end

    registeredUpgradePlugins = target.internal.UpgradePlugin.RegisteredPlugins;

    % We don't have a valid upgrader parameter.
    if ~registeredUpgradePlugins.isKey(upgrader)
        error(message("targetframework:Upgrade:UnknownUpgrader", upgrader, strjoin(registeredUpgradePlugins.keys, """, """)));
    end

    % At this point we should have a valid plugin class string, but we need
    % to ensure it exists, we cannot guarantee that the product it belongs
    % to is installed.
    pluginClassString = registeredUpgradePlugins(upgrader);
    upgrader = validatePluginClass(pluginClassString, upgrader, registeredUpgradePlugins.keys);

    % Execute the upgrade.
    upgradedObjects = upgrader.upgrade(varargin{:});
    assert(isa(upgradedObjects, "target.internal.Object"), "Upgrade should return an array of target.internal.Object instances.");

    % Export to a MATLAB function should the call site request it.
    if options.ExportToMATLABFunction && ~isempty(upgradedObjects)
        target.internal.export(upgradedObjects, "FileName", options.ExportFileName, "Overwrite", options.Overwrite);
    end
end

function upgrader = validatePluginClass(classString, upgrader, registeredUpgraders)

    if ~target.internal.UpgradePlugin.isaValid(classString)
        error(message("targetframework:Upgrade:UnknownUpgrader", upgrader, strjoin(registeredUpgraders, """, """)));
    end

    % Create an instance of the plugin class
    upgrader = feval(classString);
end
