#!/usr/local/bin/perl -w
###########################################
# flipit - Record and Play Backwards
# Mike Schilli, 2009 (m@perlmeister.com)
###########################################
use strict;
use POE;
use POE::Wheel::Run;
use Curses::UI::POE;
use File::Temp qw(tempfile);
use Sysadm::Install qw(:all);
use POSIX;

our $HEAP;

my $CUI = Curses::UI::POE->new(
  -color_support => 1, 
  inline_states  => {
    _start => sub {
      $HEAP = $_[HEAP];
    },
    play_ended => \&footer_update,
});

my $WIN = $CUI->add("win_id", "Window");

my $FOOT = $WIN->add(qw( bottom Label
  -y -1 -paddingspaces 1
  -fg white -bg blue));

footer_update();

$CUI->set_binding(sub { exit 0; }, "q");
$CUI->set_binding( \&play_flipped, "p");
$CUI->set_binding( \&record, "r" );
$CUI->set_binding( \&record_stop, "s" );

$CUI->mainloop;

###########################################
sub record {
###########################################
  if(defined $HEAP->{recorder}->{wheel}) {
    return; # Still recording
  }

  my($fh, $tempfile) = tempfile(
      SUFFIX => ".ogg", UNLINK => 1);

  my $wheel =
    POE::Wheel::Run->new(
      Program     => "rec",
      ProgramArgs => [$tempfile],
      StderrEvent => 'ignore',
  );

  $HEAP->{recorder} = {
      wheel => $wheel,
      file  => $tempfile,
  };

  $FOOT->text("Recording ... " .
   "([s] to stop, [p] to play)");
  $FOOT->draw();
}

###########################################
sub record_stop {
###########################################
  my $wheel = $HEAP->{recorder}->{wheel};

  return if !defined $wheel;

  $wheel->kill(SIGTERM);
  delete $HEAP->{recorder}->{wheel};
  footer_update();
}

###########################################
sub footer_update {
###########################################
  my $text = "[r] to record";

  if(defined $HEAP->{recorder}->{file}) {
    $text .= ", [p] to play";
  }

  $text .= ", [q] to quit";

  $FOOT->text($text);
  $FOOT->draw();
}

###########################################
sub play_flipped {
###########################################
  if(defined $HEAP->{recorder}->{wheel}) {
        # Active recording? Stop it.
      record_stop( $HEAP );
  }

  $FOOT->text("Playing ...");
  $FOOT->draw();

  my $recorded = $HEAP->{recorder}->{file};

  return if ! defined $recorded;

  my $wheel =
    POE::Wheel::Run->new(
      Program     => \&sox_play,
      ProgramArgs => [$recorded],
      StderrEvent => 'ignore',
      CloseEvent  => 'play_ended',
  );

  $HEAP->{players}->{$wheel->ID} = $wheel;
}

###########################################
sub sox_play {
###########################################
  my($recording) = @_;

  my($fh, $tmpfile) = 
     tempfile(SUFFIX => ".ogg");

  tap "sox", $recording, 
             $tmpfile, "reverse";
  tap "play", $tmpfile;

  unlink $tmpfile;
}
