function handles = plot(a_plot, layout_axis)

% plot - Draws this plot in the current axis or at the position in
%	layout_axis.
%
% Usage:
% handles = plot(a_plot, layout_axis)
%
% Description:
%
%   Parameters:
%	a_plot: A plot_abstract object, or a subclass object.
%	layout_axis: The axis position to layout this plot (Optional). 
%		
%   Returns:
%	handles: Handles of graphical objects drawn.
%
% See also: plot_stack, plot_abstract
%
% $Id$
%
% Author: Cengiz Gunay <cgunay@emory.edu>, 2004/10/04

% Copyright (c) 2007 Cengiz Gunay <cengique@users.sf.net>.
% This work is licensed under the Academic Free License ("AFL")
% v. 3.0. To view a copy of this license, please look at the COPYING
% file distributed with this software or visit
% http://opensource.org/licenses/afl-3.0.php.

% TODO: 
% - add new prop for affecting deep plot_stack props?
% - correct missing space at bottom

% Get generic verbose switch setting
vs = warning('query', 'verbose');
verbose = strcmp(vs.state, 'on');

a_plot_props = get(a_plot, 'props');

minwidth = 0.001;
minheight = 0.001;

% Setting up the layout_axis is the same as in plot_abstract/plot.m
% This must be the only code repeated between the two.
if isfield(a_plot_props, 'border')
  border = a_plot_props.border;
else
  border = 0;
end

plot_stack_id = [ 'plot_stack(' a_plot.orient ')' ];

if verbose
  disp([ plot_stack_id ': starting with props' ]);
  disp(a_plot_props);
end

if ~ exist('layout_axis', 'var')
  layout_axis = [];
end

% Call parent plot_abstract/plot.m to set up the axis position
% Open this axis for putting the title only
[this_axis, layout_axis] = openAxis(a_plot, layout_axis);

left_side = layout_axis(1);
bottom_side = layout_axis(2);
width = layout_axis(3);
height = layout_axis(4);

% Hide the axis, but not the title
set(this_axis, 'Visible', 'off');

% Put the plot_stack title first
if ~isfield(a_plot_props, 'noTitle') || a_plot_props.noTitle == 0
  th = title(get(a_plot, 'title'));
  set(th, 'Visible', 'on')
end

%disp(sprintf('Position: %0.3f+%0.3f+%0.3fx%0.3f', ...
%	     left_side, bottom_side, width, height));

% Pass the spacing cues from the parent plot to the children
if isfield(a_plot_props, 'noXLabel') && a_plot_props.noXLabel == 1
  a_plot_props.xLabelsPos = 'none';
end

if isfield(a_plot_props, 'XTickLabel') && isempty(a_plot_props.XTickLabel)
  a_plot_props.xTicksPos = 'none';
end

if isfield(a_plot_props, 'noYLabel') && a_plot_props.noYLabel == 1
  a_plot_props.yLabelsPos = 'none';
end

if isfield(a_plot_props, 'YTickLabel') && isempty(a_plot_props.YTickLabel)
  a_plot_props.yTicksPos = 'none';
end

% Divide the layout area according to number of plots contained
num_plots = length(a_plot.plots);

% Fixed size for ticks and labels
% Assume 10 pt font
% Fixed size for ticks and labels, scaled to 10pt font size for current figure
[dx, dy] = calcGraphNormPtsRatio(gcf);
decosize_x = 10 * dx;
decosize_y = 10 * dy;

% These values are only used to spare space for the first plot,
% and only if its specified that they have labels or ticks and the rest don't.
% This added space will be undone in plot_abstract/plot.m so that the 
% actual plots are the same size as other tiles.
tickheight = 0;
tickwidth = 0;
labelheight = 0;
labelwidth = 0;
titleheight = 0;

if strcmp(a_plot.orient, 'x') 
  if isfield(a_plot_props, 'yLabelsPos') && strcmp(a_plot_props.yLabelsPos, 'left')
    labelwidth = decosize_x;
  end
  
  if isfield(a_plot_props, 'yTicksPos') && strcmp(a_plot_props.yTicksPos, 'left')
    tickwidth = 3 * decosize_x;
  end
end

