#!/usr/bin/perl -w
###########################################
# xaday - Mail out a tip every day
# Mike Schilli, 2007 (m@perlmeister.com)
###########################################
use strict;
use Rose::DB::Object::Loader;
use Getopt::Std;
use File::Temp qw(tempfile);
use Sysadm::Install qw(:all);
use Mail::Mailer;

my $RECSEP    = qr/^=head1/;
my $HEAD      = "=head1";
my $MAIL_FROM = 'me@_foo.com';

getopts("d:lepm:f:", \my %opts);

die "usage: $0 -d dbfile ..." 
                           unless $opts{d};

my $loader = Rose::DB::Object::Loader->new(
  db_dsn => "dbi:SQLite:dbname=$opts{d}",
  db_options   => {
    AutoCommit => 1, RaiseError => 1 },
);

$loader->make_classes();

if($opts{e} or $opts{l}) {
  my($fh, $tmpf) = tempfile(UNLINK => 1);
  my $tips = 
         Tip::Manager->get_tips_iterator();
  my $data_before = "";

  while(my $tip = $tips->next()) {
    $data_before .= 
      "$HEAD " .
      $tip->head() . " {" .
      $tip->id() . "}" . "\n\n" .
      $tip->text() .  "\n\n";
    }
    if($opts{l}) {
        print $data_before;
        exit 0;
    }
    blurt($data_before, $tmpf);
    system("$ENV{EDITOR} $tmpf");
    my $data_after = slurp($tmpf);
    die "No change" if 
              $data_before eq $data_after;

    db_update(\$data_after);
}

if($opts{f}) {
    db_update($opts{f});
}

if($opts{m}) {
  my $tips = Tip::Manager->get_tips(
    query => [ "published" => undef],
    sort_by => 'id',
    limit   => 1,
  );
  if(@$tips) {
    $tips->[0]->published(
                        DateTime->today());
    $tips->[0]->update();
    mail($opts{m}, $tips->[0]->head(), 
         $tips->[0]->text());
  } else {
      die "Nothing left to publish";
  }
}

###########################################
sub text2db {
###########################################
  my($text) = @_;
  $text = "" unless defined $text;

  my @fields = ();

  while($text =~ 
          /^($RECSEP.*?)
            (?=$RECSEP|\s*\Z)/smgx) {
    my($head, $info, $tip) = rec_parse($1);
    $tip =~ s/\s+\Z//;
    $tip =~ s/\A\s+//;
    push @fields, [$head, $info, $tip];
  }
  return \@fields;
}

###########################################
sub rec_parse {
###########################################
    my($text) = @_;

    if($text =~ /$RECSEP\s+(.*?)
                 (?:\s+\{(.*?)\})?
                 $
                 (.*)
                /smgx) {
        return($1, $2, $3);
    }

    return undef;
}

###########################################
sub db_update {
###########################################
  my($in) = @_;

  my $data;

  if( ref($in) ){
    $data = $$in;
  } else {
    $data = slurp($in);
  }

  my $fields = text2db($data);

  my @keep_ids = map { $_->[1] } @$fields;
  my $gone;
  if(@keep_ids) {
    $gone = Tip::Manager->delete_tips(
          where => ["!id" => \@keep_ids] );
  } else {
    $gone = Tip::Manager->delete_tips(
                                all => 1 );
  }
  print "$gone rows deleted\n" if $gone;

  for(@$fields) {
    my($head, $info, $tip) = @$_;

    my $rec;

    if(defined $info) {
      $rec = Tip->new(id => $info);
      $rec->load();
      $rec->head($head);
      $rec->text($tip);
      $rec->update();
    } else {
      $rec = Tip->new(
        text => $tip,
        head => $head,
      );
      $rec->save();
    }
  }
}

###########################################
sub mail {
###########################################
  my($to, $head, $body) = @_;

  my $mailer = Mail::Mailer->new();

  $mailer->open({
   'From' => $MAIL_FROM,
   'To'   => $to,
   'Subject' => $head,
  });
  print $mailer $body;
  close $mailer;
}
