# -><- Messages here.

package MediaConnection;

use warnings;
use strict;

use POE qw(
  Wheel::ReadWrite Filter::HTTPD Filter::Stream
);

use constant FILE_NAME => "./big.mp3";
use constant MIME_TYPE => "audio/x-mp3";

sub spawn {
  my ($class, $socket) = @_;

  POE::Session->create(
    inline_states => {
      _start    => \&handle_start,
      got_input => \&handle_input,
      got_error => \&handle_error,
      got_flush => \&handle_flush,
      got_full  => sub { warn "full" },
      got_ready => \&handle_ready,
    },
    args => [ $socket ],
  );
}

sub handle_start {
  my ($heap, $socket) = @_[HEAP, ARG0];
  $heap->{stream} = POE::Wheel::ReadWrite->new(
    Handle       => $socket,
    Filter       => POE::Filter::HTTPD->new(),
    InputEvent   => "got_input",
    ErrorEvent   => "got_error",
    FlushedEvent => "got_flush",
    HighMark     => 1024 * 256,
    LowMark      => 1024 * 128,
    HighEvent    => "got_full",
    LowEvent     => "got_ready",
  );
}

sub handle_input {
  my ($heap, $request) = @_[HEAP, ARG0];

  if ($request->isa("HTTP::Response")) {
    $heap->{stream}->put($request);
    $heap->{shutdown} = 1;
    return;
  }

  # We could get the FILE_NAME from the request
  # and derive MIME_TYPE from it, but that is
  # outside the scope of this example.

  if (open($heap->{file}, "<", FILE_NAME)) {
    my $response = HTTP::Response->new(200);
    $response->header(
      Content_Type   => MIME_TYPE,
      Content_Length => -s FILE_NAME
    );
    $heap->{stream}->put($response);

    binmode($heap->{file});
    $heap->{stream}->set_output_filter(
      POE::Filter::Stream->new()
    );
    $_[KERNEL]->yield("got_ready");
    return;
  }

  my $response = HTTP::Response->new(500);
  $response->header(
    Content_Type => "text/plain"
  );
  $response->content(
    "Couldn't read " . FILE_NAME . ": $!"
  );
  $heap->{stream}->put($response);
  $heap->{shutdown} = 1;
}


sub handle_flush {
  my ($kernel, $heap) = @_[KERNEL, HEAP];
  warn "flushed chunks";
  if ($heap->{shutdown}) {
    warn "shut down";
    delete $heap->{stream};
    return;
  }
}

sub handle_ready {
  my $heap = $_[HEAP];
  warn "sending some chunks";
  while (
    my $bytes_read = sysread(
      $heap->{file}, my $buffer = "", 65536
    )
  ) {
    next unless $heap->{stream}->put($buffer);
    warn "chunk buffer full";
    return;
  }
  warn "end of file";
  $heap->{shutdown} = 1;
}

sub handle_error {
  my $heap = $_[HEAP];
  my ($syscall, $errno, $text) = @_[ARG0..ARG2];
  delete $heap->{stream};
  return unless $errno;
  warn "Conn: $syscall error $errno: $text\n";
}

1;
