function axReturn = newplot(hsave)
% NEWPLOT Determine where to draw graphics objects.
% 
%    NEWPLOT prepares the current axes of the current figure for subsequent 
%    graphics commands.
% 
%    NEWPLOT(target) prepares the object specified by target for plotting 
%    instead of the current axes of the current figure. The target object 
%    can be a Cartesian axes, polar axes, or geographic axes object. If 
%    target is empty, newplot behaves as if it were called without any inputs.
%
%    H = NEWPLOT(...) prepares a figure and axes for subsequent graphics 
%    commands and returns the current axes.
%
%    To create a simple 2-D plot, use the plot function instead.
% 
%    Use NEWPLOT at the beginning of high-level graphics code to determine
%    which figure and axes to target for graphics output. Calling NEWPLOT can
%    change the current figure and current axes. 
% 
%    The figure and axes NextPlot properties determine how NEWPLOT behaves 
%    when you are drawing graphics in existing figures and axes:
%       - NextPlot 'new': Create a new figure and use it as the
%         current figure. This option is only available for the figure
%         NextPlot property.
%       - NextPlot 'add': Add the new graphics without changing any properties
%         or deleting any objects. 
%       - NextPlot 'replacechildren': Delete all existing objects whose handles 
%         are not hidden before drawing the new objects. 
%       - NextPlot 'replace': Delete all existing objects 
%         regardless of whether or not their handles are hidden, and reset 
%         most properties to their defaults before drawing the new objects. 
%       - NextPlot 'replaceall': Delete all existing objects and reset both
%         sides of an Axes object with two y-axes. This option is only
%         available for the axes NextPlot property, and is equivalent to
%         'replace' for Axes objects with a single y-axis.
%
%    See also axes, cla, clf, figure, hold, ishold, plot, reset.

%   Copyright 1984-2021 The MathWorks, Inc.
%   Built-in function.

if nargin == 0 || isempty(hsave)
    hsave = [];
elseif ~isscalar(hsave) || ~ishghandle(hsave)
    error(message('MATLAB:newplot:InvalidHandle'))
else
    % Make sure we have an object handle.
    hsave = handle(hsave);
end

% Get the ancestor axes and figure from the input (if present).
fig = gobjects(0);
ax = gobjects(0);
if ~isempty(hsave)
    obj = hsave;
    while ~isempty(obj)
        if isgraphics(obj, 'figure')
            fig = obj;
        elseif isgraphics(obj,'axes') || isgraphics(obj,'polaraxes') || isgraphics(obj,'geoaxes')
            ax = obj;
        end
        obj = obj.Parent;
    end
end

% If no axes or figure was found, create a new figure. Check if the axes is
% empty to avoid creating a figure if an unparented axes was provided.
if isempty(fig) && isempty(ax)
    fig = gcf;
end

if ~isempty(fig)
    % Prepare the figure based on the NextPlot property.
    fig = ObserveFigureNextPlot(fig, hsave);

    % Set figure's NextPlot property to 'DefaultFigureNextplot' after obeying the previous setting.
    fig.NextPlot = get(groot, 'DefaultFigureNextplot');
end

checkNextPlot=true;
if isempty(ax)
    ax = gca(fig);
    if ~isa(ax,'matlab.graphics.axis.Axes')
        if isprop(ax,'NextPlot') && ishold(ax)
            error(message('MATLAB:newplot:HoldOnMixing',ax.Type))
        else
            ax = matlab.graphics.internal.swapaxes(ax,@axes);
            
            % We just created a new axes, no need to check NextPlot
            checkNextPlot = false;
        end
    end
elseif ~any(ishghandle(ax))
    error(message('MATLAB:newplot:NoAxesParent'))
end

if checkNextPlot
    ax = ObserveAxesNextPlot(ax, hsave);
end

if nargout
    axReturn = ax;
end

function fig = ObserveFigureNextPlot(fig, hsave)
%
% Helper fcn for preparing figure for nextplot, optionally
% preserving specific existing descendants.
% GUARANTEED to return a figure, even if some crazy combination
% of create / delete fcns deletes it.

switch fig.NextPlot
    case 'new'
        % if someone calls plot(x,y,'parent',h) and h is an axes
        % in a figure with NextPlot 'new', ignore the 'new' and
        % treat it as 'add' - just add the axes to that figure.
        if isempty(hsave)
            fig = figure;
        end
    case 'replace'
        clf(fig, 'reset', hsave);
    case 'replacechildren'
        clf(fig, hsave);
    case 'add'
        % nothing
end
if ~any(ishghandle(fig)) && isempty(hsave)
    fig = figure;
end

function ax = ObserveAxesNextPlot(ax, hsave)
%
% Helper fcn for preparing axes for nextplot, optionally
% preserving specific existing descendants
% GUARANTEED to return an axes in the same figure as the passed-in
% axes, even if that axes gets deleted by an overzealous create or
% delete fcn anywhere in the figure.

% for performance only call ancestor when needed
fig = ax.Parent;
if ~isempty(fig) && ~strcmp(fig.Type,'figure')
    fig = ancestor(fig,'figure');
end

switch ax.NextPlot
    case 'replaceall'
        cla(ax, 'reset', hsave);
    case 'replace'
        % If there are multiple data spaces, ax.prepareForPlot() will do a
        % reset of the properties for the active data space (while
        % preserving other data spaces) and return false to indicate that a
        % full reset is not necessary. Otherwise, ax.prepareForPlot() will
        % return true.
        if (ax.prepareForPlot())
            cla(ax, 'reset', hsave);
        else
            cla(ax, hsave);
        end
    case 'replacechildren'
        cla(ax, hsave);
    case 'add'
        % nothing
end

if ~any(ishghandle(ax)) && isempty(hsave)
    if ~any(ishghandle(fig))
        ax = axes;
    else
        ax = axes('Parent',fig);
    end
end
