use strict;
use warnings;
use Test::More;
use SDL;
use SDL::Config;
use SDL::Video;
use SDL::Color;
use SDLx::Sprite::Animated;
use lib 't/lib';
use SDL::TestTool;


my $videodriver = $ENV{SDL_VIDEODRIVER};
$ENV{SDL_VIDEODRIVER} = 'dummy' unless $ENV{SDL_RELEASE_TESTING};

if ( !SDL::TestTool->init(SDL_INIT_VIDEO) ) {
	plan( skip_all => 'Failed to init video' );
} elsif ( !SDL::Config->has('SDL_image') ) {
	plan( skip_all => 'SDL_image support not compiled' );
}


can_ok(
	'SDLx::Sprite::Animated',
	qw( new rect clip load surface x y w h draw alpha_key
		step_x step_y type max_loops ticks_per_frame current_frame current_loop
		set_sequences sequence next previous reset start stop draw)
);

TODO: {
	local $TODO = 'methods not implemented yet';
	can_ok( 'SDLx::Sprite', qw( add remove zoom ) );
}

my $disp = SDL::Video::set_video_mode( 300, 300, 32, SDL_ANYFORMAT );

my $sprite = SDLx::Sprite::Animated->new(
	width  => 48,
	height => 48
);

isa_ok( $sprite, 'SDLx::Sprite' );
isa_ok( $sprite, 'SDLx::Sprite::Animated' );

my $clip = $sprite->clip;
ok( $clip, 'clip defined upon raw initialization' );
isa_ok( $clip, 'SDL::Rect', 'spawned clip isa SDL::Rect' );
is( $clip->x, 0,  'clip->x init' );
is( $clip->y, 0,  'clip->y init' );
is( $clip->w, 48, 'clip->w init' );
is( $clip->h, 48, 'clip->h init' );

my $rect = $sprite->rect;
ok( $rect, 'rect defined upon raw initialization' );
isa_ok( $rect, 'SDL::Rect', 'spawned rect isa SDL::Rect' );
is( $rect->x, 0,  'rect->x init' );
is( $rect->y, 0,  'rect->y init' );
is( $rect->w, 48, 'rect->w init' );
is( $rect->h, 48, 'rect->h init' );

my ( $x, $y ) = ( $sprite->x, $sprite->y );
is( $x, 0, 'no x defined upon raw initialization' );
is( $y, 0, 'no y defined upon raw initialization' );

my ( $w, $h ) = ( $sprite->w, $sprite->h );
is( $w, 48, 'w defined upon raw initialization' );
is( $h, 48, 'h defined upon raw initialization' );

isa_ok(
	$sprite->load('test/data/hero.bmp'),
	'SDLx::Sprite::Animated', '[load] works'
);

isa_ok(
	$sprite->alpha_key( SDL::Color->new( 0xfc, 0x00, 0xff ) ),
	'SDLx::Sprite::Animated', '[alpha_key] works'
);

isa_ok(
	$sprite->alpha(0xcc), 'SDLx::Sprite::Animated',
	'[alpha] integer works '
);

isa_ok(
	$sprite->alpha(0.3), 'SDLx::Sprite::Animated',
	'[alpha] percentage works'
);

is( $clip->x, 0,  'clip->x after load' );
is( $clip->y, 0,  'clip->y after load' );
is( $clip->w, 48, 'clip->w after load' );
is( $clip->h, 48, 'clip->h after load' );

is( $rect->x, 0,  'rect->x after load' );
is( $rect->y, 0,  'rect->y after load' );
is( $rect->w, 48, 'rect->w after load' );
is( $rect->h, 48, 'rect->h after load' );

$sprite->set_sequences( left => [ [ 1, 0 ], [ 1, 1 ], [ 1, 2 ] ], );

my ( $clip_w, $clip_h ) = ( $sprite->clip->w, $sprite->clip->h );
$sprite->alpha_key( SDL::Color->new( 0xfc, 0x00, 0xff ) );
is( $sprite->clip->w, $clip_w, 'alpha_key() does not change clip width' );
is( $sprite->clip->h, $clip_h, 'alpha_key() does not change clip height' );

$sprite->sequence('left');

is( $sprite->current_frame, 1, 'sprite->current_frame after sequence' );
is( $sprite->current_loop,  1, 'sprite->current_loop after sequence' );

is( $clip->x, 48, 'clip->x after sequence' );
is( $clip->y, 0,  'clip->y after sequence' );
is( $clip->w, 48, 'clip->w after sequence' );
is( $clip->h, 48, 'clip->h after sequence' );

