package AA::UI;

use strict;
use warnings;

sub new($$) {
	my ($class, $name) = @_;
	if ($name eq "") {
		return AA::UI::GTK->new(1);
	} elsif ($name eq "gtk") {
		return AA::UI::GTK->new(0);
	} elsif ($name =~ /\.pdf$/) {
		return AA::UI::PDF->new($name);
	} elsif ($name =~ /\.png$/) {
		return AA::UI::PNG->new($name);
	}
}

package AA::UI::GTK;

my $debug = 1;

our @ISA = ('AA::UI');

sub new($$) {
	my ($class, $mode) = @_;
	my $ui = {
		MODE => $mode,
	};
	return bless($ui, $class);
}

my $u_scenario;
my $u_scene;
my $u_frame;
my $u_direction;
my @u_scenes = ();
my @u_last_frame = ();

my $window;
my $cairo;
my $area;
my $pixmap;
my $timer;
my $stopped = 0;
my $fullscreen = 0;
my $movie = 0;
my ($lastw, $lasth) = (-1, -1);
my ($pixw, $pixh) = (-1, -1);
my ($last_scene, $last_frame) = (-1, -1);

sub draw {
	my ($force) = @_;
	if (!$force) {
		$area->queue_draw();
		return;
	}

	my $w = $area->get_allocated_width;
	my $h = $area->get_allocated_height;
	# print "Area $w x $h\n";

	if ($lastw != $w || $lasth != $h) {
		($lastw, $lasth) = ($w, $h);
		if ($w/$h >= 4/3) {
			$pixh = $h;
			$pixw = int($h/3*4);
		} else {
			$pixw = $w;
			$pixh = int($w/4*3);
		}
		print "Resized to ${w}x${h}, pixmap size ${pixw}x${pixh}\n" if $debug;
	}

	$cairo->rectangle(0, 0, $w, $h);
	$cairo->set_source_rgb(0, 0, 0);
	$cairo->fill;

	$cairo->translate(($w - $pixw) / 2, 0);
	my $scale = $pixw/1024;
	$cairo->scale($scale, $scale);

	if (@u_scenes) {
		print "@@@ Scene $u_scene frame $u_frame\n" if $debug;
		$u_scenes[$u_scene]->[$u_frame]->Draw($cairo);
		$cairo->set_source_rgb(.5, .5, .5);
		$cairo->set_font_size(15);
		$cairo->move_to(950,750);
		$cairo->show_text($u_scene . "/" . $#u_scenes);
	} else {
		AA->calculate;
		AA->draw($cairo);
	}

	$last_scene = $u_scene;
	$last_frame = $u_frame;
}

sub step() {
	# FIXME: the timer still runs
	if (@u_scenes) {
		if ($u_direction > 0) {
			if ($u_frame < $u_last_frame[$u_scene]) {
				$u_frame++;
			} elsif ($u_scene < @u_scenes - 1) {
				$u_scene++;
				$u_frame = 0;
			}
			if ($u_frame == $u_last_frame[$u_scene]) {
				$u_direction = 0 unless $movie;
			}
		} elsif ($u_direction < 0) {
			if ($u_frame) {
				$u_frame--;
			} elsif ($u_scene) {
				$u_scene--;
				$u_frame = $u_last_frame[$u_scene];
				$u_direction = 0 unless $movie;
			}
		}
		return if ($u_scene == $last_scene && $u_frame == $last_frame);
	} else {
		AA::Anim->step;
	}
	draw(0);
}

sub prepare() {
	$window = Gtk3::Window->new ('toplevel');
	$area = Gtk3::DrawingArea->new();
	$area->signal_connect("draw" => sub {
		my ($w, $cr) = @_;
		$cairo = $cr;
		draw(1);
		if (!defined $timer) {
			$timer = Glib::Timeout->add(30, sub { $stopped || step(); return 1; });
		}
	});
	$area->set_can_focus(1);
	$area->add_events('key-press-mask');
	$area->signal_connect('key-press-event' => sub {
		my ($w, $evt) = @_;
		my $k = Gtk3::Gdk::keyval_name($evt->keyval);
		print "Pressed key $k\n" if $debug;
		if ($k eq "Escape") {
			Gtk3->main_quit;
		} elsif ($k eq "f") {
			if ($fullscreen = !$fullscreen) {
				$window->fullscreen;
			} else {
				$window->unfullscreen;
			}
		} elsif ($k eq "space" || $k eq "Right" || $k eq "Page_Down") {
			if (@u_scenes) {
				if ($stopped || $k eq "Page_Down") {
					if ($u_scene+1 < @u_scenes) {
						$u_scene++;
						$u_frame = $u_last_frame[$u_scene];
					}
					$u_direction = 0;
				} elsif ($u_direction > 0) {
					$u_frame = $u_last_frame[$u_scene];
					$u_direction = 0;
				} else {
					$u_direction = 1;
				}
				draw(0);
			} else {
				while (AA::Anim->step) { AA->calculate; }
				if ($u_scene+1 < @$u_scenario) {
					$u_scene++;
					AA::Anim->start;
					&{$u_scenario->[$u_scene]};
					draw(0);
				}
			}
		} elsif ($k eq "BackSpace" || $k eq "Left" || $k eq "Page_Up") {
			if (@u_scenes) {
				if ($stopped || $k eq "Page_Up") {
					if ($u_scene > 0) {
						$u_scene--;
						$u_frame = $u_last_frame[$u_scene];
					}
					$u_direction = 0;
				} elsif ($u_direction < 0) {
					$u_frame = 0;
				} else {
					$u_direction = -1;
				}
				draw(0);
			}
		} elsif ($k eq "Home" || $k eq "0") {
			if (@u_scenes) {
				$u_scene = 0;
				$u_frame = 0;
				$u_direction = 0;
				draw(0);
			}
		} elsif ($k eq "End" || $k eq "9") {
			if (@u_scenes) {
				$u_scene = $#u_scenes;
				$u_frame = $u_last_frame[$u_scene];
				$u_direction = 0;
				draw(0);
			}
		} elsif ($k eq "p") {
			$stopped = !$stopped;
			$u_direction = 0 if $stopped;
			print "Stopped is $stopped\n" if $debug;
		} elsif ($k eq "m") {
			$movie = !$movie;
			print "Movie mode is $movie\n" if $debug;
		} elsif ($k eq "Return") {
			if (@u_scenes) {
				$u_frame = ($u_direction > 0) ? $u_last_frame[$u_scene] : 0;
			} else {
				while (AA::Anim->step) { AA->calculate; }
			}
		}
	});

	$window->signal_connect ("delete-event" => sub { Gtk3->main_quit });
	$window->set_title("Brum");
	$window->set_wmclass("brum", "Brum");
	$window->set_default_size(640, 480);
	$window->add ($area);
	$window->show_all;
}

sub RunScenario($$) {
	my ($ui, $scenario) = @_;

	if ($ui->{MODE}) {
		print "Rendering...\n";
		foreach my $s (@$scenario) {
			print ">>> Scene ", scalar @u_scenes, "\n" if $debug;
			AA::Anim->start;
			&$s;
			my $show = [];
			while (AA::Anim->step) {
				print "\t>>> Frame ", scalar @$show, "\n" if $debug;
				AA->calculate;
				push @$show, AA::Scene->new();
			}
			push @u_scenes, $show;
			push @u_last_frame, scalar @$show - 1;
		}
		print "Ready.\n";
	} else {
		$u_scenario = $scenario;
		AA::Anim->start;
		&{$scenario->[0]};
	}

	$u_scene = 0;
	$u_frame = 0;
	$u_direction = 0;
	prepare();
	Gtk3->main;
}

package AA::UI::PDF;

our @ISA = ('AA::UI');

sub new($$) {
	my ($class, $name) = @_;
	my $ui = { };
	$ui->{SURF} = Cairo::PdfSurface->create($name, 512, 384) or die "Unable to create PDF surface $name\n";
	$ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
	$ui->{CAIRO}->scale(.5, .5);
	return bless($ui, $class);
}

sub RunScenario($$$) {
	my ($ui, $scenario) = @_;
	my $page = 0;
	print "Rendering to PDF\n";
	foreach my $s (@$scenario) {
		$page++;
		print "### Page $page ###\n";
		AA::Anim->start;
		&$s();
		do {
			AA->calculate;
		} while (AA::Anim->step);
		AA->draw($ui->{CAIRO});
		$ui->{CAIRO}->show_page;
	}
}

package AA::UI::PNG;

our @ISA = ('AA::UI');

sub new($$) {
	my ($class, $name) = @_;
	my $ui = { };
	$ui->{NAME} = $name;
	$ui->{SURF} = Cairo::ImageSurface->create('argb32', 1024, 768) or die "Unable to create image surface $name\n";
	$ui->{CAIRO} = Cairo::Context->create($ui->{SURF});
	return bless($ui, $class);
}

sub RunScenario($$$) {
	my ($ui, $scenario) = @_;
	my $cairo = $ui->{CAIRO};
	my $page = 0;
	print "Rendering to PNG images\n";
	foreach my $s (@$scenario) {
		$page++;
		print "### Page $page ###\n";
		AA::Anim->start;
		&$s();
		do {
			AA->calculate;
		} while (AA::Anim->step);
		AA->draw($cairo);
		$cairo->show_page;
		my $name = sprintf($ui->{NAME}, $page);
		$ui->{SURF}->write_to_png($name) or die "Unable to write to $name\n";
	}
}

1;