if strcmp(a_plot.orient, 'y') 
  if isfield(a_plot_props, 'xLabelsPos') && strcmp(a_plot_props.xLabelsPos, 'bottom')
    labelheight = 2 * decosize_y;
  end

  if isfield(a_plot_props, 'xTicksPos') && strcmp(a_plot_props.xTicksPos, 'bottom')
    tickheight = decosize_y;
  end
end

% If only topmost plot has title, give it more space
if isfield(a_plot_props, 'titlesPos') && strcmp(a_plot_props.titlesPos, 'top')
  titleheight = 2 * decosize_y;
end

% If a relative sizing given
if isfield(a_plot_props, 'relativeSizes')
  relative_sizes = a_plot_props.relativeSizes;
  if length(a_plot.plots) ~= length(relative_sizes)
    error([ 'Property relativeSizes (' num2str(length(relative_sizes)) ...
   	    ' items) should have same length as the plots array (' ...
 	    num2str(length(a_plot.plots)) ' items).' ]);
  end
else
  % otherwise all plots are equal size
  relative_sizes = ones(1, length(a_plot.plots));
end

if strcmp(a_plot.orient, 'x')
  tilewidth = max(width - labelwidth - tickwidth, minwidth) / sum(relative_sizes);
  tileheight = height;
elseif strcmp(a_plot.orient, 'y')
  tilewidth = width;
  tileheight = ...
	  max(height - labelheight - tickheight - titleheight, minheight) / ...
	  sum(relative_sizes);
end

% if infs in given axis_limits, find maximal range limits
if any(isinf(a_plot.axis_limits))
  maximal_ranges = [];
  for plot_num=1:num_plots
    if iscell(a_plot.plots)
      one_plot = a_plot.plots{plot_num};
    else
      one_plot = a_plot.plots(plot_num);
    end
    maximal_ranges = growRange([ maximal_ranges; axis(one_plot) ]);
  end
end