is( $rect->x, 0,  'rect->x after sequence' );
is( $rect->y, 0,  'rect->y after sequence' );
is( $rect->w, 48, 'rect->w after sequence' );
is( $rect->h, 48, 'rect->h after sequence' );

$sprite->next;
is( $sprite->current_frame, 2, 'sprite->current_frame after next' );
is( $sprite->current_loop,  1, 'sprite->current_loop after next' );

is( $clip->x, 48, 'clip->x after next' );
is( $clip->y, 48, 'clip->y after next' );
is( $clip->w, 48, 'clip->w after next' );
is( $clip->h, 48, 'clip->h after next' );

is( $rect->x, 0,  'rect->x after next' );
is( $rect->y, 0,  'rect->y after next' );
is( $rect->w, 48, 'rect->w after next' );
is( $rect->h, 48, 'rect->h after next' );

$sprite->next;
is( $sprite->current_frame, 3, 'sprite->current_frame after second next' );
is( $sprite->current_loop,  1, 'sprite->current_loop after second next' );

is( $clip->x, 48, 'clip->x after second next' );
is( $clip->y, 96, 'clip->y after second next' );
is( $clip->w, 48, 'clip->w after second next' );
is( $clip->h, 48, 'clip->h after second next' );

is( $rect->x, 0,  'rect->x after second next' );
is( $rect->y, 0,  'rect->y after second next' );
is( $rect->w, 48, 'rect->w after second next' );
is( $rect->h, 48, 'rect->h after second next' );

$sprite->next;
is( $sprite->current_frame, 1, 'sprite->current_frame after third next' );
is( $sprite->current_loop,  2, 'sprite->current_loop after second next' );

is( $clip->x, 48, 'clip->x after third next' );
is( $clip->y, 0,  'clip->y after third next' );
is( $clip->w, 48, 'clip->w after third next' );
is( $clip->h, 48, 'clip->h after third next' );

is( $rect->x, 0,  'rect->x after third next' );
is( $rect->y, 0,  'rect->y after third next' );
is( $rect->w, 48, 'rect->w after third next' );
is( $rect->h, 48, 'rect->h after third next' );

is( $sprite->next, $sprite, 'next() returns the object' );

is( $sprite->current_frame, 2, 'sprite->current_frame after next' );

is( $sprite->previous, $sprite, 'previous() returns the object' );

is( $sprite->current_frame, 1, 'sprite->current_frame after previous' );

$sprite->next;
is( $sprite->current_frame, 2, 'sprite->current_frame before reset' );

is( $clip->x, 48, 'clip->x before reset' );
is( $clip->y, 48, 'clip->y before reset' );
is( $clip->w, 48, 'clip->w before reset' );
is( $clip->h, 48, 'clip->h before reset' );

is( $sprite->reset, $sprite, 'reset() returns the object' );

is( $sprite->current_frame, 1, 'sprite->current_frame after reset' );

is( $clip->x, 48, 'clip->x after reset' );
is( $clip->y, 0,  'clip->y after reset' );
is( $clip->w, 48, 'clip->w after reset' );
is( $clip->h, 48, 'clip->h after reset' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	rect  => SDL::Rect->new( 40, 50, 48, 48 ),
);

$clip = $sprite->clip;
is( $clip->x, 0,  'clip->x after new with image and rect' );
is( $clip->y, 0,  'clip->y after new with image and rect' );
is( $clip->w, 48, 'clip->w after new with image and rect' );
is( $clip->h, 48, 'clip->h after new with image and rect' );

$rect = $sprite->rect;
is( $rect->x, 40, 'rect->x after new with image and rect' );
is( $rect->y, 50, 'rect->y after new with image and rect' );
is( $rect->w, 48, 'rect->w after new with image and rect' );
is( $rect->h, 48, 'rect->h after new with image and rect' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	clip  => SDL::Rect->new( 0, 0, 48, 48 ),
);

$clip = $sprite->clip;
is( $clip->x, 0,  'clip->x after new with image and clip' );
is( $clip->y, 0,  'clip->y after new with image and clip' );
is( $clip->w, 48, 'clip->w after new with image and clip' );
is( $clip->h, 48, 'clip->h after new with image and clip' );

$rect = $sprite->rect;
is( $rect->x, 0,  'rect->x after new with image and clip' );
is( $rect->y, 0,  'rect->y after new with image and clip' );
is( $rect->w, 48, 'rect->w after new with image and clip' );
is( $rect->h, 48, 'rect->h after new with image and clip' );

