#!/usr/bin/perl
use v5.14;
use AnyEvent::ReadLine::Gnu;
use UAV::Pilot;
use UAV::Pilot::Commands;
use UAV::Pilot::ARDrone::Driver;
use UAV::Pilot::ARDrone::Control::Event;
use Getopt::Long qw( :config no_ignore_case );

my $IP               = '192.168.1.1';
my $PROMPT           = 'uav> ';
my $MULTILINE_PROMPT = "\t";
my @LIB_PATHS        = ();
my @LIBS             = ();
my $IFACE            = undef;
GetOptions(
    'host=s'      => \$IP,
    'i|iface=s'   => \$IFACE,
    'l|load=s'    => \@LIBS,
    'L|library=s' => \@LIB_PATHS,
);


sub run_cmd
{
    my ($cmd, $repl) = @_;
    my $return = 1;
    if( $cmd =~ /\A(?: exit | quit | q ) \s*;\s*\z/x ) {
        $return = 0;
    }
    else {
        eval {
            $repl->run_cmd( $cmd );
        };
        warn $@ if $@;
    }

    return $return;
}

sub load_libraries
{
    my ($repl, $lib_paths, $libs, $cv) = @_;

    $repl->add_lib_dir( $_ ) for @$lib_paths;
    $repl->add_lib_dir( UAV::Pilot->default_module_dir );

    print "Library paths:\n" . join( "\n", map { "\t$_" } @{ $repl->lib_dirs } ) . "\n";
    foreach my $lib (@$libs) {
        print "Loading library '$lib' . . . ";
        $repl->load_lib( $lib, {
            condvar => $cv,
        });
        print "OK\n";
    }

    print "\n";
    return 1;
}

{
    my @cmd = ();

    sub add_cmd
    {
        my ($cmd) = @_;
        push @cmd => $cmd;
        return 1;
    }

    sub full_cmd
    {
        my $cmd = join( ' ', @cmd );
        @cmd = ();
        return $cmd;
    }
}


{
    my $continue = 1;

    my $driver_args = {
        host => $IP,
    };
    $driver_args->{iface} = $IFACE if defined $IFACE;

    my $ardrone = UAV::Pilot::ARDrone::Driver->new( $driver_args );
    $ardrone->connect;

    my $dev = UAV::Pilot::ARDrone::Control::Event->new({
        driver => $ardrone,
    });
    my $cv = $dev->init_event_loop;
    my $repl = UAV::Pilot::Commands->new({
        device  => $dev,
        condvar => $cv,
    });
    load_libraries( $repl, \@LIB_PATHS, \@LIBS, $cv );

    my $readline; $readline = AnyEvent::ReadLine::Gnu->new(
        prompt => $PROMPT,
        on_line => sub {
            my ($line) = @_;
            add_cmd( $line );
            if( $line =~ /; \s* \z/x ) {
                my $cmd = full_cmd;
                $readline->hide;
                my $do_continue = run_cmd( $cmd, $repl );
                $readline->show;

                $cv->send( $do_continue ) unless $do_continue;
            }
        },
    );

    $cv->recv;
}

__END__


=head1 SYNOPSIS

    uav \
        --host 192.168.1.1 \
        -L /path/to/libraries
        -l ARDrone

=head1 DESCRIPTION

Launches a shell for controlling a UAV.  Perl statements may be typed at the prompt, ending 
with a semi-colon.  With the Parrot AR.Drone, try:

    uav> takeoff;
    uav> pitch -0.5;
    uav> wave;
    uav> land;

=head1 OPTIONS

=head2 --host

Host IP to connect to.  Out of the box, the Parrot AR.Drone will be its own wireless 
access point on IP 192.168.1.1 (which is the default here).

=head2 -L or --library

Path to library modules.  May be specified multiple times.  By default, this will be the
dist shared dir returned by L<File::ShareDir> for L<UAV::Pilot>.

=head2 -l or --load

Library to load.  May be specified multiple times.  It will need to be under one of the 
directories specified by the C<--library> option (or the default library path).

=cut
