#########
# Author: rmp@sanger.ac.uk
# Maintainer: webmaster@sanger.ac.uk
# Created: 2001
#
package Sanger::Graphics::Renderer;
use Sanger::Graphics::Glyph::Poly;
use Sanger::Graphics::Glyph::Rect;
use strict;
use Time::HiRes qw(time);

our $patterns = {
# south-west - north-east thin line
  'hatch_ne'    => {
    'size' => [ 4, 4 ],
    'lines' => [
      [ 0,3,3,0 ]
    ]
  },
# south-east - north-west thin line
  'hatch_nw'    => {
    'size' => [ 4, 4 ],
    'lines' => [
      [ 0,0,3,3 ]
    ]
  },
# vertical 1px lines
  'hatch_vert'  => {
    'size' => [ 4, 4 ],
    'lines' => [
      [ 0,0,0,3 ],
      [ 2,0,2,3 ]
    ]
  },
# hotizontal 1px lines
  'hatch_hori'  => {
    'size' => [ 4, 4 ],
    'lines' => [
      [ 0,0,3,0 ],
      [ 0,2,3,2 ]
     ]
  },
# sw-ne (school tie!) v-thick lines
  'hatch_thick' => {
    'size' => [ 12, 12 ],
    'polys' => [
      [ [ 0,11],[ 5,11],[11, 5],[11, 0] ],
      [ [ 0,0 ],[ 0, 4],[ 4, 0]         ],
    ],
  },
  'hatch_thick_sw' => {
    'size' => [ 12, 12 ],
    'polys' => [
      [ [ 11,11],[ 6,11],[0, 5],[0, 0] ],
      [ [ 11,0 ],[ 11, 4],[ 7, 0]         ],
    ],
  },

  'pin_ne'   => { 'size' => [8,8], 'lines' => [[0,7,7,0]]} ,
  'pin_sw'   => { 'size' => [8,8], 'lines' => [[0,0,7,7]]} ,
  'pin_hori' => { 'size' => [8,8], 'lines' => [[0,2,7,2],[0,6,7,6]]} ,
  'pin_vert' => { 'size' => [8,8], 'lines' => [[2,0,2,7],[6,0,6,7]]} ,
  'hash'     => { 'size' => [4,4], 'lines' => [[0,2,3,2],[2,0,2,3]]} ,
  'check'    => { 'size' => [6,6], 'lines' => [[0,0,5,5],[0,5,5,0]]} ,
};

sub new {
  my ($class, $config, $extra_spacing, $glyphsets_ref) = @_;
  my $self = {
    'glyphsets' => $glyphsets_ref,
    'canvas'    => undef,
    'colourmap' => $config->colourmap(),
    'config'    => $config,
    'extra_spacing' => $extra_spacing,
    'spacing'   => $config->get_parameter( 'spacing')||2,
    'margin'    => $config->get_parameter( 'margin')||5,
		'sf'        => $config->get_parameter( 'sf' )||1
  };
  bless($self, $class);
  $self->render();
  return $self;
}

sub config {
  my ($self, $config) = @_;
  $self->{'config'}   = $config if($config);
  return $self->{'config'};
}

