function oldpath = addpath(varargin)
%ADDPATH Add folder to search path.
%   ADDPATH FOLDERNAME prepends the specified folder to the current
%   matlabpath.  Surround FOLDERNAME in quotes if the name contains a
%   space.  If FOLDERNAME is a set of multiple folders separated by path
%   separators, then each of the specified folders will be added.
%
%   ADDPATH FOLDERNAME1 FOLDERNAME2 FOLDERNAME3 ...  prepends all the
%   specified folders to the path.
%
%   ADDPATH ... -END    appends the specified folders.
%   ADDPATH ... -BEGIN  prepends the specified folders.
%   ADDPATH ... -FROZEN disables folder change detection for folders
%                       being added.
%
%   Use the functional form of ADDPATH, such as
%   ADDPATH('folder1','folder2',...), when the folder specification is
%   a variable or string.
%
%   P = ADDPATH(...) returns the path prior to adding the specified paths.
%
%   Examples
%       addpath c:\matlab\work
%       addpath /home/user/matlab
%       addpath /home/user/matlab:/home/user/matlab/test:
%       addpath /home/user/matlab /home/user/matlab/test
%
%   See also RMPATH, PATHTOOL, PATH, SAVEPATH, USERPATH, GENPATH, REHASH.

%   Copyright 1984-2023 The MathWorks, Inc.

% Number of  input arguments
    n = nargin;
    narginchk(1,Inf);
    [varargin{:}] = convertStringsToChars(varargin{:});

    if nargout>0
        oldpath = path;
    end

    append = -1;
    freeze = 0;
    args = varargin;

    while (n > 1)
        last = args{n};
        % Append or prepend to the existing path
        if isequal(last,1) || strcmpi(last,'-end')
            if (append < 0), append = 1; end
            n = n - 1;
        elseif isequal(last,0) || strcmpi(last,'-begin')
            if (append < 0), append = 0; end
            n = n - 1;
        elseif strcmpi(last,'-frozen')
            freeze = 1;
            n = n - 1;
        else
            break;
        end
    end
    if (append < 0), append = 0; end

    % Check, trim, and concatenate the input strings
    if (n == 1 && isscalar(varargin{1}) && any(varargin{1} == pathsep))
        % handle deprecated input form
        p = catdirs(mfilename,varargin{1:n});
    else
        % Check for and resolve any package specifiers in input
        resolveddirs = resolveAnyPackages('installed',varargin{1:n});
        if isempty(resolveddirs)
            return
        end
        p = catdirs(mfilename,resolveddirs{:});
    end

    % If p is empty then return
    if isempty(p)
        return;
    elseif ~isempty(strfind(p, char(0)))
        error(message('MATLAB:FileManip:NullCharacterInName'));
    end

    paths = strsplit(p,pathsep());
    if ~((matlab.internal.feature('packages') ~= int32(0)) && ~isempty(getenv("PACKAGE_SPIN")))
        if freeze
            for n = 1:size(paths,2)-1
                feature('DirectoryFreeze',paths{n});
            end
        end
        doPathAddition(p, append);
    else
        % This is non-shipping code branch
        for m = 1:length(paths)-1
            aFolder = paths{m};
            if doesPackageJsonFileExist(aFolder)
                [isRegistered, isOnPath] = isRegisteredAndIsOnPath(aFolder);

                if isRegistered && isOnPath
                    % no-op as it is already on the path
                elseif isRegistered && ~isOnPath
                    % Already installed but its root folder is removed from MATLAB search path
                    matlab.internal.package.addToTheSearchPathOrder(aFolder);
                else
                    % isRegistered is false
                    matlab.mpm.internal.register(aFolder, '-temporary');
                end
            else
                % When feature is ON, allow normal addpath operation for
                % folders not having resources/mpackage.json
                if freeze
                    feature('DirectoryFreeze', aFolder);
                end
                doPathAddition(aFolder, append)
            end
        end
    end

end

function doPathAddition(p, append)
% Append or prepend the new path
    mp = matlabpath;
    if append
        path(mp, p);
    else
        path(p, mp);
    end
end

function tf = doesPackageJsonFileExist(aFolder)
    tf = exist(fullfile(aFolder, 'resources'), 'dir') && ...
         exist(fullfile(aFolder, 'resources', "mpackage.json"), 'file');
end

function [isRegistered, isOnPath] = isRegisteredAndIsOnPath(loc)
    installedPackages = matlab.mpm.internal.list();
    tmp = arrayfun(@(x)checkInstall(x, loc), installedPackages);
    if any(tmp)
        isRegistered = true;
        isOnPath = installedPackages(tmp).OnThePath;
    else
        isRegistered = false;
        isOnPath = false;
    end

    function y = checkInstall(p, loc)
        t = matlab.mpm.internal.info(p.Package);
        try
            y = isequal(builtin('_canonicalizepath', t.InstallationLocation), ...
                        builtin('_canonicalizepath', loc));
        catch
            y = false;
        end
    end
end
