#!/usr/bin/perl -w

use Data::Dumper;
use Math::Factoring qw(factor);

use PIC::Vis::Algebra::Prime::50Million;
my $million50 = PIC::Vis::Algebra::Prime::50Million->new();

foreach my $n (2..999) {
  print "-----------------------\n";
  my $solidnumbernotationds = GetSolidNumberNotationDS(N => $n);
  print Dumper({S => $solidnumbernotationds});
  print $n.' - '.PrintSolidNumberNotation(DS => $solidnumbernotationds)."\n";
  if (! scalar @{$solidnumbernotationds->{D}}) {
    my $compressedsolidnumbernotationds = GetCompressedSolidNumberNotationDS(DS => $solidnumbernotationds);
    print Dumper({C => $compressedsolidnumbernotationds});
    print "\t".PrintCompressedSolidNumberNotationDS(DS => $compressedsolidnumbernotationds)."\n\n";
  }
}

sub GetSolidNumberNotationDS {
  my (%args) = @_;
  my $n = $args{N};
  my @duplicatepile;
  my @solidnumberfactors;
  my $previousfactor = undef;
  foreach my $factor (sort {$a <=> $b} factor($n)) {
    my $skip;
    if (defined $previousfactor) {
      if ($factor eq $previousfactor) {
	push @duplicatepile, $factor;
	$skip = 1;
      }
    }
    unless ($skip) {
      $previousfactor = $factor;
      push @solidnumberfactors, $factor;
    }
  }

  my $total = $solidnumberfactors[0];
  foreach my $i (1..$#solidnumberfactors) {
    $total *= $solidnumberfactors[$i];
  }
  return
    {
     D => \@duplicatepile,
     F => \@solidnumberfactors,
     T => $total,
    };

}

sub PrintSolidNumberNotation {
  my (%args) = @_;
  my $ds = $args{DS};
  my @duplicatepile = @{$ds->{D}};
  my $total = $ds->{T};
  return join('.',@duplicatepile).'.'.$total
}


sub GetCompressedSolidNumberNotationDS {
  my (%args) = @_; 
  my $ds = $args{DS};
  die Dumper({Error => "Not a solid number", DS => $ds}) if scalar @{$ds->{D}};
  my @bitvector;
  foreach my $factor (@{$ds->{F}}) {
    my $bit = $million50->GetPrimeIndex(Prime => $factor);
    print "$bit\n";
    $bitvector[$bit - 1] = 1;
  }
  foreach my $i (0..$#bitvector) {
    $bitvector[$i] ||= 0;
  }
  my $binarynumber = join('',(reverse @bitvector));
  $decimalnumber = eval 'my $decimalnumber = 0b'.$binarynumber;
  return {
	  B => $binarynumber,
	  D => $decimalnumber,
	 };
}

sub PrintCompressedSolidNumberNotationDS {
  my (%args) = @_;
  return $args{DS}->{D};
}
