package SockJS::Transport::JSONPPolling;

use strict;
use warnings;

use base 'SockJS::Transport::Base';

sub new {
    my $self = shift->SUPER::new(@_);

    push @{$self->{allowed_methods}}, 'GET';

    return $self;
}

sub dispatch_GET {
    my $self = shift;
    my ($env, $conn, $path) = @_;

    my ($callback) = $env->{QUERY_STRING} =~ m/(?:^|&|;)c=([^&;]+)/;
    if (!$callback) {
        return [500, [], ['"callback" parameter required']];
    }

    $callback =~ s/%(..)/chr(hex($1))/eg;
    if ($callback !~ m/^[a-zA-Z0-9-_\.]+$/) {
        return [500, [], ['invalid "callback" parameter']];
    }

    return sub {
        my $respond = shift;

        my $writer = $respond->(
            [   200,
                [   'Content-Type' => 'application/javascript; charset=UTF-8',
                    'Connection'   => 'close',
                ]
            ]
        );

        if ($conn->is_connected && !$conn->is_reconnecting) {
            my $message = $self->_wrap_message($callback,
                'c[2010,"Another connection still open"]' . "\n");
            $writer->write($message);
            $writer->close;
            return;
        }

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

                $message = $self->_wrap_message($callback, $message);

                $writer->write($message);
                $writer->write('');
                $writer->close;

                $conn->reconnecting if $conn->is_connected;
            }
        );

        if ($conn->is_closed) {
            $conn->connected;
            $conn->close;
        }
        elsif ($conn->is_connected) {
            $conn->reconnected;
        }
        else {
            $conn->write('o');

            $conn->connected;
        }
    };
}

sub _wrap_message {
    my $self = shift;
    my ($callback, $message) = @_;

    $message =~ s/(['""\\\/\n\r\t]{1})/\\$1/smg;
    $message = qq{/**/$callback("$message");\r\n};

    return $message;
}

1;
