The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Copyright 2008, 2009 Kevin Ryde

# This file is part of Chart.
#
# Chart is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3, or (at your option) any later version.
#
# Chart is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with Chart.  If not, see <http://www.gnu.org/licenses/>.

package App::Chart::Series::AddSub;
use 5.008;
use strict;
use warnings;
use Carp;
use List::Util qw(min max);

use App::Chart::Database;
use App::Chart::TZ;
use base 'App::Chart::Series';

use constant DEBUG => 0;

sub new {
  if (DEBUG) { require Data::Dumper;
               print "AddSub new ",Data::Dumper::Dumper(\@_); }
  my ($class, $x, $y, @more) = @_;
  $y->isa('App::Chart::Series')
    or croak 'Can only add two App::Chart::Series objects';

  my $x_timebase = $x->timebase;
  my $y_timebase = $y->timebase;
  if (ref $x_timebase ne ref $y_timebase) {
    croak 'Can only add Series with same timebase scale';
  }

  my $timebase;
  if ($x_timebase->to_iso(0) ge $y_timebase->to_iso(0)) {
    $timebase = $x_timebase;
  } else {
    $timebase = $y_timebase;
  }

  my $x_offset = $timebase->convert_from_floor ($x_timebase, 0);
  my $y_offset = $timebase->convert_from_floor ($y_timebase, 0);

  my $hi = min ($timebase->convert_from_floor ($x_timebase, $x->hi),
                $timebase->convert_from_floor ($y_timebase, $y->hi));

  return $class->SUPER::new
    (timebase => $timebase,
     hi       => $hi,
     parent   => $x,
     parent2  => $y,
     x_offset => $x_offset,
     y_offset => $y_offset,
     arrays   => { map {; $_ => [] } keys %{$x->{'arrays'}} },
  @more);
}

sub fill_part {
  my ($self, $lo, $hi) = @_;

  my $xs = $self->{'parent'};
  my $ys = $self->{'parent2'};
  my $negate   = $self->{'negate'};
  my $x_offset = $self->{'x_offset'};
  my $y_offset = $self->{'y_offset'};

  $xs->fill ($lo - $x_offset, $hi - $x_offset);
  $ys->fill ($lo - $y_offset, $hi - $y_offset);

  my $arrays = $self->{'arrays'};
  while (my ($aname, $sa) = each %$arrays) {
    my $xa = $xs->array($aname);
    my $ya = $ys->array($aname);

    my $hi = min ($hi, $#$xa - $x_offset, $#$ya - $x_offset);
    if ($#$sa < $hi) { $#$sa = $hi; }  # pre-extend

    foreach my $i ($lo .. $hi) {
      my $x = $xa->[$i - $x_offset];
      if (defined $x) {
        my $y = $ya->[$i - $y_offset];
        if (defined $y) {
          $sa->[$i] = $x + ($negate ? - $y : $y);
          if (DEBUG) {print "$i  $x ",($negate ? '-' : '+')," $y $sa->[$i]\n";}
        }
      }
    }
  }
}

1;
__END__

=head1 NAME

App::Chart::Series::AddSub -- ...

=head1 SYNOPSIS

 use App::Chart::Series::AddSub;
 my $adj_series = App::Chart::Series::AddSub->new ()

=head1 DESCRIPTION

...

=head1 SEE ALSO

L<App::Chart::Series::Database>

=cut