package Games::Wormy::Render;

use 5.010;
use strict;
use warnings;
use experimental 'switch';

use Imager;
use List::Util qw(sum max);

our $VERSION = '1.01';

our %COL = (
	bg     => Imager::Color->new(255, 255, 255),
	wall   => Imager::Color->new(  0,   0,   0),
	player => [
		{
			main  => Imager::Color->new(hue => 120, v => 1, s => .67),
			outer => Imager::Color->new(hue => 120, v => 1, s => .33),
		},
	],
	bouncy => Imager::Color->new(hue => 180, v => 1, s => 1),
);

sub level {
	my ($self, $level) = @_;
	$level or return;

	my $field = Imager->new(xsize => $level->{width}, ysize => $level->{height});
	$field->box(filled => 1, color => $COL{bg});

	# initial player paths
	require Math::Trig;
	my $DIRMULT = Math::Trig::pi() / 128;
	for my $num (0 .. $#{ $level->{worms} }) {
		my $player = $level->{worms}->[$num];
		$field->line(
			x1 => $player->{x},
			y1 => $player->{y},
			x2 => $player->{x} + sin($_ * $DIRMULT) * 15,
			y2 => $player->{y} + cos($_ * $DIRMULT) * 15,
			color => $COL{player}->[$num]->{outer},
		) for $player->{d} + 13, $player->{d} - 13;
		$field->line(
			x1 => $player->{x},
			y1 => $player->{y},
			x2 => $player->{x} + sin($player->{d} * $DIRMULT) * 20,
			y2 => $player->{y} + cos($player->{d} * $DIRMULT) * 20,
			color => $COL{player}->[$num]->{main},
		);
		$field->circle(
			x => $player->{x},
			y => $player->{y},
			r => 2,
			color => $COL{player}->[$num]->{main},
		);
		last;
	}

	# outer field borders
	$field->box(
		xmin => $_,   ymin => 0,
		xmax => $_+1, ymax => $level->{height} - 1,
		filled => 1,
		color => $COL{wall},
	) for 0, $level->{width} - 2;
	$field->box(
		ymin => $_,   xmin => 2,
		ymax => $_+1, xmax => $level->{width} - 1,
		filled => 1,
		color => $COL{wall},
	) for 0, $level->{height} - 2;

	# draw objects
	for my $object (@{ $level->{objects} }) {
		my @x = @$object{'x1', 'x2'};
		my @y = @$object{'y1', 'y2'};
		given ($object->{type}) {
			when (1) {
				$field->line(
					x1 => $x[0],
					y1 => $y[0],
					x2 => $x[1],
					y2 => $y[1],
					color => $COL{wall},
				);
			}
			when (2) {
				$field->polyline(
					points => [
						[  $x[0], $y[0]], [  $x[1], $y[1]],
						[++$x[1], $y[1]], [++$x[0], $y[0]],
						[$x[0], ++$y[0]], [$x[1], ++$y[1]],
						[--$x[1], $y[1]], [--$x[0], $y[0]],
					],
					color => $COL{wall},
				);
			}
			when (3) {
				$field->box(
					xmin => $x[0],
					ymin => $y[0],
					xmax => $x[1],
					ymax => $y[0] + $y[1],
					filled => 1,
					color => $COL{wall},
				);
			}
			when (4) {
				$field->circle(
					x => $x[0],
					y => $y[0],
					r => $x[1],
					filled => 1,
					color => $COL{wall},
				);
			}
		}
	}

	for my $bouncy (@{ $level->{balls} }) {
		$field->box(
			xmin => $bouncy->{x},
			ymin => $bouncy->{y},
			xmax => $bouncy->{x} + 1,
			ymax => $bouncy->{y} + 1,
			color => $COL{bouncy},
		);
	}

	return $field;
}

sub composite {
	my $self = shift;

	# single level can be returned directly
	return $self->level($_[0]) if @_ == 1;

	# concatenate images of multiple levels
	my $width  = max map { $_->{width} } @_;
	my $height = sum(map { $_->{height} + 1 } @_) - 1;
	my $output = Imager->new(xsize => $width, ysize => $height);
	$output->box(filled => 1, color => [64, 0, 0]);
	$height = 0;
	for (@_) {
		$output->paste(src => $self->level($_), top => $height);
		$height += $_->{height} + 1;
	}
	return $output;
}

1;