% Lay the stack out in a loop
for plot_num=1:num_plots
  % Initialize space variables
  left_space = 0;
  bottom_space = 0;
  title_space = 0;

  if strcmp(a_plot.orient, 'x')
    plot_seq = plot_num;
  else
    % invert the sequence, because matlab starts from bottom in Y axis
    plot_seq = num_plots - plot_num + 1;
  end
  if iscell(a_plot.plots)
    one_plot = a_plot.plots{plot_seq};
  else
    one_plot = a_plot.plots(plot_seq);
  end
  if isempty(one_plot)
    continue;
  end

  % Warning: one_plot's props are superceded by the plot_stack props
  % done for getting the correct label behavior, etc. (experimental)
  %its_props = mergeStructs(a_plot_props, get(one_plot, 'props'));
  its_props = get(one_plot, 'props');

  % Check if y-ticks only for the leftmost plot
  if isfield(a_plot_props, 'yTicksPos') 
    if ((plot_num > 1 && strcmp(a_plot_props.yTicksPos, 'left') && ...
	 strcmp(a_plot.orient, 'x')) || ...
	strcmp(a_plot_props.yTicksPos, 'none'))
      if isa(one_plot, 'plot_stack')
        its_props(1).yTicksPos = 'none';
      else
        its_props(1).YTickLabel = {};
      end
    else
      % Then, allocate space only for this first plot.
      left_space = tickwidth;
      %its_props(1).YTickLabel = 1; is this required?    
      if verbose
	disp([ plot_stack_id ': allocating one-time space for y-ticks.' ]);
      end
    end
  end
  if isfield(a_plot_props, 'yLabelsPos') 
    if ((plot_num > 1 && strcmp(a_plot_props.yLabelsPos, 'left') && ...
	 strcmp(a_plot.orient, 'x')) || ...
	strcmp(a_plot_props.yLabelsPos, 'none')) 
      if isa(one_plot, 'plot_stack')
        its_props(1).yLabelsPos = 'none';
      else
        its_props(1).noYLabel = 1;
      end
    else
      % Then, allocate space only for this first plot.
      left_space = left_space + labelwidth;
      if ~isfield(its_props, 'noYLabel') || its_props.noYLabel == 0
	its_props(1).noYLabel = 0;
      end
      if verbose
	disp([[ plot_stack_id ': allocating one-time ' num2str(left_space) ' space for y-label.' ]]);
      end
    end
  end

  if isfield(a_plot_props, 'xTicksPos') && ...
	((plot_num > 1 && strcmp(a_plot_props.xTicksPos, 'bottom') && ...
	  strcmp(a_plot.orient, 'y')) || ...
	 strcmp(a_plot_props.xTicksPos, 'none'))
    if isa(one_plot, 'plot_stack')
      its_props(1).xTicksPos = 'none';
    else
      its_props(1).XTickLabel = {};
    end
  else
    bottom_space = tickheight;
    if verbose
      disp([ plot_stack_id ': allocating one-time space for x-ticks.' ]);
    end
    %its_props(1).XTickLabel = 1;
  end
  if isfield(a_plot_props, 'xLabelsPos') && ...
	((plot_num > 1 && strcmp(a_plot_props.xLabelsPos, 'bottom') && ...
	  strcmp(a_plot.orient, 'y')) || ...
	 strcmp(a_plot_props.xLabelsPos, 'none'))
    if isa(one_plot, 'plot_stack')
      its_props(1).xLabelsPos = 'none';
    else
      its_props(1).noXLabel = 1;
    end
  else
    % Signal to plot that it has space to put its labels
    bottom_space = bottom_space + labelheight;
    if ~isfield(its_props, 'noXLabel') || its_props.noXLabel == 0
      its_props(1).noXLabel = 0;
    end
    if verbose
      disp([ plot_stack_id ': allocating one-time ' num2str(bottom_space) ' space for x-label.' ]);
      end
  end
  % Check if title only for the topmost plot
  if isfield(a_plot_props, 'titlesPos') 
    if 	(plot_num < num_plots && strcmp(a_plot_props.titlesPos, 'top') && ...
	 strcmp(a_plot.orient, 'y'))
      if isa(one_plot, 'plot_stack')
        its_props(1).titlesPos = 'none';
        its_props(1).noTitle = 1;
      else
        its_props(1).noTitle = 1;
      end
    else
      title_space = titleheight;
    end
    if strcmp(a_plot_props.titlesPos, 'none')
      if isa(one_plot, 'plot_stack')
        its_props(1).titlesPos = 'none';
        its_props(1).noTitle = 1;
      else
        its_props(1).noTitle = 1;
      end
    end
  end

  % Set the modified properties back to the plot
  one_plot = set(one_plot, 'props', its_props);

  % Calculate subplot positioning
  x_offset = left_side + labelwidth + tickwidth - left_space + ...
      strcmp(a_plot.orient, 'x') * sum(relative_sizes(1:(plot_num - 1))) * tilewidth;
  y_offset = bottom_side  + labelheight + tickheight - bottom_space + ...
      strcmp(a_plot.orient, 'y') * sum(relative_sizes((plot_seq + 1):end)) * tileheight;
  if strcmp(a_plot.orient, 'x')
    this_width = relative_sizes(plot_num) * tilewidth;
    this_height = tileheight;
  else
    this_width = tilewidth;
    this_height = relative_sizes(plot_seq) * tileheight;
  end
  position = [x_offset, y_offset, ...
  	      this_width + left_space, ...
  	      this_height + bottom_space + title_space ];
  one_handle = plot(one_plot, position);
  % Set its axis limits if requested
  current_axis = axis;
  if ~ isempty(a_plot.axis_limits)
    infs = isinf(a_plot.axis_limits);
    if any(infs)
      % replace the infs from the maximal ranges
      a_plot.axis_limits(infs) = maximal_ranges(infs);
    end
    current_axis = setAxisNonNaN(a_plot.axis_limits);
  end
  if isfield(a_plot_props, 'relaxedLimits') && a_plot_props.relaxedLimits == 1
    % Set axis limits to +/- 10% of bounds
    axis_width = current_axis(2) - current_axis(1);
    axis_height = current_axis(4) - current_axis(3);
    current_axis(1) = current_axis(1) - axis_width * .1;
    current_axis(2) = current_axis(2) + axis_width * .1;
    current_axis(3) = current_axis(3) - axis_height * .1;
    current_axis(4) = current_axis(4) + axis_height * .1;
  end
  axis(current_axis);
  % Place other decorations
  one_handle = decorate(one_plot, one_handle);
end

% not used here (TODO: could return at least list of axes)
handles = struct('plot', [], 'axis', []);

hold off;