#############################################################################
# output the graph as Scalable Vector Graphics
#
# (c) by Tels 2004-2005.
#############################################################################

package Graph::Simple::As_svg;

use vars qw/$VERSION/;

$VERSION = '0.01';

#############################################################################
#############################################################################

package Graph::Simple;

use strict;

sub _as_svg
  {
  my ($self) = @_;

  # convert the graph to a textual representation

  $self->layout() unless defined $self->{score};

  my ($rows,$cols,$max_x,$max_y,$cells) = $self->_prepare_layout();

  my $txt = 
     "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"$max_x em\" height=\"$max_y em\" x=\"0\" y=\"0\">"
    ."\n<!-- Generated by Graph::Simple $Graph::Simple::VERSION" .
	    " at " . scalar localtime() . "-->\n";

  # generate the class attributes first
  # XXX TODO
  ## output groups first, with their nodes
  #foreach my $gn (sort keys %{$self->{groups}})
  #  {
  #  my $group = $self->{groups}->{$gn};
  #  $txt .= $group->as_txt();		# marks nodes as processed if nec.
  #  $count++;
  #  }

  foreach my $n (@$cells)
    {
    # exclude filler cells
    if ($n->{w} != 0 && $n->{h} != 0)
      {
      $txt .= $n->as_svg() . "\n";	# output node
      }
    }

  $txt . "</svg>";			# finish
  }
 
1;

=pod

=head1 NAME

Graph::Simple::As_svg - Output graph as Scalable Vector Graphics (SVG)

=head1 SYNOPSIS

	use Graph::Simple;
	
	my $graph = Graph::Simple->new();

	my $bonn = Graph::Simple::Node->new(
		name => 'Bonn',
	);
	my $berlin = Graph::Simple::Node->new(
		name => 'Berlin',
	);

	$graph->add_edge ($bonn, $berlin);

	print $graph->as_svg();

	# prints something like:


=head1 DESCRIPTION

C<Graph::Simple::As_svg> contains just the code for converting a
L<Graph::Simple|Graph::Simple> object to a SVG text.

=head1 EXPORT

Exports nothing.

=head1 SEE ALSO

L<Graph::Simple>.

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms of the GPL. See the LICENSE file for information.

=head1 AUTHOR

Copyright (C) 2004 - 2005 by Tels L<http://bloodgate.com>

=cut

package Graph::Simple::Node;

sub as_svg
  {
  my $self = shift;

  my $name = $self->{att}->{label}; $name = $self->{name} unless defined $name;

  my $em = 10;		# multiplication factor chars * em = units (pixels)

  # the attributes of the element we will finally output
  my $att = $self->_svg_attributes($em);
  
  my $shape = $att->{shape};				# rect, circle etc

  # set a potential title
  my $title = $self->title();
  $att->{title} = $title if $title ne '';

  my $att_line = '';				# attributes as text (cur line)
  my $att_txt = '';				# attributes as text (all)
  foreach my $e (sort keys %$att)
    {
    $att_line .= " $e=\"$att->{$e}\"";
    if (length($att_line) > 75)
      {
      $att_txt .= "$att_line\n"; $att_line = '';
      }
    }
  $att_txt .= "$att_line";
  $att_txt =~ s/\n\z//;		# avoid a "  >" on last line
 
  my $elem = $name;
  if ($self->isa('Graph::Simple::Edge'))
    {
    $elem = "edge";
    }

  my $svg = "<!-- $elem -->\n<$shape$att_txt>\n"; 
  }

sub _svg_attributes
  {
  # Return a hash with attributes for the node, like "x => 1, y => 1, w => 1, h => 1"
  # Especially usefull for shapes other than boxes.

  my ($self,$em) = @_;

  my $att = {};

  my $shape = $self->attribute('shape') || 'rect';
  $shape =~ s/^(rectangle|box)\z/rect/;			# rectangle, box => rect

  if ($shape eq 'circle')
    {
    $att->{cx} = $self->{x} * $em;
    $att->{cy} = $self->{y} * $em;
    $att->{r} = $self->{w} > $self->{h} ? $self->{w} : $self->{h};
    $att->{r} /= 2;
    $att->{r} *= $em;
    }
  elsif ($shape eq 'ellipse')
    {
    $att->{cx} = $self->{x} * $em;
    $att->{cy} = $self->{y} * $em;
    $att->{rx} = $self->{w} * $em / 2;
    $att->{ry} = $self->{h} * $em / 2;
    }
  elsif ($shape eq 'rounded')
    {
    $shape = 'rect';
    # round corners by 10%
    $att->{ry} = '10%';
    $att->{rx} = '10%';
    }
  else
    {
    # XXX TODO: other shapes than rectangles
    $att->{x} = $self->{x} * $em;
    $att->{y} = $self->{y} * $em;
    $att->{width} = $self->{w} * $em;
    $att->{height} = $self->{h} * $em;
    }
  $att->{shape} = $shape;

  my $border = $self->attribute('border') || '';
  $border =~ s/(solid|dotted|dashed)//g;
  my $border_style = $1 || 'solid';
  $border =~ s/^([\d\.]+(px|em|%))//g;
  $att->{"stroke-width"} = $1 || '1px';
  $border =~ s/\s//g;
  $border = $self->attribute('border-color') || '' if ($border eq '');
  $att->{stroke} = $border if $border ne '';
  
  my $background = $self->attribute('background') || '';
  $att->{fill} = $background if $background ne '';

  $att;
  }

