#!/afs/athena.mit.edu/contrib/perl5/bin/perl

use Socket;
use Sys::Hostname;
use Tk;

use Tk qw(exit); 

$server_port=8930;
$multi_port=8931;

die unless $myaddr = gethostbyname(hostname());
die unless $destaddr = gethostbyname("cj.mit.edu");
die unless $multiaddr = gethostbyname("224.0.1.20");

die unless $proto = getprotobyname('udp');

die unless $paddr = sockaddr_in(0,$myaddr);
die unless $multipaddr = sockaddr_in($multi_port,$multiaddr);
die unless $destpaddr = sockaddr_in($server_port,$destaddr);

die "$!\n" unless socket(MAIN_SOCK, PF_INET, SOCK_DGRAM, $proto);
die "$!\n" unless socket(MULTI_SOCK, PF_INET, SOCK_DGRAM, $proto);

die "$!\n" unless setsockopt(MULTI_SOCK,SOL_SOCKET,SO_REUSEADDR,
			     pack("l",1));
die "bind: $!\n" unless bind(MULTI_SOCK,$multipaddr);
$mreq=$multiaddr."\0\0\0\0";

$sys=$ENV{"ATHENA_SYS"};

$poll=0;

$add_mem=$sys;

if($add_mem=~/.*linux.*/){
    die "$!\n" unless setsockopt(MULTI_SOCK,0,35,$mreq);
}elsif($add_mem=~/.*nbsd.*/){
    die "$!\n" unless setsockopt(MULTI_SOCK,0,12,$mreq);
}elsif($add_mem=~/sgi.*/){
    eval(setsockopt(MULTI_SOCK,0,5,$mreq));
    eval(setsockopt(MULTI_SOCK,0,23,$mreq));
}elsif($add_mem=~/sun4.*/){
    die "$!\n" unless setsockopt(MULTI_SOCK,0,19,$mreq);
}elsif($add_mem=~/pmax.*/){
    die "$!\n" unless setsockopt(MULTI_SOCK,0,5,$mreq);
}else{
    $poll=1;
    print "Whoops... $sys doesn't do multicast... Gotta poll.\n";
}

$toplevel=MainWindow->new(width=>340,height=>50);
$toplevel->resizable(FALSE,FALSE);

# Setup the spinning fish
$pixmaps="/afs/sipb.mit.edu/user/xiphmont/vol/pixmaps";
$fish=$toplevel->Pixmap(-file => "$pixmaps/fishframe.xpm");

$frame=$toplevel->Frame(-borderwidth=>2,-relief=>groove,
			-bg=>$toplevel->cget('-bg'))->
    place(-relwidth=>1.0,-width=>-46,-relheight=>1.0,-relx=>0,-rely=>0);


$slider=$frame->Scale(from=>0, to=>255, -bigincrement=>0,-showvalue=>FALSE,
			 orient=>horizontal,-command=>\&adjust,
			 highlightthickness=>0,-bg=>$toplevel->cget('-bg'))->
    place(-relx=>0,-rely=>0,-relwidth=>1.0,-width=>-30,-relheight=>.58,
	  -anchor=>nw);
$level=$frame->Label(highlightthickness=>0,borderwidth=>0,
		     -bg=>$toplevel->cget('-bg'))->
    place(-relx=>1.0,-rely=>0.0,-relheight=>.60,-width=>30,-anchor=>'ne');
	
$scale1=$frame->Radiobutton(highlightthickness=>0,selectcolor=>"green",
			    borderwidth=>1,command=>\&srefresh,
			    activebackground=>$frame->cget("-background"),
			    value=>0,variable=>\$scale,text=>"linear",
			    -bg=>$toplevel->cget('-bg'))->
    place(-relx=>0.02,-rely=>1.-.23,-relheight=>.35,-anchor=>w);

$scale2=$frame->Radiobutton(highlightthickness=>0,selectcolor=>"green",
			    borderwidth=>1,command=>\&srefresh,
			    activebackground=>$frame->cget("-background"),
			    value=>1,variable=>\$scale,text=>"log",
			    -bg=>$toplevel->cget('-bg'))->
    place(-relx=>0.24,-rely=>1.-.23,-relheight=>.35,-anchor=>w);

$hostwindow=$frame->Label(highlightthickness=>0,
			    borderwidth=>1,relief=>groove,
			    -bg=>$toplevel->cget('-bg'))->
    place(-relx=>0.42,-rely=>1.-.23,-relheight=>.35,-anchor=>w,-relwidth=>.55);

$mute=$toplevel->Canvas(borderwidth=>0,
			    highlightthickness=>0,
			    width=>40,height=>40,-bg=>$toplevel->cget('-bg'))->
    place(-relx=>1.0,-rely=>0.5,-x=>-2,-anchor=>'e');

$mute->createImage(0,0,-image=>$fish,-anchor=>nw,-tags=>["fish"]);

