The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use UAV::Pilot::Exceptions;
use UAV::Pilot::Video::FileDump;
use UAV::Pilot::ARDrone::Video;
use UAV::Pilot::Events;

our $dev = undef;

{
    my @NO_ARG_STRAIGHT_COMMANDS = qw(
        takeoff
        land
        calibrate
        phi_m30
        phi_30
        theta_m30
        theta_30
        theta_20deg_yaw_200
        theta_20deg_yaw_m200
        turnaround
        turnaround_godown
        yaw_shake
        yaw_dance
        phi_dance
        theta_dance
        vz_dance
        wave
        phi_theta_mixed
        double_phi_theta_mixed
        flip_ahead
        flip_behind
        flip_left
        flip_right
        emergency
        hover
        start_userbox_nav_data
        stop_userbox_nav_data
        cancel_userbox_nav_data
    );
    foreach my $name (@NO_ARG_STRAIGHT_COMMANDS) {
        no strict 'refs';
        *$name = sub () {
            $dev->$name;
        };
    }
}

{
    my @SINGLE_ARG_STRAIGHT_COMMANDS = qw(
        pitch
        roll
        yaw
        vert_speed
    );
    foreach my $name (@SINGLE_ARG_STRAIGHT_COMMANDS) {
        no strict 'refs';
        *$name = sub ($) {
            $dev->$name( @_ );
        };
    }
}

{
    my @TWO_ARG_STRAIGHT_COMMANDS = qw(
        led_blink_green_red
        led_blink_green
        led_blink_red
        led_blink_orange
        led_snake_green_red
        led_fire
        led_standard
        led_red
        led_green
        led_red_snake
        led_blank
        led_right_missile
        led_left_missile
        led_double_missile
        led_front_left_green_others_red
        led_front_right_green_others_red
        led_rear_right_green_others_red
        led_rear_left_green_others_red
        led_left_green_right_red
        led_left_red_right_green
        led_blink_standard
    );
    foreach my $name (@TWO_ARG_STRAIGHT_COMMANDS) {
        no strict 'refs';
        *$name = sub ($$) {
            $dev->$name( @_ );
        };
    }
}

sub take_picture ($$;$)
{
    $dev->take_picture( @_ );
}

sub record_usb ()
{
    $dev->record_usb;
}

{
    my $cv          = undef;
    my $events      = undef;
    my $easy_events = undef;
    my $init_events = sub {
        return 1 if defined $events;
        die "Can't init UAV::Pilot::Events without a condvar\n" unless defined $cv;

        $events = UAV::Pilot::Events->new({
            condvar => $cv,
        });
        $easy_events = UAV::Pilot::EasyEvent->new({
            condvar => $cv,
        });
        $dev->setup_read_nav_event( $easy_events );
        $events->init_event_loop;
        $easy_events->init_event_loop;

        # If we can load SDL, then init it here
        eval "use UAV::Pilot::SDL::Events";
        if(! $@ ) {
            my $sdl_events = UAV::Pilot::SDL::Events->new;
            $events->register( $sdl_events );
        }

        $dev->init_event_loop( $cv, $easy_events );
        return 1;
    };

    my $sdl = undef;
    my $init_sdl = sub {
        return 1 if defined $sdl;
        eval "use UAV::Pilot::SDL::Window;";
        die "Can't use UAV::Pilot::SDL::Window: $@\n" if $@;

        $init_events->();
        $sdl = UAV::Pilot::SDL::Window->new;
        $events->register( $sdl );
        return 1;
    };

    my $vid_driver = undef;
    my $init_vid_driver = sub {
        return 1 if defined $vid_driver;

        $vid_driver = UAV::Pilot::ARDrone::Video->new({
            condvar => $cv,
            driver  => $dev->driver,
        });
        $vid_driver->init_event_loop;
        $dev->video( $vid_driver );

        return 1;
    };


    sub uav_module_init
    {
        my ($class, $cmd, $args) = @_;
        $cv  = $$args{condvar};

        $easy_events = UAV::Pilot::EasyEvent->new({
            condvar => $cv,
        });
        $easy_events->init_event_loop;

        $dev = $cmd->controller_callback_ardrone->(
            $cmd, $cv, $easy_events );
        return 1;
    }


    sub start_joystick ()
    {
        $init_events->();
        eval "use UAV::Pilot::SDL::Joystick";
        die "Problem loading UAV::Pilot::SDL::Joystick: $@\n" if $@;

        my $joystick = UAV::Pilot::SDL::Joystick->new({
            condvar => $cv,
            events  => $easy_events,
        });
        $events->register( $joystick );

        say 'Ready for joystick input on ['
            . SDL::Joystick::name( $joystick->joystick->index )
            . ']';

        return 1;
    }

    sub start_nav ()
    {
        eval "use UAV::Pilot::ARDrone::SDLNavOutput";
        die "Problem loading UAV::Pilot::ARDrone::SDLNavOutput: $@\n" if $@;
        $init_sdl->();
        $init_events->();

        my $nav = UAV::Pilot::ARDrone::SDLNavOutput->new({
            feeder => $dev,
        });
        $dev->driver->add_nav_collector( $nav );
        $nav->add_to_window( $sdl, $sdl->BOTTOM );

        say "Outputting navigation data";

        return 1;
    }

    sub start_video ()
    {
        $init_events->();
        $init_sdl->();
        $init_vid_driver->();
        eval "use UAV::Pilot::SDL::Video";
        die "Problem loading UAV::Pilot::SDL::Video: $@\n" if $@;
        eval "use UAV::Pilot::Video::H264Decoder";
        die "Problem loading UAV::Pilot::Video::H264Decoder: $@\n" if $@;

        my $display = UAV::Pilot::SDL::Video->new;
        my $video   = UAV::Pilot::Video::H264Decoder->new({
            displays => [ $display ],
        });
        $vid_driver->add_handler( $video );
        $display->add_to_window( $sdl, $sdl->TOP );

        say "Ouputting video";
        return 1;
    }

    sub dump_video_to_file ($)
    {
        my ($file) = @_;
        $init_vid_driver->();

        open( my $fh, '>', $file ) or UAV::Pilot::IOException->throw({
            error => "Can't open [$file] for reading: $!\n",
        });
        my $vid_dump = UAV::Pilot::Video::FileDump->new({
            fh => $fh,
        });

        $vid_driver->add_handler( $vid_dump );
        say "Dumping video to file '$file'";
        return 1;
    }
}


1;