#/usr/bin/perl -w
# FBITS Day Calculator

# 1: find (day of year) of year's first 1st-quarter moon, mod 12, - 1
# 2: find day that is 12 days after <!--each--> the first full moon in that month
# 3: add and subtract 42pi days from the first date above, wrapping around the end of the year

# options: [year] | [start]-[end] |
# year limit: must be between 1970 and 2037, inclusive

#*** todo:  handle blue/no full moons correctly

use strict;
use Date::Calc qw/:all/;
use Astro::MoonPhase;
use DBI;

my $input = shift || '';
print "FBITS Day occurs on $1/$2 in the year(s) ", join(', ',when_fbits($1,$2)), ".\n" and exit if $input =~ /(\d+)\/(\d+)/;
print map {(join("\t",@{$_}),"\n")} range_fbits($1,$2) and exit if $input =~ /(\d+)-(\d+)/;
is_fbits() if $input eq '--today';
$input eq '' ? print next_fbits() : print map {($_,"\n")} year_fbits($input);

sub is_fbits {
   my ($year, $month, $day) = Today();
   {
      if (next_fbits() eq "$month/$day/$year") {
         exit 0;
      } else {
         exit 1;
      }
   }
}

sub next_fbits {
   my ($year, $month, $day) = Today();
   {
      for (fbits($year)) {
         return join('/', @{$_}[1,2,0]) if $_->[1] >= $month and $_->[2] > $day;
      }
      $year++; $month = $day = 0; redo;
   }
}

sub when_fbits {
   my ($year, $month, $day) = (1970, @_);
   my @blah;
   {
      for (fbits($year)) {
         push @blah, $year if $_->[1] == $month and $_->[2] == $day;
      }
      $year++, redo if $year < 2037;
   }
   return @blah;
}

sub year_fbits {
   return map {join '/', @{$_}[1,2,0]} fbits(shift);
}

sub range_fbits {
   my ($start, $end) = @_;
   return map {["$_:",year_fbits($_)]} ($start..$end);
}

sub fbits {
   my ($year) = @_;
   my $q1_day = Day_of_Year(find_phase_after($year,1,1,.25));

   my $month = $q1_day % 12 - 1;
   $month += 12 if $month < 1;

   my @full_date = find_phase_after($year,$month,1,.5);
   return unless $full_date[1] == $month;

   my @fbits;
   $fbits[0] = [ $year, (Add_Delta_Days(@full_date, ($year % 2 ? 12 : 19)))[1,2] ];
   $fbits[1] = [ $year, (Add_Delta_Days(@{$fbits[0]}, -(42*3.14159265358979323)))[1,2] ];
   $fbits[2] = [ $year, (Add_Delta_Days(@{$fbits[0]}, (42*3.14159265358979323)))[1,2] ];

   return (sort {Date_to_Days(@{$a}) <=> Date_to_Days(@{$b})} (@fbits));
}

sub find_phase_after {
   my ($year, $month, $day, $phase) = @_;
   my $secs = to_absolute($year,$month,$day);

   return unless grep($phase, 0,.25,.5,.75,1);

   my @phases;
   {
   @phases = phasehunt($secs);
   $secs = $phases[4]+86400, redo unless $phases[$phase*4] >= $secs;
   }

   my @normal = (localtime($phases[$phase*4]))[3..5];
   return ($normal[2]+1900,$normal[1]+1,$normal[0]);
}

sub to_absolute {
   my ($year, $month, $day) = @_;
   return Delta_Days(1970,1,1, $year,$month,$day)*86400 #+ 43200;
}

