use strict;
use warnings;
use Test::More;
use Test::HexString;

use Protocol::SPDY;
use Protocol::SPDY::Test qw(:all);

sub hexdump($) {
	my $idx = 0;
	my @bytes = split //, join '', @_;
	print "== had " . @bytes . " bytes\n";
	while(@bytes) {
		my @chunk = splice @bytes, 0, 16;
		printf "%04x ", $idx;
		printf "%02x ", ord $_ for @chunk;
		(my $txt = join '', @chunk) =~ s/[^[:print:]]/./g;
		print "   " x (16 - @chunk);
		print for split //, $txt;
		print "\n";
		$idx += @bytes;
	}
}

sub unhex($) { join '', map { chr hex } split ' ', shift }

sub double_check(&$) {
	my $code = shift;
	my $data = shift;
	my $sender_zlib = Protocol::SPDY::Compress->new;
	ok(my $original = Protocol::SPDY::Frame->parse(\unhex $data, zlib => $sender_zlib), 'parse frame');
	control_frame_ok($original);
	ok(my $encoded = $original->as_packet($sender_zlib), 'can regenerate packet');

	my $receiver_zlib = Protocol::SPDY::Compress->new;
	# Check once for original bytestream, then again after decoding/regenerating packet
	subtest 'Original bytestream' => sub { $code->($original); };
	ok(my $regenerated = Protocol::SPDY::Frame->parse(\(my $copy = $encoded), zlib => $receiver_zlib), 'can use decoded info to generate a new packet');
	control_frame_ok($regenerated);
	subtest 'Regenerated bytestream' => sub { $code->($regenerated); };
}

sub check_headers {
	my $frame = shift;
	my @hdr = @{+shift};
	is_deeply([ $frame->header_list ], [ map $hdr[2 * $_], 0..$#hdr/2 ], "header list matches");
	my %hdr = @hdr;
	for my $k (sort keys %hdr) {
		is($frame->header($k), $hdr{$k}, "$k matches");
	}
}

note 'SETTINGS frame';
double_check {
	my $frame = shift;
	isa_ok($frame, 'Protocol::SPDY::Frame::Control::SETTINGS');
	is($frame->type_string, 'SETTINGS', 'have SETTINGS as type');
	is($frame->setting('INITIAL_WINDOW_SIZE'), 10485760, 'INITIAL_WINDOW_SIZE = 10485760');
	is($frame->setting('MAX_CONCURRENT_STREAMS'), 1000, 'MAX_CONCURRENT_STREAMS = 1000');
	is("$frame", "SPDY:SETTINGS, control, MAX_CONCURRENT_STREAMS=1000,INITIAL_WINDOW_SIZE=10485760", 'stringified frame');
	done_testing;
} <<'EOF';
80 03 00 04 00 00 00 14 00 00 00 02 00 00 00 04 00 00 03 e8 00 00 00 07 00 a0 00 00
EOF

note 'SYN_STREAM frame';
double_check {
	my $frame = shift;
	plan tests => 19;
	isa_ok($frame, 'Protocol::SPDY::Frame::Control::SYN_STREAM');
	is($frame->stream_id, 1, 'stream_id is correct');
	ok(!$frame->associated_stream_id, 'no associated stream_id');
	is($frame->version, 3, 'is version 3');
	ok($frame->fin, 'FIN flag is set');
	ok(!$frame->uni, 'UNI flag not set');
	is($frame->priority, 0, 'priority is 0');
	check_headers $frame => [
		':host'           => 'localhost:9929',
		':method'         => 'GET',
		':path'           => '/',
		':scheme'         => 'https',
		':version'        => 'HTTP/1.1',
		'accept'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
		'accept-encoding' => 'gzip,deflate,sdch',
		'accept-language' => 'en-GB,en-US;q=0.8,en;q=0.6',
		'cache-control'   => 'max-age=0',
		'cookie'          => 'm=34e2:|2a03:t|ca3:t|15cc:t|6cfc:t|77cb:t|1d98:t|5be5:t',
		'user-agent'      => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36',
	];
	done_testing;
} <<'EOF';
80 03 00 01 01 00 01 3a 00 00 00 01 00 00 00 00
00 00 38 ea e3 c6 a7 c2 02 65 1b 50 76 b2 82 16
08 7c a0 ac 9a 03 e2 58 59 5a 1a 59 82 92 aa 15
22 41 bb bb 86 80 15 17 24 82 8b 2d 46 80 00 d2
07 08 20 b0 7c 31 b0 90 cc 05 97 a4 19 25 25 05
a0 84 ce 61 85 3d 7d 23 0a 71 7b 44 a0 61 0f 06
b4 c0 b2 06 39 d6 52 47 4b 5f 0b cc b2 c0 5e ea
0b 62 04 06 f6 aa 40 2a 35 4f d7 dd 09 18 04 ba
a1 c1 10 f3 80 6c 30 c3 0c 5b b1 cf 09 10 40 b9
89 15 ba 89 e9 a9 b6 06 00 01 04 f2 03 3c 3b 9a
03 04 20 08 0e 8e 00 04 81 18 00 b6 24 9c 27 98
19 8b 81 88 3f 7e 79 a6 78 77 f7 13 e7 aa 70 1d
47 40 e6 08 c8 25 49 c8 17 3f 42 6e 8d 13 72 79
ef 0e 39 e7 4a e8 17 40 18 05 4c 86 6f 7e 55 66
4e 4e a2 be a9 9e 81 82 46 84 a1 a1 b5 82 4f 66
5e 69 85 42 85 85 59 bc 99 89 26 30 f5 02 d3 7a
78 6a 92 77 66 89 be a9 b1 b9 9e b1 99 82 86 b7
47 88 af 8f 8e 42 4e 66 76 aa 82 7b 6a 72 76 be
a6 82 73 06 b0 74 4f d5 37 b2 d0 33 d0 33 04 66
20 3d 73 43 60 8a 4d 4b 2c ca 84 ea 02 00 00 00
ff ff
EOF

note 'SYN_REPLY frame';
double_check {
	my $frame = shift;
	plan tests => 8;
	isa_ok($frame, 'Protocol::SPDY::Frame::Control::SYN_REPLY');
	is($frame->stream_id, 1, 'stream_id is correct');
	is($frame->version, 3, 'is version 3');
	ok($frame->fin, 'FIN flag is set');
	ok(!$frame->uni, 'UNI flag not set');
	check_headers $frame => [
		':status'  => '200 OK',
		':version' => 'HTTP/1.1',
	];
	done_testing;
} <<'EOF';
80 03 00 02 01 00 00 23 00 00 00 01 48 a8 e3 c6
a7 c2 02 e5 0e 50 7a b4 c2 92 48 39 ac b0 a4 52
00 00 00 00 ff ff 00 00 00 ff ff
EOF
done_testing;
