switch day diff calculation to epoch based so that "N hours short of M days" becomes...
[engit/Iron-Munger.git] / lib / IronMunger / Calculate.pm
index 76aa983..236953f 100644 (file)
@@ -2,16 +2,40 @@ package IronMunger::Calculate;
 
 use strict;
 use warnings;
+use List::Util qw(min);
+use autobox;
 use autobox::DateTime::Duration;
 use signatures;
 
+use Sub::Exporter -setup => {
+  exports => [
+    qw(successful_sequential_posts days_remaining_to_post level_for_post_count)
+  ]
+};
+
+sub day_diff ($dt1, $dt2) {
+  $dt1 = $dt1->at if $dt1->isa('IronMunger::Post');
+  $dt2 = $dt2->at if $dt2->isa('IronMunger::Post');
+  my $seconds = $dt2->epoch - $dt1->epoch;
+  $seconds = -$seconds if $seconds < 0;
+  int($seconds / 86400);
+  #$dt1->delta_days($dt2)->delta_days;
+}
+
 sub check_post_gap ($aperture, $days, @posts) {
-  return @posts if @posts <= $aperture;
+  return scalar @posts if @posts <= $aperture;
   my @next_post = splice(@posts, 0, $aperture);
-  return 0 if DateTime->now - $next_post[-1]->at > $days->days;
+  if (day_diff(DateTime->now, $next_post[-1]) > $days) {
+    while (@next_post && day_diff(DateTime->now, $next_post[-1]) > $days) {
+      pop @next_post;
+    }
+    return scalar(@next_post);
+  }
   my $success = $aperture;
   foreach my $post (@posts) {
-    return $success if $next_post[0]->at - $post->at > $days->days;
+    if (day_diff($next_post[0],$post) > $days) {
+      return $success;
+    }
     $success++;
     shift(@next_post);
     push(@next_post, $post);
@@ -20,15 +44,34 @@ sub check_post_gap ($aperture, $days, @posts) {
 }
 
 sub check_time_remaining ($aperture, $days, @posts) {
-  my $cand = (@posts > $aperture ? $posts[$aperture - 1] : $posts[-1]);
-  return $days->days - (DateTime->now - $cand->at)->in_units('days');
+  my @consider = @posts > $aperture ? @posts[0 .. $aperture - 1] : @posts;
+  foreach my $cand (reverse @consider) {
+    my $days_ago = day_diff(DateTime->now, $cand);
+    return $days - $days_ago if $days > $days_ago;
+  }
+  return $days;
 }
 
-sub successful_sequential_posts (@posts) {
-  return max(
-    check_post_gap(1, 10, @posts), # 10 days between posts
-    check_post_gap(3, 32, @posts), # 4 posts every 32 days
+sub check_both ($check, @posts) {
+  return min(
+    $check->(1, 10, @posts), # 10 days between posts
+    $check->(4, 32, @posts), # 4 posts within any given 32 days
   );
 }
 
+sub successful_sequential_posts (@posts) {
+  return check_both(\&check_post_gap, @posts);
+}
+
+sub days_remaining_to_post (@posts) {
+  return check_both(\&check_time_remaining, @posts);
+}
+
+sub level_for_post_count($count) {
+  return 'paper' if $count < 4;
+  return 'stone' if $count < 12;
+  return 'bronze' if $count < 36;
+  return 'iron';
+}
+
 1;