#!/usr/bin/perl -w

use strict;
use IO::Socket;

use Gtk2 -init;
use Glib qw/TRUE FALSE/;
use Gtk2::Helper;
use Gtk2::Pango;
use Gtk2::Gdk::Keysyms;

my ($who) = $ARGV[0];
#check and warn if we received wrong argument
unless(($who)&&($who =~ m/shrek|donkey/)){
print "usage <program name> <shrek | donkey>\n";
exit;
}

my($sock,$MAXLEN, $LISTEN_PORT, $SEND_PORT,$tag_send,$tag_receive,$img_big,$img_send,$img_rec);
$MAXLEN = 1024;

#set the variables up if you are shrek:
if ($who =~ m/shrek/){

	$LISTEN_PORT 	= 5151;
	$SEND_PORT 	= 5152;
	$tag_send	= 'shrek';
	$tag_receive 	= 'donkey';
	$img_big 	= './pix/shrek.gif';
	$img_send 	= './pix/shrek_small.jpg';
	$img_rec 	= './pix/donkey_small.gif';
	
}

#set the variables up if you are donkey:
if ($who =~ m/donkey/){

	$LISTEN_PORT 	= 5152;
	$SEND_PORT 	= 5151;
	$tag_send	= 'donkey';
	$tag_receive 	= 'shrek';
	$img_big 	= './pix/donkey.gif';
	$img_send 	= './pix/donkey_small.gif';
	$img_rec 	= './pix/shrek_small.jpg';
}

my $tview;
	
#---------------------------------
#set up a udp server waiting for incomming messages
$sock = IO::Socket::INET->new(LocalPort => $LISTEN_PORT, Proto => 'udp')
or die "socket: $@";

#add a Gtk2::Helper watch on any incomming connections
Gtk2::Helper->add_watch ( fileno $sock, 'in',sub{ 
	my ($fd,$condition,$fh) = @_;
	#call 'watch_callback' to handle the incomming data	
	\&watch_callback($fh,$tview);
	},$sock);
	
print "Awaiting UDP messages on port $LISTEN_PORT\n";
#---------------------------------

#Gtk2::Rc->parse ('/usr/share/themes/Anger/gtk/gtkrc');
#this is parsing our theme file, giving a personal touch
Gtk2::Rc->parse ('gtkrc');

#standard window creation, placement, and signal connecting
my $window = Gtk2::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { exit;});
$window->set_border_width(5);
$window->set_position('center_always');
#again just some fine touches
$window->set_title("I am $tag_send");
$window->set_icon_from_file($img_send);

#this vbox will geturn the bulk of the gui
my ($vbox) = &ret_vbox();

#add and show the vbox
$window->add($vbox);
$window->show();

#our main event-loop
Gtk2->main();

sub ret_vbox {

my $vbox = Gtk2::VBox->new(FALSE,0);
	#add an image to indicate who you are
	my $img_who = Gtk2::Image->new_from_file($img_big);

$vbox->pack_start($img_who,TRUE,TRUE,0);

	my $frame = Gtk2::Frame->new("Simple Chat - I am $tag_send");
		
	#method of Gtk2::Container
	$frame->set_border_width(5);
	
		my $sw = Gtk2::ScrolledWindow->new (undef, undef);
    		$sw->set_shadow_type ('etched-out');
		$sw->set_policy ('automatic', 'automatic');
		#This is a method of the Gtk2::Widget class,it will force a minimum 
		#size on the widget. Handy to give intitial size to a 
		#Gtk2::ScrolledWindow class object
		$sw->set_size_request (300, 300);
		#method of Gtk2::Container
		$sw->set_border_width(5);
		
			$tview = Gtk2::TextView->new();
			#we do not want to edit anything
			$tview->set_editable(FALSE);
			$tview->set_cursor_visible (FALSE);
							
  			my $buffer = $tview->get_buffer();
			
			#create a mark at the end of the buffer, and on each
			#'insert_text' we tell the textview to scroll to that mark
			$buffer->create_mark ('end', $buffer->get_end_iter, FALSE);
			$buffer->signal_connect (insert_text => sub {
				$tview->scroll_to_mark ($buffer->get_mark ('end'),
	                        0.0, TRUE, 0, 0.5);
			});
			
			#create a tag for the shreck		
			$buffer->create_tag ("shrek",
					style =>'italic',
					weight => PANGO_WEIGHT_ULTRALIGHT,
					family => 'flubber',
					foreground => "#189f3b",
					size => 20000,
					);
					
			#create a tag for the donkey		
			$buffer->create_tag ("donkey",
					style =>'italic',
					weight => PANGO_WEIGHT_ULTRALIGHT,
					family => 'davis',
					foreground => "blue",
					size => 20000,
					);
						
		$sw->add($tview);
	$frame->add($sw);
$vbox->pack_start($frame,TRUE,TRUE,4);
	#--------------------------------------
	my $hbox = Gtk2::HBox->new(FALSE,5);
	
		my $ent_send = Gtk2::Entry->new;
	$hbox->pack_start($ent_send,TRUE,TRUE,0);
	
		my $btn_send = Gtk2::Button->new_from_stock('gtk-ok');
		#connect the 'key_press_signal' to a handler that will
		#filter for 'Return'; if TRUE, trigger a button click
		$ent_send->signal_connect('key_press_event'=> sub {
			my ($widget,$event) = @_;
			if($event->keyval == $Gtk2::Gdk::Keysyms{Return}) {
                 		$btn_send->clicked;
                 		return 1;
			}
		
		});
		
		$btn_send->signal_connect("clicked" =>sub {
			#get the contents of the entry
			my $msg_send = $ent_send->get_text;
			#clear the entry
			$ent_send->set_text("");
			#grab focus again for the next round of talks
			$ent_send->grab_focus;
			#if there was bogus input, ignore it!
			if ($msg_send !~ m/^\s*$/){
				#open up a UDP client connection
				my $server_host = "127.0.0.1";
				my $sock = IO::Socket::INET->new(Proto => 'udp',
                              	PeerPort  => $SEND_PORT,
                              	PeerAddr  => $server_host)
    				or die "Creating socket: $!\n";
				#send the message out on the socket
				$sock->send($msg_send."\n") or die "send: $!";
				#update the screen locally
				&update_buffer($buffer,$msg_send,TRUE);	
			}
		});
		
	$hbox->pack_end($btn_send,TRUE,TRUE,0);	
	#--------------------------------------
$vbox->pack_start($hbox,TRUE,TRUE,4);
	#set initial focus
	$vbox->set_focus_child($hbox);
	
$vbox->show_all();
return $vbox;
}

	
sub watch_callback {

	my ($fh,$tview) = @_;
	my $msg;
	$fh->recv($msg, $MAXLEN) or die "recv: $!";
		print $msg."\n";
		my $buffer = $tview->get_buffer();
		&update_buffer($buffer,$msg,FALSE);
		
	return 1;
}

Gtk2->main;

sub update_buffer {

	my ($buffer,$msg,$send)= @_;
	
	$msg = $msg."\n";
	if ($send) {
	
		my $iter = $buffer->get_end_iter;
		$buffer->insert_pixbuf ($iter,  Gtk2::Gdk::Pixbuf->new_from_file ($img_send));
		$buffer->insert_with_tags_by_name($iter, $msg,$tag_send); 
	
	}else{
	
		my $iter = $buffer->get_end_iter;
		$buffer->insert_pixbuf ($iter,  Gtk2::Gdk::Pixbuf->new_from_file ($img_rec));
		$buffer->insert_with_tags_by_name($iter, $msg,$tag_receive); 
		
	}
}