$mute->bind('fish','<Enter>',[sub{$mutelight=1;&twirlupdate}]);
$mute->bind('fish','<Leave>',[sub{$mutelight=0;&twirlupdate}]);
$mute->bind('fish','<Button>',[sub{&mute;&twirlupdate;}]);
$mute->bind('fish','<ButtonRelease>',[sub{&twirlupdate;}]);		  
&twirlupdate();

$slider->bind('<Button>',[sub{$slideractive=1;}]);
$slider->bind('<ButtonRelease>',[sub{$slideractive=0;}]);
$slideractive=0;

$toplevel->bind($toplevel,'<Any-KeyPress-q>',\&my_exit);

$toplevel->fileevent(MAIN_SOCK, "readable", \&response);
$toplevel->fileevent(MULTI_SOCK, "readable", \&multi);
if($poll){$toplevel->repeat(1000,\&poll_status);}

&genlookup;

$lastaddr=0;
$muted=-1;
$mutelight=0;
$volume=-1;
$scalevolume=-1;
$scale=1; # 0=linear 1=log 2=square
&poll_status;
$mute->repeat(100,\&twirlback);

MainLoop();

sub my_exit(){
    close(MAIN_SOCK);
    close(MULTI_SOCK);
  Tk::exit;
}

sub srefresh{

    if(&s2v($scalevolume)!=$volume){
	$scalevolume=&v2s($volume);
    }
    $level->configure(-text=>"$volume");
    if($slideractive==0){
	$slider->set($scalevolume);
    }
}

sub update{
    my ($request,$val,$ip_3,$ip_2,$ip_1,$ip_0)=@_;

    if($request eq 'V'){
	if($volume!=-1){
	    if($volume<$val){
		$fishcounter++;
		if($fishcounter>=12){$fishcounter=0;}
		&twirlupdate();
	    }elsif($volume>$val){
		$fishcounter--;
		if($fishcounter<0){$fishcounter=11;}
		&twirlupdate();
	    }
	}
	$volume=$val;
	&srefresh;
    }elsif($request eq 'M'){
	$muted=$val;
	&twirlupdate();
    }

    my $addr=inet_aton("$ip_3.$ip_2.$ip_1.$ip_0");
    if($addr ne $lastaddr){
	$lastaddr=$addr;
	my ($host)=gethostbyaddr($addr,AF_INET);
	($host)=split(/\./,$host);
	$host=lc($host);
	$hostwindow->configure(text=>$host);
    }
}    

sub poll_status{
    ($volume,$muted)=&request('Q', 'Q');
    $scalevolume=&v2s($volume);
}

sub adjust{
    if($slideractive && $volume!=-1){
	my $req;
	$val=&s2v($_[0]);
	&request('V',$val);
    }
}

sub mute{
    if($muted!=-1){
	if($muted==0){
	    $muted=1;
	    &request('M',1);
	}else{
	    $muted=0;
	    &request('M',0);
	}
    }
}

sub response {
    recv(MAIN_SOCK,$ret,8,0);
    my ($A,$retval,$val,$ip_3,$ip_2,$ip_1,$ip_0,$Z)=unpack 'A1A1CCCCCA1', $ret;
    if($Z eq 'Z'){
	&update($retval,$val,$ip_3,$ip_2,$ip_1,$ip_0);
    }
}

sub multi {
    recv(MULTI_SOCK,$ret,8,0);
    my ($A,$retval,$val,$ip_3,$ip_2,$ip_1,$ip_0,$Z)=unpack 'A1A1CCCCCA1', $ret;
    if($Z eq 'Z'){
	&update($retval,$val,$ip_3,$ip_2,$ip_1,$ip_0);
    }
}

sub request {
    my ($request,$val)=@_;
    my $ret,$end,$retval;

    $request= pack 'A1A1CCCCCA1', 'A',$request, "$val",0,0,0,0,'Z';

    send(MAIN_SOCK,$request,0,$destpaddr);
}

sub twirlback{
    if($muted){
	$fishcounter++;
	if($fishcounter>=12){$fishcounter=0;}
	&twirlupdate();
    }
}

sub twirlupdate{
    $math=$fishcounter*-40;
    if($muted){
	$mute->coords('fish',$math,-80);
    }else{
	if($mutelight){
	    $mute->coords('fish',$math,-40);
	}else{
	    $mute->coords('fish',$math,0);
	}
    }
}

sub genlookup {
    @vslookup=();
    @svlookup=();

    my $count=0;
    while($count<256){
	$val=int(31.95*log($count+1)/log(2));
	push @vslookup, $val;
	$svlookup[$val]=$count;
	$count++;
    }

    $count=0;
    my $last=0;
    while($count<256){
	if(defined($svlookup[$count])){
	    $last=$svlookup[$count];
	}else{
	    $svlookup[$count]=$last;
	}
	$count++;
    }
}

sub v2s {
    my ($val)=@_;
   
    if($scale==0){
	$val;
    }elsif($scale==1){
	$vslookup[$val];
    }
}

sub s2v {
    my ($val)=@_;

    if($scale==0){
	$val;
    }elsif($scale==1){
	$svlookup[$val];
    }
}





