function [out,varargout] = subsref(G, S)
%

%   Copyright 2014-2020 The MathWorks, Inc.

%  Only dot subscripting is allowed on graph.
if ~strcmp(S(1).type, '.')
    error(message('MATLAB:graphfun:graph:ScalarObject'));
end

% Store for re-use, avoid looking up multiple times for performance
S1subs = S(1).subs;

if strcmp(S1subs, 'Edges')
    if isscalar(S)
        out = getEdgesTable(G);
        nargoutchk(0, 1);
    else
        if strcmp(S(2).type, '.')
            % Short-circuit to EdgeProperties if appropriate.
            S2subs = S(2).subs;
            edges = G.EdgeProperties;
            if strcmp(S2subs, 'Weight') && isnumeric(edges) && iscolumn(edges)
                % Use minimized (weights-only) edge properties
                if numel(S) == 2
                    out = edges;
                    nargoutchk(0, 1);
                    return
                end
                S(1:2) = [];
            elseif matches(S2subs, 'EndNodes')
                EndNodes = G.Underlying.Edges;
                [names, hasNodeNames] = getNodeNames(G);
                if hasNodeNames
                    EndNodes = reshape(names(EndNodes), [], 2);
                end
                if numel(S) == 2
                    out = EndNodes;
                    nargoutchk(0, 1);
                    return
                end
                edges = EndNodes;
                S(1:2) = [];
            elseif matches(S2subs, 'Properties')
                edges = getEdgesTable(G);
                S(1) = [];
            else
                edges = getEdgePropertiesTable(G);
                S(1) = [];
            end
        else
            % G.Edges(...) or G.Edges{...}
            useEdgeProp = false;
            if numel(S(2).subs) == 2 % other numbers here result in error from table indexing
                % Case G.Edges(firstInd, secondInd) = V or G.Edges{firstInd, secondInd} = V
                % Error if first variable (EndNodes) is impacted, otherwise
                % modify j so that it can be applied to G.EdgeProperties.
                secondInd = S(2).subs{2};
                if isnumeric(secondInd)
                    if ~any(secondInd == 1)
                        secondInd = secondInd - 1;
                        useEdgeProp = true;
                    end
                elseif islogical(secondInd) && ~isempty(secondInd)
                    if ~secondInd(1)
                        secondInd(1) = [];
                        useEdgeProp = true;
                    end
                elseif ischar(secondInd) || iscellstr(secondInd) || isstring(secondInd)
                    if ~isequal(secondInd, ':') && ~any(strcmp(secondInd, 'EndNodes'))
                        useEdgeProp = true;
                    end
                end
                S(2).subs{2} = secondInd;
            end
            if useEdgeProp
                edges = getEdgePropertiesTable(G);
            else
                edges = getEdgesTable(G);
            end
            S(1) = [];
        end
        if nargout == 1
            out = subsref(edges, S);
        elseif nargout == 0
            % Need to pass through the information that there's 0 outputs.
            [args{1:nargout}] = subsref(edges, S);
            if ~isempty(args)
                out = args{1};
                varargout = args(2:end); % Should be empty, but let's pass it along just in case.
            end
        else
            [out, varargout{1:nargout-1}] = subsref(edges, S);
        end
    end
elseif strcmp(S1subs, 'Nodes')
    if isscalar(S)
        nargoutchk(0, 1);
        out = getNodePropertiesTable(G);
    else
        if strcmp(S(2).type, '.') && strcmp(S(2).subs, 'Name')
            % Short-circuit to minimized NodeProperties if appropriate.
            nodeprop = G.NodeProperties;
            if iscell(nodeprop)
                if numel(S) == 2
                    out = nodeprop;
                    nargoutchk(0, 1);
                else
                    S(1:2) = [];
                    if nargout == 1
                        out = subsref(nodeprop, S);
                    elseif nargout == 0
                        % Need to pass through the information that there's 0 outputs.
                        [args{1:nargout}] = subsref(nodeprop, S);
                        if ~isempty(args)
                            out = args{1};
                            varargout = args(2:end); % Should be empty, but let's pass it along just in case.
                        end
                    else
                        [out, varargout{1:nargout-1}] = subsref(nodeprop, S);
                    end
                end
                return
            end
        end
        
        nodeprop = getNodePropertiesTable(G);
        S(1) = [];
        if nargout == 1
            out = subsref(nodeprop, S);
        elseif nargout == 0
            % Need to pass through the information that there's 0 outputs.
            [args{1:nargout}] = subsref(nodeprop, S);
            if ~isempty(args)
                out = args{1};
                varargout = args(2:end); % Should be empty, but let's pass it along just in case.
            end
        else
            [out, varargout{1:nargout-1}] = subsref(nodeprop, S);
        end
    end
else
    % Only allow access of public properties/methods.  Otherwise flow through...
    if ismethod(G, S1subs)
        % Any call G.graphmethod(...) is passed through here.
        if nargout == 1
            out = builtin('subsref', G, S);
        elseif nargout == 0
            % Need to pass through the information that there's 0 outputs, e.g. addedge will warn in this case
            [args{1:nargout}] = builtin('subsref', G, S);
            if ~isempty(args)
                out = args{1};
                varargout = args(2:end); % Should be empty, but let's pass it along just in case.
            end
        else
            [out, varargout{1:nargout-1}] = builtin('subsref', G, S);
        end
    else
        mc = metaclass(G);
        if isempty( findobj(mc.PropertyList, '-depth',0,'Name', S1subs) )
            error(message('MATLAB:noSuchMethodOrField', S1subs, class(G)));
        else
            error(message('MATLAB:class:GetProhibited', S1subs, class(G)));
        end
    end
end
