package Plack::Middleware::SocketIO::WebSocket;

use strict;
use warnings;

use base 'Plack::Middleware::SocketIO::Base';

use Protocol::WebSocket::Frame;
use Protocol::WebSocket::Handshake::Server;

use Plack::Middleware::SocketIO::Handle;

sub name {'websocket'}

sub finalize {
    my $self = shift;
    my ($cb) = @_;

    my $fh = $self->req->env->{'psgix.io'};
    return unless $fh;

    my $hs = Protocol::WebSocket::Handshake::Server->new_from_psgi($self->req->env);
    return unless $hs->parse($fh);

    return unless $hs->is_done;

    my $handle = $self->_build_handle($fh);
    my $frame = Protocol::WebSocket::Frame->new;

    return sub {
        my $respond = shift;

        $handle->write(
            $hs->to_string => sub {
                my $handle = shift;

                my $conn = $self->add_connection(on_connect => $cb);

                $handle->on_read(
                    sub {
                        my $handle = shift;

                        $frame->append($_[0]);

                        while (my $message = $frame->next) {
                            $conn->read($message);
                        }
                    }
                );

                $handle->on_eof(
                    sub {
                        $handle->close;

                        $self->client_disconnected($conn);
                    }
                );

                $conn->on_write(
                    sub {
                        my $conn = shift;
                        my ($message) = @_;

                        $message = $self->_build_frame($message);

                        $handle->write($message);
                    }
                );

                $conn->send_id_message($conn->id);

                $self->client_connected($conn);
            }
        );
    };
}

sub _build_frame {
    my $self = shift;
    my ($message) = @_;

    return Protocol::WebSocket::Frame->new($message)->to_string;
}

1;
__END__

=head1 NAME

Plack::Middleware::SocketIO::WebSocket - WebSocket transport

=head1 DESCRIPTION

L<Plack::Middleware::SocketIO::WebSocket> is a WebSocket transport implementation.

=head1 SEE ALSO

L<Protocol::WebSocket>

=cut