$sprite = SDLx::Sprite::Animated->new(
	image  => 'test/data/hero.bmp',
	rect   => SDL::Rect->new( 40, 50, 48, 48 ),
	step_x => 50,
	step_y => 50,
);
$sprite->set_sequences(
	left  => [ [ 1, 0 ], [ 1, 1 ], ],
	right => [ [ 3, 0 ], [ 3, 1 ], ],
);
$sprite->sequence('left');

$clip = $sprite->clip;
is( $clip->x, 50, 'clip->x after new with step_x, step_y' );
is( $clip->y, 0,  'clip->y after new with step_x, step_y' );
is( $clip->w, 48, 'clip->w after new with step_x, step_y' );
is( $clip->h, 48, 'clip->h after new with step_x, step_y' );

$sprite->next;
$clip = $sprite->clip;
is( $clip->x, 50, 'clip->x after first next' );
is( $clip->y, 50, 'clip->y after first next' );
is( $clip->w, 48, 'clip->w after first next' );
is( $clip->h, 48, 'clip->h after first next' );

$sprite->next;
$clip = $sprite->clip;
is( $clip->x, 50, 'clip->x after second next' );
is( $clip->y, 0,  'clip->y after second next' );
is( $clip->w, 48, 'clip->w after second next' );
is( $clip->h, 48, 'clip->h after second next' );

$sprite->sequence('right');
$clip = $sprite->clip;
is( $clip->x, 150, 'clip->x after sequence change' );
is( $clip->y, 0,   'clip->y after sequence change' );
is( $clip->w, 48,  'clip->w after sequece change' );
is( $clip->h, 48,  'clip->h after sequence change' );

$sprite->next;
$clip = $sprite->clip;
is( $clip->x, 150, 'clip->x after first next' );
is( $clip->y, 50,  'clip->y after first next' );
is( $clip->w, 48,  'clip->w after first next' );
is( $clip->h, 48,  'clip->h after first next' );

$sprite->next;
$clip = $sprite->clip;
is( $clip->x, 150, 'clip->x after second next' );
is( $clip->y, 0,   'clip->y after second next' );
is( $clip->w, 48,  'clip->w after second next' );
is( $clip->h, 48,  'clip->h after second next' );

$sprite = SDLx::Sprite::Animated->new(
	image     => 'test/data/hero.bmp',
	rect      => SDL::Rect->new( 40, 50, 48, 48 ),
	max_loops => 2,
);
$sprite->set_sequences( up => [ [ 0, 0 ], [ 0, 1 ], ], );
$sprite->sequence('up');
$clip = $sprite->clip;
is( $clip->y, 0, 'clip->y after new with max_loops' );

$sprite->next;
is( $clip->y, 48, 'clip->y after first next' );

$sprite->next;
is( $clip->y, 0, 'clip->y after second next' );

$sprite->next;
is( $clip->y, 48, 'clip->y after third next' );

$sprite->next;
is( $clip->y, 0, 'clip->y after fourth next' );

$sprite->next;
is( $clip->y, 0, 'clip->y after fifth next' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	rect  => SDL::Rect->new( 40, 50, 48, 48 ),
	type  => 'reverse'
);
$sprite->set_sequences( up => [ [ 0, 0 ], [ 0, 1 ], [ 0, 2 ], ], );
$sprite->sequence('up');
$clip = $sprite->clip;
is( $clip->y, 0, 'clip->y after new with type = reverse' );
is( $sprite->current_loop, 1,
	'sprite->current_loop after new with type = reverse'
);

$sprite->next;
is( $clip->y,               48, 'clip->y after first next' );
is( $sprite->current_frame, 2,  'sprite->current_frame after first next' );
is( $sprite->current_loop,  1,  'sprite->current_loop after first next' );

$sprite->next;
is( $clip->y,               96, 'clip->y after second next' );
is( $sprite->current_frame, 3,  'sprite->current_frame after second next' );
is( $sprite->current_loop,  1,  'sprite->current_loop after second next' );

$sprite->next;
is( $clip->y,               48, 'clip->y after third next' );
is( $sprite->current_frame, 2,  'sprite->current_frame after third next' );
is( $sprite->current_loop,  1,  'sprite->current_loop after third next' );

$sprite->next;
is( $clip->y,               0, 'clip->y after fourth next' );
is( $sprite->current_frame, 1, 'sprite->current_frame after fourth next' );
is( $sprite->current_loop,  2, 'sprite->current_loop after fourth next' );

$sprite->next;
is( $clip->y,               48, 'clip->y after fifth next' );
is( $sprite->current_frame, 2,  'sprite->current_frame after fifth next' );
is( $sprite->current_loop,  2,  'sprite->current_loop after fifth next' );