sub render {
  my ($self) = @_;
  my $config = $self->{'config'};
  #########
  # now set all our labels up with scaled negative coords
  # and while we're looping, tot up the image height
  #
  my $spacing   = $self->{'spacing'};
  my $im_height = $self->{'margin'} * 2 - $spacing;
  for my $glyphset (@{$self->{'glyphsets'}}) {
    next if (scalar @{$glyphset->{'glyphs'}} == 0 || 
             scalar @{$glyphset->{'glyphs'}} == 1 && ref($glyphset->{'glyphs'}[0])=~/Diagnostic/ );
    my $fntheight = (defined $glyphset->label())?$config->texthelper->height($glyphset->label->font()):0;
    my $gstheight = $glyphset->height();
    if($gstheight > $fntheight) {
      $im_height += $gstheight + $spacing;
    } else {
      $im_height += $fntheight + $spacing;
    }
  }
  $im_height += $self->{'extra_spacing'};
  $config->image_height( $im_height );
  my $im_width = $config->image_width();
  #########
  # create a fresh canvas
  #
  if($self->can('init_canvas')) {
    $self->init_canvas($config, $im_width, $im_height );
  }
  my %tags;
  my %layers = ();
  for my $glyphset (@{$self->{'glyphsets'}}) {
    foreach( keys %{$glyphset->{'tags'}}) {
      if($tags{$_}) {
	# my @points = ( @{$tags{$_}}, @{$glyphset->{'tags'}{$_}} );
        my $COL   = undef;
        my $FILL  = undef;
        my $Z     = undef;
	my @points = map { 
          $COL  = defined($COL)  ? $COL  : $_->{'col'};
          $FILL = defined($FILL) ? $FILL : ($_->{'style'} && $_->{'style'} eq 'fill'); 
          $Z    = defined($Z)    ? $Z    : $_->{'z'};
	  (
	   $_->{'glyph'}->pixelx + $_->{'x'} * $_->{'glyph'}->pixelwidth,
	   $_->{'glyph'}->pixely + $_->{'y'} * $_->{'glyph'}->pixelheight
	  ) } (@{$tags{$_}}, @{$glyphset->{'tags'}{$_}});
#     warn Data::Dumper::Dumper($tags{$_});
#	warn Data::Dumper::Dumper(\@points);
	my $first = $glyphset->{'tags'}{$_}[0];
        my $PAR = { 
          'absolutex'    => 1,
          'absolutewidth'=> 1,
          'absolutey'    => 1,
        };
	my $glyph;
        $PAR->{'bordercolour'} = $COL if defined $COL;
	$PAR->{'href'}   = $tags{$_}[0]->{'href'};
	$PAR->{'alt'}    = $tags{$_}[0]->{'alt'};
	$PAR->{'id'}     = $tags{$_}[0]->{'id'};
        $PAR->{'colour'} = $COL if($FILL);
# 794 5 123 5 123 421 794 421
        if( @points == 4 &&
          ($points[0] == $points[2] || $points[1] == $points[3])
        ) {
          $PAR->{'pixelx'}      = $points[0] < $points[2] ? $points[0] : $points[2];
          $PAR->{'pixely'}      = $points[1] < $points[3] ? $points[1] : $points[3];
          $PAR->{'pixelwidth'}  = $points[0] + $points[2] - 2 * $PAR->{'pixelx'};
          $PAR->{'pixelheight'} = $points[1] + $points[3] - 2 * $PAR->{'pixely'};
	  $glyph = $COL ? Sanger::Graphics::Glyph::Rect->new($PAR) : Sanger::Graphics::Glyph::Space->new($PAR);
        } elsif( @points == 8 &&
	    $points[0] == $points[6] &&
	    $points[1] == $points[3] &&
	    $points[2] == $points[4] &&
	    $points[5] == $points[7]
	) {
	  $PAR->{'pixelx'}      = $points[0] < $points[2] ? $points[0] : $points[2];
	  $PAR->{'pixely'}      = $points[1] < $points[5] ? $points[1] : $points[5];
	  $PAR->{'pixelwidth'}  = $points[0] + $points[2] - 2 * $PAR->{'pixelx'};
	  $PAR->{'pixelheight'} = $points[1] + $points[5] - 2 * $PAR->{'pixely'};
	  $glyph = $COL ? Sanger::Graphics::Glyph::Rect->new($PAR) : Sanger::Graphics::Glyph::Space->new($PAR);
	} else {
	  $PAR->{'pixelpoints'}  = [ @points ];
	  $glyph = Sanger::Graphics::Glyph::Poly->new($PAR);
	}

	push @{$layers{defined $Z ? $Z : -1 }}, $glyph;
	delete $tags{$_};
      } else {
	$tags{$_} = $glyphset->{'tags'}{$_}
      }       
    }
    foreach( @{$glyphset->{'glyphs'}} ) {
      push @{$layers{$_->{'z'}||0}}, $_;
    }
  }

my %M;
my $Ta;
  for my $layer ( sort { $a<=>$b } keys %layers ) {
    #########
    # loop through everything and draw it
    #
    for ( @{$layers{$layer}} ) {
      my $method = $M{$_} ||= $self->method($_);
my $T = time();
      if($self->can($method)) {
	$self->$method($_,$Ta);
      } else {
	print STDERR qq(Sanger::Graphics::Renderer::render: Do not know how to $method\n);
      }
      $Ta->{$method} ||= [];
      $Ta->{$method}[0] += time()-$T;
      $Ta->{$method}[1] ++;   
    }
  }
  #########
  # the last thing we do in the render process is add a frame
  # so that it appears on the top of everything else...
  $self->add_canvas_frame($config, $im_width, $im_height);
}

sub canvas {
  my ($self, $canvas) = @_;
  $self->{'canvas'} = $canvas if(defined $canvas);
  return $self->{'canvas'};
}

sub method {
  my ($self, $glyph) = @_;
  my ($suffix) = ref($glyph) =~ /.*::(.*)/;
  return qq(render_$suffix);
}

sub render_Diagnostic { 1; }
sub render_Composite {
  my ($self, $glyph,$Ta) = @_;
  for my $subglyph (@{$glyph->{'composite'}}) {
    my $method = $self->method($subglyph);
my $T = time();
    if($self->can($method)) {
      $self->$method($subglyph,$Ta);
    } else {
      print STDERR qq(Sanger::Graphics::Renderer::render_Composite: Do not know how to $method\n);
    }
      $Ta->{$method} ||= [];
      $Ta->{$method}[0] += time()-$T;
      $Ta->{$method}[1] ++;   
  }
}

#########
# empty stub for Blank spacer objects with no rendering at all
#
sub render_Space {
}

#########
# placeholder for renderers which can't import sprites
#
sub render_Sprite {
  my $self = shift;
  return $self->render_Rect(@_);
}

1;