%% Copyright (C) 2004-2012 David Legland <david.legland@grignon.inra.fr>
%% All rights reserved.
%%
%% Redistribution and use in source and binary forms, with or without
%% modification, are permitted provided that the following conditions are met:
%%
%%     1 Redistributions of source code must retain the above copyright notice,
%%       this list of conditions and the following disclaimer.
%%     2 Redistributions in binary form must reproduce the above copyright
%%       notice, this list of conditions and the following disclaimer in the
%%       documentation and/or other materials provided with the distribution.
%%
%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
%% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
%% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
%% ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
%% ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
%% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
%% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
%% CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
%% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%%
%% 2012 Adapted to Octave by Juan Pablo Carbajal <carbajal@ifi.uzh.ch>

%% -*- texinfo -*-
%% @deftypefn {Function File}  drawGraph (@var{nodes}, @var{edges})
%% @deftypefnx {Function File}  drawGraph (@var{nodes}, @var{edges}, @var{faces})
%% @deftypefnx {Function File}  drawGraph (@var{graph})
%% @deftypefnx {Function File}  drawGraph (@dots{}, @var{snodes})
%% @deftypefnx {Function File}  drawGraph (@dots{}, @var{snodes}, @var{sedges})
%% @deftypefnx {Function File}  drawGraph (@dots{}, @var{snodes}, @var{sedges}, @var{sfaces})
%% @deftypefnx {Function File}  {@var{h} = } drawGraph (@dots{})
%% @deftypefnx {Function File}  {[@var{h} @var{he}] = } drawGraph (@dots{})
%% @deftypefnx {Function File}  {[@var{h} @var{he} @var{hf}] = } drawGraph (@dots{})
%% Draw a graph, given as a set of vertices and edges
%%
%%   DRAWGRAPH(NODES, EDGES)
%%   draw a graph specified by a set of nodes (array N*2 or N*3,
%%   corresponding to coordinate of each node), and a set of edges (an array
%%   Ne*2, containing for each edge the first and the second node).
%%   Default drawing is a red circle for nodes and a blue line for edges.
%%
%%   DRAWGRAPH(NODES, EDGES, FACES)
%%   also draw faces of the graph as patches.
%%
%%   DRAWGRAPH(GRAPH)
%%   passes argument in a srtucture with at least 2 fields named 'nodes' and
%%   'edges', and possibly one field 'faces', corresponding to previously
%%   described parameters.
%%   GRAPH can also be a cell array, whose first element is node array,
%%   second element is edges array, and third element, if present, is faces
%%   array.
%%
%%
%%   DRAWGRAPH(..., SNODES)
%%   DRAWGRAPH(..., SNODES, SEDGES)
%%   DRAWGRAPH(..., SNODES, SEDGES, SFACES)
%%   specify the draw mode for each element, as in the classical 'plot'
%%   function. To not display some elements, uses 'none'.
%%
%%
%%   H = DRAWGRAPH(...)
%%   return handle to the set of edges.
%%
%%   [HN, HE] = DRAWGRAPH(...)
%%   return handle to the set of nodes and to the set of edges.
%%
%%   [HN, HE, HF] = DRAWGRAPH(...)
%%   Also return handle to the set of faces.
%%
%% @end deftypefn
function varargout = drawGraph(varargin)

  %% initialisations

  % uses empty arrays by default for edges and faces
  e = [];
  f = [];

  % default styles for nodes, edges, and faces

  % nodes are drawn as red circles
  sn = {'linestyle', 'none', 'color', 'r', 'marker', 'o'};

  % edges are drawn as blue lines
  se = {'linestyle', '-', 'color', 'b'};

  % faces are cyan, their edges are not drawn
  sf = {'EdgeColor', 'none', 'Facecolor', 'c'};


  %% Process input arguments

  % case of a call without arguments
  if nargin==0
      help drawGraph;
      return;
  end

  % ---------------------------------------------------------------
  % First extract the graph structure

  var = varargin{1};
  if iscell(var)
      % graph is stored as a cell array: first cell is nodes, second one is
      % edges, and third is faces
      n = var{1};
      if length(var)>1
          e = var{2};
      end
      if length(var)>2
          f = var{3};
      end
      varargin(1) = [];
  elseif isstruct(var)
      % graph is stored as a structure, with fields 'nodes', 'edges', and
      % eventually 'faces'.
      n = var.nodes;
      e = var.edges;
      if isfield(var, 'faces')
          f = var.faces;
      end
      varargin(1) = [];
  else
      % graph is stored as set of variables: nodes, edges, and eventually
      % faces
      n = varargin{1};
      e = varargin{2};
      varargin(1:2) = [];

      if ~isempty(varargin)
          var = varargin{1};
          if isnumeric(var)
              % faces are stored in a numeric array of indices
              f = var;
              varargin(1) = [];
          elseif iscell(var)
              if ~ischar(var{1})
                  % faces are stored in a cell array, each cell containing a
                  % row vector of indices
                  f = var;
                  varargin(1) = [];
              end
          end
      end
  end

  % extract drawing style

  if ~isempty(varargin)
      sn = concatArguments(sn, varargin{1});
  end

  if length(varargin)>1
      se = concatArguments(se, varargin{2});
  end

  if length(varargin)>2
      sf = concatArguments(sf, varargin{3});
  end



  %% main drawing processing

  hold on;

  if size(n, 2)==2
      % Draw a 2 dimensional graph ----------------------

      % Draw faces of the graph ------------
      if ~strcmp(sf{1}, 'none') && ~isempty(f)
          if iscell(f)
              % each face is contained in a cell.
              hf = zeros(size(f));
              for fi=1:length(f)
                  hf(fi) = patch('Faces', f{fi}, 'Vertices', n, sf{:});
              end
          else
              % process faces as an Nf*N array. Nf is the number of faces,
              % and all faces have the same number of vertices (nodes).
              hf = patch('Faces', f, 'Vertices', n, sf{:});
          end
      end

      % Draw 2D Edges ----------------------
      if ~strcmp(se{1}, 'none') && size(e, 1)>0
          he = plot([n(e(:,1),1) n(e(:,2),1)]', [n(e(:,1),2) n(e(:,2),2)]', se{:});
      end

      % Draw 2D nodes ----------------------
      if ~strcmp(sn{1}, 'none')
          hn = plot(n(:,1), n(:,2), sn{:});
      end


  elseif size(n, 2)==3
      % Draw a 3 dimensional graph ----------------------

      % use a zbuffer to avoid display pbms.
      set(gcf, 'renderer', 'zbuffer');

      % Draw 3D Faces ----------------------
      if ~strcmp(sf{1}, 'none')
          if iscell(f)
              % each face is contained in a cell.
              hf = zeros(size(f));
              for fi=1:length(f)
                  hf(fi) = patch('Faces', f{fi}, 'Vertices', n, sf{:});
              end
          else
              % process faces as an Nf*N array. Nf i the number of faces,
              % and all faces have the same number of vertices (nodes).
              hf = patch('Faces', f, 'Vertices', n, sf{:});
          end
      end

      % Draw 3D edges ----------------------
      if ~strcmp(se{1}, 'none') && size(e, 1)>0
  %         he = plot3(...
  %             [n(e(:,1),1) n(e(:,2),1)]', ...
  %             [n(e(:,1),2) n(e(:,2),2)]', ...
  %             [n(e(:,1),3) n(e(:,2),3)]', ...
  %             se{:});
          he = line(...
              [n(e(:,1),1) n(e(:,2),1)]', ...
              [n(e(:,1),2) n(e(:,2),2)]', ...
              [n(e(:,1),3) n(e(:,2),3)]', ...
              se{:});
      end

      % Draw 3D nodes ----------------------
      if ~strcmp(sn{1}, 'none');
          hn = plot3(n(:,1), n(:,2), n(:,3), sn{:});
      end

  end


  %% Format output arguments

  % return handle to edges
  if nargout==1
      varargout{1} = he;
  end

  % return handle to nodes and edges
  if nargout==2
      varargout{1} = hn;
      varargout{2} = he;
  end

  % return handle to nodes, edges and faces
  if nargout==3
      varargout{1} = hn;
      varargout{2} = he;
      varargout{3} = hf;
  end



endfunction

function res = concatArguments(in1, in2)
  % in1 is a cell array already initialized
  % in2 is an argument that can be:
  %   - empty
  %   - the string 'none'
  %   - another cell array

  if isempty(in2)
      res = in1;
      return;
  end

  if ischar(in2)
      if strcmp('none', in2)
          res = {'none'};
          return;
      end
  end

  if iscell(in1)
      res = [in1(:)' in2(:)'];
  else
      res = [{in1} in2(:)];
  end

endfunction
