# A simple chat server connection manager.
# Implements the "CheezyChat" client/server
# interface.
# Copyright 2004 by Rocco Caputo.  Free software.
# Same terms as Perl itself.  Have fun!

package Chat;

use warnings;
use strict;

use POE qw(Wheel::ReadWrite);
use ChatUser;

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

  POE::Session->create(
    inline_states => {
      _start    => \&handle_start,
      got_login => \&handle_login,
      got_chat  => \&handle_chat,
      got_error => \&handle_error,
      hear      => \&handle_hear,
      got_flush => \&handle_flush,
    },
    args => [ $socket ],
  );
}

sub handle_start {
  my ($heap, $socket) = @_[HEAP, ARG0];
  $heap->{stream} = POE::Wheel::ReadWrite->new(
    Handle     => $socket,
    InputEvent => "got_login",
    ErrorEvent => "got_error",
  );
  $heap->{stream}->put(
    "Welcome to the CheezyChat Server.",
    "Please log in with: connect <login name>",
  );
}

sub handle_login {
  my ($heap, $input) = @_[HEAP, ARG0];
  if ($input =~ /^connect\s+(.+?)\s*$/) {
    if (ChatUser->is_on($1)) {
      $heap->{stream}->put(
        "Sorry, '$1' is already on.  Try again."
      );
      return;
    }
    $heap->{stream}->put(
      "You are logged in as $1.",
      "/who shows who's on.  /quit exits."
    );
    ChatUser->login($_[SESSION]->ID(), $1);
    $heap->{stream}->event(
      InputEvent => "got_chat"
    );
    return;
  }
  $heap->{stream}->put(
    "I don't understand.  Please try again."
  );
}

sub handle_chat {
  my ($heap, $input) = @_[HEAP, ARG0];
  if ($input =~ /^\/(quit|exit)$/i) {
    ChatUser->logout($_[SESSION]->ID());
    $heap->{stream}->event(
      FlushedEvent => "got_flush"
    );
    return;
  }
  if ($input =~ /^\/who$/i) {
    my @users = ChatUser->get_users();
    $heap->{stream}->put(
      "People online: " . join(", ", @users)
    );
    return;
  }
  ChatUser->say($_[SESSION]->ID(), $input);
}

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

sub handle_hear {
  return unless $_[HEAP]->{stream};
  $_[HEAP]->{stream}->put($_[ARG0]);
}

sub handle_flush {
  delete $_[HEAP]->{stream};
}
1;