$sprite->next;
is( $clip->y,               96, 'clip->y after sixth next' );
is( $sprite->current_frame, 3,  'sprite->current_frame after sixth next' );
is( $sprite->current_loop,  2,  'sprite->current_loop after sixth next' );

$sprite->next;
is( $clip->y,               48, 'clip->y after seventh next' );
is( $sprite->current_frame, 2,  'sprite->current_frame after seventh next' );
is( $sprite->current_loop,  2,  'sprite->current_loop after seventh next' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	rect  => SDL::Rect->new( 40, 50, 48, 48 ),
);
$sprite->set_sequences( up => [ [ 0, 0 ], [ 0, 1 ], ], );
$sprite->sequence('up');
$clip = $sprite->clip;
is( $clip->y, 0, 'clip->y after new' );

$sprite->previous;
is( $clip->y, 48, 'clip->y after first previous' );

$sprite->previous;
is( $clip->y, 0, 'clip->y after second previous' );

$sprite->previous;
is( $clip->y, 48, 'clip->y after third previous' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	rect  => SDL::Rect->new( 40, 50, 48, 48 ),
	type  => 'reverse'
);
$sprite->set_sequences( up => [ [ 0, 0 ], [ 0, 1 ], [ 0, 2 ], ], );
$sprite->sequence('up');
$clip = $sprite->clip;
is( $clip->y, 0, 'clip->y after new with type = reverse' );

$sprite->previous;
is( $clip->y,               96, 'clip->y after first previous' );
is( $sprite->current_frame, 3,  'sprite->current_frame after first previous' );

$sprite->previous;
is( $clip->y,               48, 'clip->y after second previous' );
is( $sprite->current_frame, 2,  'sprite->current_frame after second previous' );

$sprite->previous;
is( $clip->y,               0, 'clip->y after third previous' );
is( $sprite->current_frame, 1, 'sprite->current_frame after third previous' );

$sprite->previous;
is( $clip->y,               48, 'clip->y after fourth previous' );
is( $sprite->current_frame, 2,  'sprite->current_frame after fourth previous' );

$sprite->previous;
is( $clip->y,               96, 'clip->y after fifth previous' );
is( $sprite->current_frame, 3,  'sprite->current_frame after fifth previous' );

$sprite->previous;
is( $clip->y,               48, 'clip->y after sixth previous' );
is( $sprite->current_frame, 2,  'sprite->current_frame after sixth previous' );

$sprite->previous;
is( $clip->y,               0, 'clip->y after seventh previous' );
is( $sprite->current_frame, 1, 'sprite->current_frame after seventh previous' );

$sprite = SDLx::Sprite::Animated->new(
	image     => 'test/data/hero.bmp',
	rect      => SDL::Rect->new( 40, 50, 48, 48 ),
	clip      => SDL::Rect->new( 48, 48, 48, 48 ),
	sequences => { up => [ [ 0, 0 ], [ 0, 1 ] ] },
	sequence  => 'up',
);
$clip = $sprite->clip;
is( $clip->x, 48, 'clip->x after new with clip' );
is( $clip->y, 48, 'clip->y after new with clip' );

$sprite->next();
is( $clip->x, 48, 'clip->x after first next' );
is( $clip->y, 96, 'clip->y after first next' );

$sprite->next();
is( $clip->x, 48, 'clip->x after second next' );
is( $clip->y, 48, 'clip->y after second next' );

$sprite = SDLx::Sprite::Animated->new(
	image => 'test/data/hero.bmp',
	rect  => SDL::Rect->new( 40, 50, 48, 48 ),
);
$clip = $sprite->clip;
is( $clip->x, 0, 'clip->x after new with no sequences' );
is( $clip->y, 0, 'clip->y after new with no sequences' );

my $sequences = [
	[ 0, 0 ],  [ 48, 0 ],  [ 96, 0 ],  [ 144, 0 ],  [ 192, 0 ],
	[ 0, 48 ], [ 48, 48 ], [ 96, 48 ], [ 144, 48 ], [ 192, 48 ],
	[ 0, 96 ], [ 48, 96 ], [ 96, 96 ], [ 144, 96 ], [ 192, 96 ],
];

foreach my $count ( 1 .. 20 ) {
	$sprite->next;
	my $s = $sequences->[ $count % @$sequences ];
	is( $clip->x, $s->[0], 'clip->x after ' . $count . '-th next' );
	is( $clip->y, $s->[1], 'clip->y after ' . $count . '-th next' );
}

done_testing;

#reset the old video driver
if ($videodriver) {
	$ENV{SDL_VIDEODRIVER} = $videodriver;
} else {
	delete $ENV{SDL_VIDEODRIVER};
}

