#**************************************************************************
#   Copyright (C) 2009 by Michael Andreen <harvATruinDOTnu>               *
#                                                                         *
#   This program is free software; you can redistribute it and/or modify  *
#   it under the terms of the GNU General Public License as published by  *
#   the Free Software Foundation; either version 2 of the License, or     *
#   (at your option) any later version.                                   *
#                                                                         *
#   This program is distributed in the hope that it will be useful,       *
#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#   GNU General Public License for more details.                          *
#                                                                         *
#   You should have received a copy of the GNU General Public License     *
#   along with this program; if not, write to the                         *
#   Free Software Foundation, Inc.,                                       *
#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
#**************************************************************************/

package NDIRC::Dispatcher;
use strict;
use warnings;
use feature ':5.10';

use Moose;
use Moose::Exporter;
use Set::Object ();

use NDIRC::Command;

Moose::Exporter->setup_import_methods(
	as_is => [ 'command' ]
);



has commands => (
	is => 'ro',
	isa => 'HashRef[Object]',
	default => sub{ {} },
);

has channels => (
	is => 'ro',
	isa => 'HashRef[ArrayRef[Str]]',
	default => sub{ {} },
);


my $DISP;

sub load {
	my $self = shift;

	$DISP = $self;

	for (@_){
		my $file = "NDIRC/Commands/$_.pm";

		unless (my $return = do $file){
			warn "couldn't parse $file: $@" if $@;
			warn "couldn't do $file: $!"    if $!;
			warn "couldn't run $file"       unless $return;
		}
	}
	$DISP = undef;
}

sub command ($$$) {
	my ($c,$a,$class) = @_;
	my %c = %{$a};
	my @aliases;
	if (exists $c{alias}){
		@aliases = @{$c{alias}} if ref $c{alias} eq 'ARRAY';
		push @aliases, $c{alias} if ref $c{alias} eq '';
	}
	push @aliases, $c;
	say "Command: (@aliases)";
	for my $a (@aliases){
		$c{name} = $a;
		my $co = $class->new_object(\%c);
		$DISP->commands->{$a} = $co;
	}
}

sub add_channel {
	my ($self,$channel,$types) = @_;

	$types = Set::Object->new(@{$types});
	$types->insert('universal');
	$self->channels->{lc $channel} = $types;
}

sub has_command {
	my ($self,$command,$channel) = @_;
	$channel = lc $channel;

	return 0 unless defined $command && defined $channel;
	return 0 unless exists $self->commands->{$command};
	$command = $self->commands->{$command};
	return 1 if $command->type eq 'universal';
	return 0 unless exists $self->channels->{$channel};

	return $self->channels->{$channel}->has($command->type);
}

sub run_command {
	my ($self,$c,$command,$args) = @_;

	return 0 unless exists $self->commands->{$command};
	my $acl = $self->commands->{$command}->acl;
	return 0 if $acl && !$c->check_user_roles($acl);

	$args //= '';

	eval {
		$self->commands->{$command}->execute($c,$args)
	};
	if ($@){
		given ($@){
			when(/^ARGS/){
				$c->reply($c->disp->commands->{$command}->help);
			}
			default {
				$c->reply("Something went wrong. If it is not temporary, please report it. '$_'");
			}
		}
	}
	return 1;
}

1;
