package GIFgraph::EvenlySpaced;

use strict;

use MRP::BaseClass;

use vars qw(@ISA %fields $AUTOLOAD $VERSION);

$VERSION = 1.0;

sub AUTOLOAD {
  my $thing = shift;
  my ($package, $function) = $AUTOLOAD =~ m/^(.*)::([^:]+)$/;
  return if $function eq 'DESTROY';

  if(ref($thing)) {
    return $thing->_DelegateGraph->$function(@_);
  }
#  my $super = join '::', 'SUPER', $function;
#  return $thing->$super(@_);
  die "Could not find $AUTOLOAD via $thing ";
}

sub new {
  my $class = shift;
  my $graph = shift;
  my $self = new MRP::BaseClass;
  $self->rebless($class);
  $self->_DelegateGraph($graph);
  return $self;
}

sub plot {
  my ($self, $data) = @_;
  my $fudge = $self->fudge;
  my @processed;

  my @x = @{$data->[0]};
  my @distances;
  my ($min, $max) = ($x[0], $x[$#x]);
  my $len = $max-$min;
  foreach my $i (1 .. $#x) {
    $distances[$i-1] = $x[$i] - $x[$i-1];
  }
  my @sdist = sort { $a<=>$b } @distances;

  my $sd = shift @sdist;
  while(@sdist) {
    my $nd = shift @sdist;
    my $diff = $nd/$sd;
    $diff = $diff - int($diff);
    $diff = 1-$diff if $diff > 0.5;
    next if $diff < $fudge;
    my $rat = $nd/$sd;
    my $continue = 1;
    for(my $ax = 2; $continue; $ax++) {
      my $yx = $ax*$rat;
      if($yx !~ /\./) {
	$sd = $nd/$yx;
	$continue = 0;
      }
    }
  }

  my $lowest = shift @x;
  my $column = 0;
  for(my $newX = $min; ($newX-$sd) < $max; $newX+=$sd) {
    if($newX >= $lowest) {
      foreach my $series (0 .. $#$data) {
	push @{$processed[$series]}, $data->[$series][$column];
      }
      $column++;
      $lowest = shift @x;
    } else {
      foreach my $series (0 .. $#$data) {
	push @{$processed[$series]}, undef;
      }
    }
  }

  local $^W = undef;
  return $self->_DelegateGraph->plot(\@processed);
}

sub isa {
  my ($thing, $type) = @_;
  return $thing->_DelegateGraph->isa($type) || $thing->SUPER::isa($type);
}

BEGIN {
  @ISA = qw(MRP::BaseClass);
  %fields = (
	     fudge => 0.1,
	     _DelegateGraph => undef,
	    );
  GIFgraph::EvenlySpaced->check4Clashes;
}

$VERSION;

__END__

=head1 NAME

GIFgraph::EvenlySpaced - spaces the data points evenly

=head1 DESCRIPTION

This module wraps a GIFgraph object so that the data points become
numericaly spaced (aproximately).

=head1 SYNOPSIS

Wrapps a GIFgraph object (probably a GIFgraph::lines) so that the x
values are spaced numericaly. Use exactly as your GIFgraph object. Due
to a problem I had with AUTOLOAD, it must be the outer wrapper class.

=head1 Use

  $graph = new GIFgraph::lines(400,300);
  $es = new GIFgraph::EvenlySpaced($graph);

or

  $graph = new GIFgraph::lines(400,300);
  $withmap = new GIFgraph::WithMap($graph);
  $es = new GIFgraph::EvenlySpaced($withmap);

or even

  $es = new GIFgraph::EvenlySpaced(new GIFgraph::WithMap(new GIFgraph::lines(400,300)));

etc. etc. etc.

=head1 Functions

=over

=item new

Returns a new GIFgraph::EvenlySpaced object

  $es = new GIFgraph::EvenlySpaced($parentGraph);

where $parentGraph is any object that behaves like a GIFgraph::lines
type object such as a GIFgraph::WithMap.

=item plot

This function is overridden to space the data numericaly along the
x-axis.

=back

=head1 Fields

=over

=item fudge

This is a fudge factor used in checking whether one number roughly
devides into another. It defaults to 0.1 but if it is obviously doing
silly things then change it. Good luck - I don't realy know how it
works.

=back

=head1 Guts

This module uses MRP::BaseClass to implement member access functions.

To make the 'parent' object behave as if it the super class I have
done some magic with AUTOLOAD. This has produced the restriction that
you can not wrap an EvenlySpaced object inside another - such as
WithMap - that also uses magic.

@ISA does not include the parent type as it is not known. The isa()
method is overridden to account for this.

=head1 AUTHOR

Matthew Pocock mrp@sanger.ac.uk
