
use strict;
use warnings;
use Xchat qw(:all);

no warnings 'qw';
my %networks = (
	':all'      => sub { command( "charset UTF-8" ); },
	':password' => sub { command( 'ns identify ...',  ) },
	freenode    => {
		actions => [
			qw(:password)
		],

		post_identify_actions => [
			sub {
				command "RECV :s 005 Khisanth NETWORK=FreeNode";
				command "UMODE +Q";
			},
		],
		channels => [
			qw(#perl #xchat)
		],
	},
);

register( "AutoJoin", "1.0001_01" );
hook_command( "ident", \&identify );

hook_server( "001", \&connected );

sub identify {
	my $network = get_network();
	return EAT_ALL unless
		grep { $_ eq ':password' } @{$networks{$network}{actions}};

	$networks{ ':password' }->();
	return EAT_ALL;
}

sub connected {
	$networks{ ':all' }->() if $networks{ ':all' };

	my $network = get_network();

	if( $networks{ $network } ) {
		my $wait_for_nickserv = run_actions( $network );	

		if( $wait_for_nickserv ) {
			my ($timer_hook, $print_hook);

			my $join_delay = get_prefs "irc_join_delay";
			$join_delay ||= 5;
			$join_delay *= 1_000;

			$timer_hook = hook_timer( $join_delay, sub {
				run_post_identify_actions( $network );
				unhook( $print_hook );
				return REMOVE;
			});

			$print_hook = hook_print( "Notice", sub {
				my ($who, $what) = @{$_[0]};

				if( get_network() eq $network
					&& !nickcmp($who, 'NickServ')
					&& $what =~ /identified/i ) {
					run_post_identify_actions( $network );
					unhook( ${$_[1]} ); # remove this hook
					unhook( $timer_hook );
					
				}
				return EAT_NONE;
			}, { data => \$print_hook } );
		} else {
			join_channels( $network );
		}
	}

	return EAT_NONE;
}

sub execute_action {
	my ( $action, $network ) = @_;
	if( ref $action ) {
		$action->();
	} elsif( $action =~ /^:/ && $networks{ $network }{ $action } ) {
		$networks{ $network }{ $action }->();
	} elsif( $action =~ /^:/ && $networks{ $action } ) {
		$networks{ $action }->();
	} else {
		prnt "Error: No such action defined '$action'\n";
	}
}

sub run_actions {
	my $network = shift;

	my $wait_for_nickserv = 0;
	my $actions = $networks{ $network }{ actions };
	
	for my $action ( @{ $actions || [] } ) {
		execute_action( $action, $network );
		$wait_for_nickserv = 1 if $action eq ':password';
	}

	return $wait_for_nickserv;
}
sub run_post_identify_actions {
	my $network = shift;
	
	my $actions = $networks{ $network }{ post_identify_actions };
	for my $action ( @{ $actions || [] } ) {
		execute_action( $action, $network );
	}

	join_channels( $network );
}

sub join_channels {
	my $network = shift;

	my @channels = @{$networks{ $network }{ channels }};
	my @pending_channels = @channels;

	my $max_length = max_length();

	my $join_string = "";
	while( @pending_channels ) {
		if( length( "$join_string,$pending_channels[0]" ) <= $max_length ) {
			$join_string .= "," . shift @pending_channels;
		} else {
			command( "JOIN $join_string" );
			$join_string = "";
		}
	}

	command( "JOIN $join_string" ) if $join_string;
}

sub max_length {
	my $max = 512;

	$max -= 13;
	$max -= length get_info "nick";
	
	$max -= 9;
	$max -= 65;

}

sub get_network {
	return lc(get_info( "network" ) || ( split /\./, get_info( "host" ) )[-2]);
}
