package Bio::EnsEMBL::VRenderer;
use strict;
use warnings;
no warnings 'uninitialized';

sub new {
  my ($class, $config, $container, $glyphsets_ref) = @_;

  my $self = {
    'glyphsets' => $glyphsets_ref,
    'canvas'    => undef,
    'colourmap' => $config->colourmap(),
    'config'    => $config,
    'container' => $container
  };
  bless($self, $class);
  $self->render();
  return $self;
}

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

  my $config = $self->{'config'};

  my $im_width  = $config->get_parameter('max_width');
  my $im_height = $config->get_parameter('max_height');

  ########## create a fresh canvas
  if($self->can('init_canvas')) {
    $self->init_canvas($config, $im_width, $im_height);
  }

  for my $glyphset (@{$self->{'glyphsets'}}) {
    ########## loop through everything and draw it
    for my $glyph ($glyphset->glyphs()) {
      my $method = $self->method($glyph);
      if($self->can($method)) {
        $self->$method($glyph);
      } else {
        print STDERR qq(Bio::EnsEMBL::Renderer::render: Do not know how to $method\n);
      }
    }

  }

  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'}{$_}});
        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;
  for my $layer ( sort { $a<=>$b } keys %layers ) {
    #########
    # loop through everything and draw it
    #
    for ( @{$layers{$layer}} ) {
      my $method = $M{$_} ||= $self->method($_);
      if($self->can($method)) {
        $self->$method($_);
      } else {
        print STDERR qq(Sanger::Graphics::Renderer::render: Do not know how to $method\n);
      }
    }
  }
  ########## 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_Composite {
  my ($self, $glyph) = @_;

  for my $subglyph (@{$glyph->{'composite'}}) {
    my $method = $self->method($subglyph);

    if($self->can($method)) {
      $self->$method($subglyph);
    } else {
      print STDERR qq(Bio::EnsEMBL::VRenderer::render_Composite: Do not know how to $method\n);
    }
  }
}

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

1;