package PIC::Vis::Algebra::Prime::50Million;

use PerlLib::SwissArmyKnife;

use POSIX;

use Class::MethodMaker
  new_with_init => 'new',
  get_set       =>
  [

   qw / Loaded /

  ];

sub init {
  my ($self,%args) = @_;
  $self->Loaded({});
}

sub GetIthPrime {
  my ($self,%args) = @_;
  my $i = $args{I};

  if ($i >= 0 and $i <= 50000000) {
    my $index = int($i / 1000000) + 1;
    my $remainder = $i % 1000000;
    # print $index."\n";
    if (! exists $self->Loaded->{$index}) {
      $self->Loaded->{$index} = $self->ProcessPrimeNumberZip
	(List => "/var/lib/myfrdcsa/codebases/internal/picform/data/prime/50-million/primes.utm.edu/lists/small/millions/primes$index.zip");
    }
    return $self->Loaded->{$index}->[$remainder];
  } else {
    print "Out of range!\n";
  }
}

sub ProcessPrimeNumberZip {
  my ($self,%args) = @_;
  my $file = $args{List};
  my $c = `zcat $file | tail -n +3`;
  return [split /[^0-9]+/, $c];
}

sub GetPrimeIndex {
  my ($self,%args) = @_;
  $self->GetPrimeIndexNewtonsMethod(%args);
}

sub GetPrimeIndexNewtonsMethod {
  my ($self,%args) = @_;
  my $prime = $args{Prime};
  if ($args{VerifyPrime}) {
    # FIXME: implement later, by verifying factor($prime) has a length
    # of exactly 1
  }

  # now figure out where in the index it is, can do this either by
  # calculating a large index or iterating with newton's method or
  # something, to locate it
  my $previousi = 0;
  my $upperbound = -1;
  my $lowerbound = 0;
  my $multiplier = 3;
  my $i = 1;
  do {
    $lowerbound = floor($i / $multiplier);
    $resultingprime = $self->GetIthPrime(I => $i);
    # print Dumper({ResultingPrime => $resultingprime});
    $i *= $multiplier;
  } while ($resultingprime < $prime);
  $upperbound = $i = ceil($i / $multiplier);

  my $jump;
  do {
    $resultingprime = $self->GetIthPrime(I => $i);
    # print Dumper
    #   ({
    # 	P => $prime,
    # 	R => $resultingprime,
    # 	U => $upperbound,
    # 	L => $lowerbound,
    # 	I => $i,
    # 	J => $jump,
    #    });
    $jump = int(($upperbound - $lowerbound) * (($multiplier - 1) / $multiplier));
    if ($resultingprime > $prime) {
      $upperbound = $i;
      $i -= $jump;
    } elsif ($resultingprime == $prime) {
      return $i;
    } else {
      $lowerbound = $i;
      $i += $jump;
    }
  } while ($resultingprime != $prime);
  return $i;
}

sub GetPrimeIndexCreatingInverseTable {
  my ($self,%args) = @_;
  my $prime = $args{Prime};
  if ($args{VerifyPrime}) {
    # FIXME: implement later, by verifying factor($prime) has a length
    # of exactly 1
  }
  # FIXME: implement
}

1;
