#!/usr/bin/env perl

use strict;
use warnings;
use App::Pocoirc;
use Getopt::Long qw(:config autohelp no_ignore_case);
use Pod::Usage;

my %args;
GetOptions(
    # program options
    'c|check'      => \$args{check_cfg},
    'f|config=s'   => \$args{cfg_file},
    'v|verbose'    => \$args{verbose},
    'd|daemonize'  => \$args{daemonize},
    'N|no-color'   => \$args{no_color},

    # global config options
    'I|lib=s@'     => \$args{lib},
    'l|log-file=s' => \$args{log_file},

    # network-specific config options
    '6|ipv6'       => \$args{ipv6},
    'S|ssl'        => \$args{ssl},
    'C|class=s'    => \$args{class},
    's|server=s'   => \$args{server},
    'n|nick=s'     => \$args{nick},
    'u|username=s' => \$args{username},
    'i|ircname=s'  => \$args{ircname},
    'j|join=s@'    => \$args{chan_specs},
    'p|plugin=s@'  => \$args{plugin_specs},
    'V|version'    => sub {
        no strict 'vars';
        my $version = defined $App::Pocoirc::VERSION
            ? $App::Pocoirc::VERSION
            : 'dev-git';
        print "Version $version\n";
        exit;
    },
) or pod2usage();

my $procname = 'pocoirc';
$0 = $procname;
if ($] < 5.013000 && $^O eq 'linux') {
    local $@;
    eval {
        require Sys::Prctl;
        Sys::Prctl::prctl_name($procname);
    };
}

my $config;
if (defined $args{cfg_file}) {
    if ($args{cfg_file} =~ /\.yml$/i) {
        require YAML::XS;
        YAML::XS->import('LoadFile');

        eval { $config = LoadFile($args{cfg_file}) };

        if ($@) {
            chomp $@;
            die "Failed to read YAML data from $args{cfg_file}: $@\n"
        }
        if (ref $config ne 'HASH') {
            die "YAML data in $args{cfg_file} should be a hash\n";
        }
    }
    elsif ($args{cfg_file} =~ /\.json$/i) {
        require JSON::XS;
        JSON::XS->import('decode_json');

        open my $fh, '<', $args{cfg_file} or die "Can't open $args{cfg_file}: $!\n";
        my $json = do { local $/; <$fh> };

        eval { $config = decode_json($json) };
        if ($@) {
            chomp $@;
            die "Failed to read JSON data from $args{cfg_file}: $@\n"
        }
        if (ref $config ne 'HASH') {
            die "JSON data in $args{cfg_file} be a hash\n";
        }
    }
    else {
        die "Config file format not supported, it must be YAML or JSON\n";
    }
}
else {
    my @plugins;
    if ($args{plugin_specs} && @{ $args{plugin_specs} }) {
        require JSON::XS;
        JSON::XS->import('decode_json');

        for my $plugspec (@{ $args{plugin_specs} }) {
            my ($class, $json) = $plugspec =~ /^([:A-Za-z0-9]+)\s*(.+)?/;
            die "Missing plugin class for option --plugin\n" if !defined $class;

            my $plug_args;
            if (defined $json) {
                eval { $plug_args = decode_json($json) };
                if ($@) {
                    chomp $@;
                    die "Invalid JSON argument for plugin $class: $@\n"
                }
                if (ref $plug_args ne 'HASH') {
                    die "JSON argument for plugin $class should be a hash\n";
                }
            }

            push @plugins, [$class, $plug_args];
        }
    }

    # process -j arguments
    if ($args{chan_specs}) {
        my %chans;
        for my $chanspec (@{ $args{chan_specs} }) {
            my ($chan, $pass) = split /:/, $chanspec, 2;
            $chans{$chan} = $pass;
        }
        push @plugins, ['AutoJoin', { Channels => \%chans }];
    }

    $config = {
        (map { defined $args{$_} ? ($_ => $args{$_}) : () } qw(lib log_file)),
        networks => [
            {
                name => 'default',
                local_plugins => \@plugins,
                (map {
                    defined $args{$_} ? ($_ => $args{$_}) : ()
                } qw(class server nick username ircname ipv6 ssl)),
            }
        ],
    };
}

App::Pocoirc->new(
    cfg       => $config,
    (map {
        defined $args{$_} ? ($_ => $args{$_}) : ()
    } qw(check_cfg daemonize verbose no_color))
)->run();

=encoding utf8

=head1 NAME

pocoirc - A command line tool for launching
L<POE::Component::IRC|POE::Component::IRC> clients

=head1 SYNOPSIS

B<pocoirc> <options>

 Options:
   -c, --check                  Check if config is valid and code compiles
   -f FOO, --config FOO         Use config file FOO
   -d, --daemonize              Run in the background
   -v, --verbose                Show IRC protocol messages
   -N, --no-color               Don't use terminal colors
   -V, --version                Print version
   -h, --help                   Print this usage message

 When not using a config file, you can use these:
   -s FOO, --server FOO         Connect to server FOO
   -n FOO, --nickname FOO       Use nickname FOO
   -u FOO, --username FOO       Use username FOO
   -i FOO, --ircname FOO        Use ircname FOO
   -j CHANNEL --join CHANNEL    Join a channel (see below)
   -p PLUGIN, --plugin PLUGIN   Load plugin PLUGIN (see below)
   -6, --ipv6,                  Use IPv6
   -S, --ssl,                   Use SSL
   -C FOO, --class FOO          E.g. POE::Component:IRC::Qnet::State
   -I FOO, --lib FOO            A Perl library directory to include
   -l, --log-file               Write status messages to this log file

 CHANNEL mentioned above can be a channel name (e.g. '#foo') or a channel
 name and a password separated by a colon (e.g. '#foo:bar'). If you specify
 any channels, an AutoJoin plugin with these parameters will be added to
 your IRC component.

 PLUGIN mentioned above should consist of the short class name, zero or
 more whitespace, and possibly a JSON hash of arguments to the plugin's
 constructor:

  -p AutoJoin
  -p 'AutoJoin{"ReJoinOnKick":0}'
  -p 'AutoJoin{"ReJoinOnKick":0,"Channels":["#foo","#bar"]}'
  -p 'AutoJoin {"ReJoinOnKick": 0, "Channels": ["#foo", "#bar"]}'

 For documentation on the configuration file, do "perldoc App::Pocoirc"

=head1 AUTHOR

Hinrik E<Ouml>rn SigurE<eth>sson, hinrik.sig@gmail.com

=head1 LICENSE AND COPYRIGHT

Copyright 2010 Hinrik E<Ouml>rn SigurE<eth>sson

This program is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut
