#!/usr/bin/env perl

# mcrcon - Commandline interface to Minecraft::RCON
#
# Ryan Thompson <rjt@cpan.org>

use strict;
use warnings;
use 5.010;

use Minecraft::RCON;
use Getopt::Long;
use Pod::Usage;
use Term::ANSIColor;

our $VERSION = '1.01_03';

my %o = get_options();
my %PERMITTED = map { $_ => 1 } qw< address port password >;
my %rcon_opts = map { $_ => $o{$_} } grep { $PERMITTED{$_} } keys %o;
my $next_id = 1;

my $rcon = Minecraft::RCON->new(%rcon_opts, color_mode => 'ignore');
die "Connection failed: " . $rcon->error unless $rcon->connect;

my @commands = @{$o{command} || []};
push @commands, join(' ', @ARGV) if @ARGV;

run_command($_) for @commands;
console() if $o{stdin} or @commands == 0;

$rcon->disconnect;

# Act like a console
sub console {
    while ( my $cmd = <STDIN> ) {
        $cmd =~ s/(^\s+|\s+$)//g; # Trim
        next unless length $cmd;
        last if $cmd =~ /^(exit|quit)$/;
        run_command($cmd);
    }
}

# Run the command and display the output, echoing if so configured
sub run_command {
    my $reset = color('reset');
    printf "%s%s$reset\n", ps1(), $_[0] if $o{ansi} and $o{echo};

    say "> $_[0]" if $o{echo} and not $o{ansi};
    print $reset if $o{ansi};

    my $r = $rcon->command($_[0], 'ignore');
    $r =~ s/[\r\n]/\n/g;

    my $strip = $rcon->color_convert($r, 'strip');
    my $conv = $rcon->color_convert($r, 'convert');
    say length $strip ? $conv : '[Command sent]';
    $next_id++;

}

# Return a hash of the commandline and config options
sub get_options {
    my %o = (
        help        => sub { pod2usage -verbose => 1 },
        tty         => -t STDOUT ? 1 : 0,
        version     => sub { say "mcrcon version $VERSION"; exit; },
    );
    GetOptions(\%o, qw<address|hostname=s port=i password=s
        command|cmd=s@ stdin ansi color_mode|color-mode
        echo help version tty>
    ) or pod2usage(2);
    $o{ansi} //= $o{tty};
    $o{color_mode} = $o{ansi} ? 'convert' : 'strip';

    %o;
}

__END__

=head1 NAME

mcrcon - RCON interface for Minecraft servers

=head1 SYNOPSIS

B<mcrcon> --pass=password [options] command

B<mcrcon> --pass=password [options] --command='cmd1' ...

=head1 OPTIONS

 --host=host        Hostname to connect to          [127.0.0.1]
                    --address, --addr, --hostname are aliases
 --port=port        Port number                         [25575]
 --password=pass    Password
 --color_mode=mode  One of convert, strip, ignore     [convert]
 --command=cmd      Command to run. May repeat.
                    --cmd is an alias
 --stdin            Read from stdin, even if commands given
 --echo             Echo the commands themselves to stdout
 --tty              Force TTY behavior, even if not detected
 -v|--version       Display version number and exit

Any remaining arguments on the commandline will be concatenated
together and interpreted as a single command, as you might expect.

=head1 DESCRIPTION

I<mcrcon> provides a commandline interface to interact with a Minecraft
server using the RCON protocol. You may specify commands via commandline
options, or via standard input. Additionally, when using C<stdin>, and
I<mcrcon> is running from a TTY, you will have a console-like interface
with readline support, command history, and help.

=head1 OPTION DETAILS

=over 4

=item --host=E<lt>hostE<gt>

The hostname or IP address of the Minecraft server.

=item --port=E<lt>portE<gt>

The TCP port number to connect to. Default is the usual RCON port number, 25575.
This must match the port number defined in your Minecraft server's
C<server.properties> file:

    rcon.port=25575

=item --password=E<lt>passwordE<gt>

The password required to connect to the Minecraft RCON. This is defined in
your Minecraft server's C<server.properties> file:

    rcon.password=

Note that the password must not be blank. A blank password defined in
C<server.properties> means that RCON is disabled on your server.

=item color_mode=convert|strip|ignore

The color mode for command responses. Normally color codes are C<convert>ed
from the Minecraft escape sequences to ANSI, so they will display properly on
a terminal. If you are filtering or otherwise processing the output, you may
wish to set C<--color_mode=strip>, to strip all color sequences entirely.
Finally, you can set C<--color_mode=ignore> to pass the Minecraft color
sequences through unmodified.

=item --stdin

Even if a Minecraft command is given on the command line, read additional
commands from standard input.

=item --echo

Echo commands themselves to standard output

=item --tty

Force TTY (terminal) behavior, even if a TTY is not detected.

=item -v | --version

Display version number and exit.

=item --help

Display usage summary and exit.

=back
