function [H,range,data,time,userrange,freq,varargout] = gplot(fcn,varargin)
% gplot  [Not a public function] Master plot function for tseries objects.
%
% Backend IRIS function.
% No help provided.

% -IRIS Toolbox.
% -Copyright (c) 2007-2012 Jaromir Benes.

% Note that if caller supplies empty `fcn`, the graph will not be actually
% created.

% User-specified handle to axes. Otherwise, the gca will be used. Make
% sure this complies with future Matlab graphics implementation where
% handles will no longer be numerics.
if length(varargin{1}) == 1 && ishghandle(varargin{1})
    ax = varargin{1}(1);
    varargin(1) = [];
else
    ax = gca();
end

% User-defined range. Otherwise the entire range of the tseries object
% will be plotted. A cell array is passed in by the `plotyy` function
% to also indicate the other axes' range that must be comprised by the
% current one.
if isnumeric(varargin{1})
    comprise = [];
    range = varargin{1};
    varargin(1) = [];
elseif iscell(varargin{1}) && length(varargin{1}) == 2 ...
        && all(cellfun(@isnumeric,varargin{1}))
    comprise = varargin{1}{2};
    range = varargin{1}{1};
    varargin(1) = [];
else
    comprise = [];
    range = Inf;
end

userrange = range;

% Tseries object that will be plotted.
x = varargin{1};
varargin(1) = [];

flag = true;
plotspecs = {};
if length(varargin) == 1 && ischar(varargin{1})
    plotspecs = varargin(1);
    varargin(1) = [];
end
[opt,varargin] = passvalopt('tseries.mygraph',varargin{:});

% In shortcut line specification, we allow for date format to be included
% after a |.
if ~isempty(plotspecs)
    index = find(plotspecs{1} == '|',1);
    if ~isempty(index)
        opt.dateformat = plotspecs{1}(index+1:end);
        plotspecs{1} = plotspecs{1}(1:index-1);
    end
end

if ~flag
    error('Incorrect type of input argument(s).');
end

%**************************************************************************

x.data = x.data(:,:);
[nper,nx] = size(x.data); %#ok<ASGLU>
range = specrange(x,range);

H = [];
if isempty(range)
    warning('iris:tseries', ...
        'No graph displayed because date range is empty.');
    return
end

freq = datfreq(range(1));

% Original x-axis limits.
xLim0 = get(ax,'xLim');

% Bar graph adjustments at either end of the x-axis.
xLimAdjust0 = getappdata(ax,'xLimAdjust');
if isempty(xLimAdjust0)
    xLimAdjust0 = 0;
end

% If hold==on, make sure new range comprises existing dates if the
% graph is a tseries graph.
if ~isempty(fcn) ...
        && ~isempty(range) && strcmp(get(ax,'nextPlot'),'add') ...
        && isequal(getappdata(ax,'tseries'),true)
    range = domergerange(range([1,end]),xLim0-[-xLimAdjust0,xLimAdjust0]);
end

% Make sure the new range and `userrange` both comprise the `comprise`
% dates. This is used in `plotyy`.
if ~isempty(comprise)
    range = domergerange(range,comprise);
    if ~isequal(userrange,Inf)
        userrange = domergerange(userrange,comprise);
    end
end

data = mygetdata(x,range);
time = dat2grid(range,opt.dateposition);

if isempty(fcn)
    return
end

set(ax,'xTickMode','auto','xTickLabelMode','auto');
switch char(fcn)
    case {'scatter'}
        if nx ~= 2
            utils.error('tseries', ...
                'Scatter plot input data must have exactly two columns.');
        end
        H = scatter(ax,data(:,1),data(:,2),plotspecs{:});
        if ~isempty(varargin)
            set(H,varargin{:});
        end
        istimeaxis = false;
    case {'barcon'}
        % Do not pass `plotspecs` but do pass user options.
        [H,varargout{1}] = tseries.mybarcon(ax,time,data,varargin{:});
        istimeaxis = true;
    otherwise
        H = fcn(ax,time,data,plotspecs{:});
        if ~isempty(varargin)
            set(H,varargin{:});
        end
        istimeaxis = true;
end

if any(strcmp(char(fcn),{'bar','barcon'}))
    setappdata(ax,'xLimAdjust',true);
end

% Set up the x-axis with proper dates. Do not do this if `time` is NaN,
% which happens with empty tseries.
if istimeaxis && ~isequalwithequalnans(time,NaN)
    tseries.timeline(ax,time,userrange,freq,opt);
    % Expand xLim for bar graphs, or make sure they are kept wide if a
    % bar graph is added a non-bar plot.
    if isequal(getappdata(ax,'xLimAdjust'),true)
        if freq > 0
            xLimAdjust = 0.5/freq;
        else
            xLimAdjust = 0.5;
        end
        xlim = get(ax,'xLim');
        set(ax,'xLim',xlim + [-xLimAdjust,xLimAdjust]);
    end
    % Earmark the axes for the highlight function.
    setappdata(ax,'tseries',true);
    setappdata(ax,'freq',freq);
end

% Perform users function.
if ~isempty(opt.function)
    opt.function(H);
end

if opt.tight
    axis(ax,'tight');
end

%**************************************************************************
    function range = domergerange(range,comprise)
        first = grid2dat(comprise(1),freq,opt.dateposition);
        % Make sure ranges with different frequencies are merged properly.
        while dat2grid(first-1,opt.dateposition) > comprise(1)
            first = first - 1;
        end
        last = grid2dat(comprise(end),freq,opt.dateposition);
        while dat2grid(last+1,opt.dateposition) < comprise(end)
            last = last + 1;
        end
        range = min(range(1),first) : max(range(end),last);
    end
% domergerange().

end