#!perl -T

use strict;
use Test::More qw(no_plan);

use Graphics::Framebuffer;
use List::Util qw(min max);

my $F = Graphics::Framebuffer->new('MALI' => 1);
isa_ok($F, 'Graphics::Framebuffer');

my $screen_width  = $F->{'XRES'};
my $screen_height = $F->{'YRES'};
my $XX            = $screen_width;
my $YY            = $screen_height;
my $xm            = 1920 / $XX;
my $ym            = 1080 / $YY;
my $center_x      = $XX / 2;
my $center_y      = $YY / 2;
my $factor        = 3;

my @OK;

subtest 'Plot tests' => sub {
    print_it($F, 'Plotting Test');
    my $s = time + $factor;
    while (time < $s) {
        my $x = int(rand($screen_width));
        my $y = int(rand($screen_height));
        $F->set_color({'alpha' => 255, 'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->plot({'x' => $x, 'y' => $y});
        push(@OK, [1, "Plot test X=$x, Y=$y"]);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Plot tests');

subtest 'Line draw tests' => sub {
    print_it($F, 'Line Test');
    for (my $l = $F->{'Y_CLIP'} ; $l < $YY ; $l += 8) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->line({'x' => 0, 'y' => $l, 'xx' => $XX, 'yy' => $l});
        push(@OK, [1, 'Diagonal line test']);
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->line({'x' => 0, 'y' => $l, 'xx' => $l, 'yy' => $F->{'Y_CLIP'}});
        push(@OK, [1, 'Diagonal line test']);
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->line({'x' => $XX, 'y' => $l, 'xx' => $XX - $l, 'yy' => $F->{'Y_CLIP'}});
        push(@OK, [1, 'Rotating line test']);

        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->line({'x' => $XX, 'y' => $YY - $l, 'xx' => $XX - $l, 'yy' => $F->{'Y_CLIP'}});
        push(@OK, [1, 'Vertical line test']);
    } ## end for (my $l = $F->{'Y_CLIP'...})
    for (my $l = 0 ; $l < $XX ; $l += 8) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->line({'x' => $l, 'y' => $F->{'Y_CLIP'}, 'xx' => $l, 'yy' => $YY});
        push(@OK, [1, 'Line test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Line drawing tests');

subtest 'Box frame tests' => sub {
    print_it($F, 'Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box({'x' => rand($XX), 'y' => rand($YY), 'xx' => rand($XX), 'yy' => rand($YY)});
        push(@OK, [1, 'Box test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Box drawing tests');

subtest 'Filled box tests' => sub {
    print_it($F, 'Filled Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box({'x' => rand($XX), 'y' => rand($YY), 'xx' => rand($XX), 'yy' => rand($YY), 'filled' => 1});
        push(@OK, [1, 'Filled box test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled box testing');

subtest 'Gradient Box tests' => sub {
    print_it($F, 'Gradient Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box(
            {
                'x'        => rand($XX),
                'y'        => rand($YY),
                'xx'       => rand($XX),
                'yy'       => rand($YY),
                'filled'   => 1,
                'gradient' => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled box test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient box testing');

subtest 'Rounded box tests' => sub {
    print_it($F, 'Rounded Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box({'x' => rand($XX), 'y' => rand($YY), 'xx' => rand($XX), 'yy' => rand($YY), 'radius' => rand($XX / 16)});
        push(@OK, [1, 'Box with rounded corners test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Rounded box testing');

subtest 'Filled rounded box tests' => sub {
    print_it($F, 'Filled Rounded Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box({'x' => rand($XX), 'y' => rand($YY), 'xx' => rand($XX), 'yy' => rand($YY), 'radius' => rand($XX / 16), 'filled' => 1});
        push(@OK, [1, 'Filled box with rounded corners test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled rounded box testing');

subtest 'Gradient filled rounded box tests' => sub {
    print_it($F, 'Gradient Rounded Box Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->box(
            {
                'x'        => rand($XX),
                'y'        => rand($YY),
                'xx'       => rand($XX),
                'yy'       => rand($YY),
                'radius'   => rand($XX / 16),
                'filled'   => 1,
                'gradient' => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled box with rounded corners test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient filled rounded box testing');

subtest 'Circle frame tests' => sub {
    print_it($F, 'Circle Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->circle({'x' => rand($XX), 'y' => rand($YY), 'radius' => rand($center_y / 2)});
        push(@OK, [1, 'Circle test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Circle frame testing');

subtest 'Filled circle tests' => sub {
    print_it($F, 'Filled Circle Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->circle({'x' => rand($XX), 'y' => rand($YY), 'radius' => rand($center_y / 2), 'filled' => 1});
        push(@OK, [1, 'Filled circle test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled circle testing');

subtest 'Gradient filled circle tests' => sub {
    print_it($F, 'Gradient Circle Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->circle(
            {
                'x'        => rand($XX),
                'y'        => rand($YY),
                'radius'   => rand($center_y / 2),
                'filled'   => 1,
                'gradient' => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled circle test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient filled circle testing');

subtest 'Arc tests' => sub {
    print_it($F, 'Arc Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->arc({'x' => rand($XX), 'y' => rand($YY), 'radius' => rand($center_y / 2), 'start_degrees' => rand(360), 'end_degrees' => rand(360)});
        push(@OK, [1, 'Arc test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Arc testing');

subtest 'Poly Arc tests' => sub {
    print_it($F, 'Poly Arc Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->poly_arc({'x' => rand($XX), 'y' => rand($YY), 'radius' => rand($center_y / 2), 'start_degrees' => rand(360), 'end_degrees' => rand(360)});
        push(@OK, [1, 'Poly Arc test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Poly Arc testing');

subtest 'Filled Pie tests' => sub {
    print_it($F, 'Filled Pie Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->filled_pie({'x' => rand($XX), 'y' => rand($YY), 'radius' => rand($center_y / 2), 'start_degrees' => rand(360), 'end_degrees' => rand(360)});
        push(@OK, [1, 'Filled Pie test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled Pie testing');

subtest 'Gradient filled Pie tests' => sub {
    print_it($F, 'Gradient Filled Pie Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->filled_pie(
            {
                'x'             => rand($XX),
                'y'             => rand($YY),
                'radius'        => rand($center_y),
                'start_degrees' => rand(360),
                'end_degrees'   => rand(360),
                'gradient'      => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled pie test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient filled pie testing');

subtest 'Ellipse frame tests' => sub {
    print_it($F, 'Ellipse Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->ellipse({'x' => rand($XX), 'y' => rand($YY), 'xradius' => rand($center_x / 2), 'yradius' => rand($center_y / 2)});
        push(@OK, [1, 'Ellipse test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Ellipse frame testing');

subtest 'Filled ellipse tests' => sub {
    print_it($F, 'Filled Ellipse Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->ellipse({'x' => rand($XX), 'y' => rand($YY), 'xradius' => rand($center_x / 2), 'yradius' => rand($center_y / 2), 'filled' => 1});
        push(@OK, [1, 'Filled ellipse test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled ellipse testing');

subtest 'Gradient ellipse tests' => sub {
    print_it($F, 'Gradient Ellipse Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->ellipse(
            {
                'x'        => rand($XX),
                'y'        => rand($YY),
                'xradius'  => rand($center_x / 2),
                'yradius'  => rand($center_y / 2),
                'filled'   => 1,
                'gradient' => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled ellipse test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient filled ellipse testing');

subtest 'Polygon frame tests' => sub {
    print_it($F, 'Polygon Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon({'coordinates' => [rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY)]});
        push(@OK, [1, 'Polygon test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Polygon frame testing');

subtest 'Filled polygon tests' => sub {
    print_it($F, 'Filled Polygon Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon({'coordinates' => [rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY)], 'filled' => 1});
        push(@OK, [1, 'Filled polygon test']);
    }
    send_results(@OK);
    @OK = ();
};
ok(1, 'Filled polygon testing');

subtest 'Gradient filled polygon tests' => sub {
    print_it($F, 'Gradient Polygon Test');
    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon(
            {
                'coordinates' => [rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY), rand($XX), rand($YY)],
                'filled'      => 1,
                'gradient'    => {
                    'start' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    },
                    'end' => {
                        'red'   => rand(256),
                        'green' => rand(256),
                        'blue'  => rand(256)
                    }
                }
            }
        );
        push(@OK, [1, 'Gradient filled polygon test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Gradient filled polygon testing');

subtest 'Bezier curve tests' => sub {
    print_it($F, 'Testing Bezier Curves');

    my $s = time + $factor;
    while (time < $s) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        my @coords = ();
        foreach my $c (1 .. int(rand(20) + 3)) {
            push(@coords, int(rand($XX)), int(rand($YY)));
        }
        $F->bezier({'coordinates' => \@coords, 'points' => 100});
        push(@OK, [1, 'Bezier curves test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Bezier curve testing');

TODO: {
    local $TODO = 'Tests may fail if default font is missing';

    subtest 'TrueType rendering tests' => sub {
        print_it($F, 'Testing TrueType Font Rendering (random height/width)');

        my $g = time + $factor;
        while (time < $g) {
            my $h  = max(10, int(rand(300 * $ym)));
            my $ws = ($XX > 255) ? rand(4) : rand(2);

            my $b = $F->ttf_print(
                {
                    'height'       => $h,
                    'wscale'       => $ws,
                    'color'        => sprintf('%02x%02x%02x', int(rand(256)), int(rand(256)), int(rand(256))),
                    'text'         => 'GFB',
                    'bounding_box' => 1,
                    'center'       => 3
                }
            );
            my $ok = 1;
            if (defined($b)) {
                $F->ttf_print($b);
            } else {
                $ok = 0;
            }
            push(@OK, [$ok, 'TrueType Test']);
        } ## end while (time < $g)
        send_results(@OK);

        @OK = ();
    };
    ok(1, 'TrueType rendering testing');
} ## end TODO:

subtest 'Flood fill tests' => sub {
    print_it($F, 'Testing flood fill');
    if ($XX > 255) {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon({'coordinates' => [220 * $xm, 190 * $ym, 1520 * $xm, 80 * $xm, 1160 * $xm, $YY, 960 * $xm, 540 * $ym, 760 * $xm, 1080 * $ym]});
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon({'coordinates' => [1270 * $xm, 570 * $ym, 970 * $xm, 170 * $ym, 600 * $xm, 500 * $ym]});
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->circle({'x' => 500 * $xm, 'y' => 320 * $ym, 'radius' => 100 * $xm});

        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->fill({'x' => 240 * $xm, 'y' => 200 * $ym});
        push(@OK, [1, 'Flood fill test']);
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->fill({'x' => 960 * $xm, 'y' => 440 * $ym});
        push(@OK, [1, 'Flood fill test']);
    } else {
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->polygon({'coordinates' => [$center_x, 3, 3, $YY - 3, $center_x, $center_y, $XX - 3, $YY - 3]});
        $F->set_color({'red' => rand(256), 'green' => rand(256), 'blue' => rand(256)});
        $F->fill({'x' => 3, 'y' => 3});
        push(@OK, [1, 'Flood fill test']);
    } ## end else [ if ($XX > 255) ]
    send_results(@OK);
    @OK = ();
};
ok(1, 'Flood fill tests');

subtest 'Color replace tests with clipping on' => sub {
    print_it($F, 'Testing Color Replace (clipping on)');

    my $x = $F->{'XRES'} / 4;
    my $y = $F->{'YRES'} / 4;
    $F->splash();
    $F->clip_set({'x' => $x, 'y' => $y, 'xx' => $x * 3, 'yy' => $y * 3});
    my $r = 128;
    my $g = 0;
    my $b = 0;
    my $s = time + $factor;
    while (time < $s) {
        my $R = int(rand(256));
        my $G = int(rand(256));
        my $B = int(rand(256));
        $F->replace_color(
            {
                'old_red'   => $r,
                'old_green' => $g,
                'old_blue'  => $b,
                'new_red'   => $R,
                'new_green' => $G,
                'new_blue'  => $B
            }
        );
        ($r, $g, $b) = ($R, $G, $B);
        push(@OK, [1, 'Replace color clipping on test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Color replace testing with clipping on');

subtest 'Color replace tests with clipping off' => sub {
    print_it($F, 'Testing Color Replace (clipping off)');

    $F->splash();

    $F->clip_reset();

    my $r = 128;
    my $g = 0;
    my $b = 0;
    my $s = time + $factor;
    while (time < $s) {
        my $R = int(rand(256));
        my $G = int(rand(256));
        my $B = int(rand(256));
        $F->replace_color(
            {
                'old_red'   => $r,
                'old_green' => $g,
                'old_blue'  => $b,
                'new_red'   => $R,
                'new_green' => $G,
                'new_blue'  => $B
            }
        );
        ($r, $g, $b) = ($R, $G, $B);
        push(@OK, [1, 'Replace color clipping off test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Color replace testing with clipping off');

subtest 'Image Load tests (different sizes)' => sub {
    print_it($F, 'Image load tests (16 bit modes will take longer)');
    my $s = time + ($factor * 3);
    while (time < $s) {
        my $image = $F->load_image(
            {
                'x'      => 0,
                'y'      => 0,
                'width'  => rand($XX),
                'height' => rand($YY),
                'file'   => 'examples/images/testpattern.jpg'
            }
        );
        $F->blit_write($image) if (defined($image));
        push(@OK, [1, 'Image load test']);
    } ## end while (time < $s)
    my $image = $F->load_image(
        {
            'x'      => 0,
            'y'      => 0,
            'width'  => $XX,
            'height' => $YY,
            'file'   => 'examples/images/testpattern.jpg'
        }
    );
    $F->blit_write($image);
    sleep $factor;
    send_results(@OK);
    @OK = ();
};
ok(1, 'Image load testing');

subtest 'Blitting tests' => sub {
    print_it($F, 'Image blitting tests');
    my $w = min(640, $XX / 2);
    my $h = min(405, $YY / 2);
    my $image;
    unless ($w == 640 && $h == 405) {
        $image = $F->load_image(
            {
                'x'      => 0,
                'y'      => 0,
                'width'  => min(640, $XX / 2),
                'height' => min(405, $YY / 2),
                'file'   => 'examples/images/RWBY_Faces.png'
            }
        );
    } else {
        $image = $F->load_image(
            {
                'x'    => 0,
                'y'    => 0,
                'file' => 'examples/images/RWBY_Faces.png'
            }
        );
    } ## end else
    my $s = time + ($factor * 2);
    while (time < $s) {
        $image->{'x'} = rand($XX - $image->{'width'});
        $image->{'y'} = rand($YY - $image->{'height'});
        $F->blit_write($image);
        push(@OK, [1, 'Image load test']);
    } ## end while (time < $s)
    send_results(@OK);
    @OK = ();
};
ok(1, 'Blitting Testing');

$F->cls();

exit(0);

sub print_it {
    my $fb      = shift;
    my $message = shift;

    $fb->normal_mode();
    $fb->clip_reset();
    $fb->cls();

    $fb->or_mode();

    my $b = $fb->ttf_print(
        {
            'x'            => 5 * $xm,
            'y'            => max(10, 20 * $ym),
            'height'       => max(10, 20 * $ym),
            'color'        => '00FF00',
            'text'         => $message,
            'bounding_box' => 1,
            'center'       => $fb->{'CENTER_X'},
            'antialias'    => 1
        }
    );
    $fb->ttf_print($b);
    $fb->clip_set({'x' => 0, 'y' => $b->{'pheight'}, 'xx' => $XX, 'yy' => $YY});
    $fb->normal_mode();
} ## end sub print_it

sub send_results {
    my @ok = @_;

    foreach my $ok (@ok) {
        ok(@{$ok});
    }
} ## end sub send_results

__END__

