package XXV::MODULES::ROBOT;
use strict;

use Tools;
use Event::File;
use Locale::gettext;
use WWW::Mechanize;
use WWW::Mechanize::FormFiller;

$SIG{CHLD} = 'IGNORE';

# This module method must exist for XXV
# ------------------
sub module {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $args = {
        Name => 'ROBOT',
        Description => gettext('This module register and run robots to fetch data from internet.'),
        Version => '0.01',
        Date => '06.09.2004',
        Author => 'xpix',
        Preferences => {
            active => {
                description => gettext('Activate this service'),
                default     => 'y',
                type        => 'confirm',
                required    => gettext('This is required!'),
            },
        },
        Commands => {
            robot => {
                description => gettext("Start a robots 'rname'"),
                short       => 'ro',
                callback    => sub{ $obj->start(@_) },
            },
        },
    };
    return $args;
}

# ------------------
sub new {
# ------------------
	my($class, %attr) = @_;
	my $self = {};
	bless($self, $class);

    # paths
    $self->{paths} = delete $attr{'-paths'};

	# who am I
    $self->{MOD} = $self->module;

    # read the DB Handle
    $self->{dbh} = delete $attr{'-dbh'};

    # all configvalues to $self without parents (important for ConfigModule)
    map {
        $self->{$_} = $attr{'-config'}->{$self->{MOD}->{Name}}->{$_} || $self->{MOD}->{Preferences}->{$_}->{default}
    } keys %{$self->{MOD}->{Preferences}};

	return $self;
}

# ------------------
sub saveRobot {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $rname = shift || return error ('No robot Name!' );
    my $rsub = shift || return error ('No Robot sub!' );

    return error("$rname is not a Code Reference!'")
        unless(ref $rsub eq 'CODE');

    $obj->clean( $rname );
    $obj->{robots}->{$rname} = $rsub;
    return $obj->{robots}->{$rname};
}

# ------------------
sub register {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $rname = shift || return error ('No robot Name!' );
    my @args = @_;

    return error("$rname is not a Robot!'")
        unless(ref $obj->{robots}->{$rname} eq 'CODE');

    push(@{$obj->{jobs}->{$rname}}, [@args]);
}

# ------------------
sub start {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $rname = shift || return error ('No Robot Name to start!');
    my $watcher = shift;
    my $console = shift;
    my $endcb   = shift;

    lg sprintf('Start Robots ....');

    unless(exists $obj->{jobs}->{$rname}) {
        return error("No Robot with name $rname is registered!");
    }

    # fork and forget
    defined(my $child = fork()) or die "Can't fork: $!";
    if($child == 0) {
        $obj->{dbh}->{InactiveDestroy} = 1;
        # create a new browser
        my $agent = WWW::Mechanize->new( autocheck => 1 );
        my $formfiller = WWW::Mechanize::FormFiller->new();

        foreach my $args (@{$obj->{jobs}->{$rname}}) {
            my ($result, $error);
            lg sprintf('Start Robot %s ....', $rname);
            eval {
                ($result, $error) = &{$obj->{robots}->{$rname}}($agent, $formfiller, @$args);
            };
            $error = $@ if($@);
            if($result) {
                warn sprintf("Robot %s sucsessfully!", $rname);
            } else {
                warn sprintf("%s in %s!", $error, $rname);
            }
        }
        &$endcb()
            if(ref $endcb eq 'CODE');
        exit(0);
    }
}

# ------------------
sub clean {
# ------------------
    my $obj = shift  || return error ('No Object!' );
    my $rname = shift || return error ('No Robot Name to clean!');
    delete $obj->{jobs}->{$rname};
}


# ------------------
sub result {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $rname = shift || return error ('No robot Name!' );

    return $obj->{result}->{$rname};

}

# ------------------
sub status {
# ------------------
    my $obj = shift || return error ('No Object!' );
    my $watcher = shift;
    my $console = shift;
    my $rname = shift;

    return 1 unless(ref $console);

    if($rname) {
        $console->table($obj->{result}->{$rname});
    } else {
        $console->table($obj->{result});
    }
}



1;
