#!/usr/local/bin/wish4.2
# -*- mode: tcl; tcl-default-application: "wish4.2"; -*-

# Code by Derek Mulcahy, <derek@toybox.demon.co.uk>, 1997.
#
# This Tcl/Tk code monitors the xnptd log files generated by using the
# associated ARC xntpd refclock driver code and provides feedback.  This
# displays the signal strength, daylight savings time and battery
# indicator.
# 
# Double clicking with middle and right buttons on the icon displays the
# logs.

# THIS CODE IS SUPPLIED AS IS, WITH NO WARRANTY OF ANY KIND.  USE AT
# YOUR OWN RISK.

# This code may be freely copied and used and incorporated in other
# systems providing the disclaimer and notice of authorship are
# reproduced.


proc tower {w} {
    set i 0
    set wx [winfo width $w]
    set wy [winfo height $w]
    set cx [expr ($wx+1)/2]
    set cy [expr ($wy+1)/2]
    foreach c {#000 #D00 #FA0 #69E #0D0} {
	set r [expr ($i+1)*4]
	set tx [expr $cx-$r]
	set ty [expr $cx-$r]
	set bx [expr $cy+$r-1]
	set by [expr $cy+$r-1]
	$w create oval $tx $ty $bx $by\
		-outline $c -width 2 -tag "tower signal$i"
	$w create oval $tx $ty $bx $by\
		-outline #DDD -width 2 -tag "tower shadow"
	incr i
    }
    .c create rectangle 0 0 [expr $wx-1] [expr $wy-1]\
	    -fill #D9D9D9 -width 2 -tag "frame bg"
    $w create polygon 2 2 $cx $cy [expr $wx-3] 2\
	    -fill #D9D9D9 -tag tower
    $w create polygon\
	    2 [expr $wy-2] $cx $cy [expr $wx-3] [expr $wy-2]\
	    -fill #D9D9D9 -tag tower
    $w create polygon\
	    [expr $cx - 1] $cy $cx $cy\
	    [expr $cx + 3] [expr $wy-3] [expr $cx - 4] [expr $wy-3]\
	    -outline #000 -tag tower
    .c create rectangle 0 0 [expr $wx-1] [expr $wy-1]\
	    -outline #FFF -width 2 -tag frame
    .c create rectangle 1 1 [expr $wx-1] [expr $wy-1]\
	    -outline #666 -width 1 -tag frame
    .c create text [expr $cx-1] [expr $wy-6]\
	    -text "" -justify center -font 5x8 -fill #FF0 -tag "quality tower"
    .c create text [expr $cx-1] [expr $wy-6]\
	    -text "" -justify center -font 5x8 -tag time -fill black
#    .c create oval 13 34 19 40 -fill #DDD -outline #DDD -tag summer
    .c create oval [expr $cx-4] 4 [expr $cx+3] 10\
	    -fill #DDD -outline #DDD -tag summer
    .c raise shadow bg
    .c create rectangle 35 36 45 41 -fill #D9D9D9 -outline #DDD -tag battery
    .c create rectangle 45 38 46 39 -fill #D9D9D9 -outline #DDD -tag battery
    .c move tower 0 -9
}

proc update_quality {q} {
    for {set i 0} {$i < $q} {incr i} {
	.c raise signal$i shadow
    }
    for {set i $q} {$i < 6} {incr i} {
	.c lower signal$i bg
    }
    .c itemconfigure quality -text $q
}

proc update_clock {stamp} {
    if [string match "g*" $stamp] {
	set n [scan $stamp "g%1d%1d" s q]
	if {$n != 2} return
	if {$s != 3} return
	update_quality $q
    }
    if [string match "o*" $stamp] {
	set n [scan $stamp "o%2d%2d%2d%1d%2d%2d%2d%1d%1d%1d" H M S j d m y b s q]
	if {$n != 10} return
	if {($b & 2) == 2} {
	    .c itemconfigure summer -fill #FF0 -outline #000
	} else {
	    .c itemconfigure summer -fill #DDD -outline #DDD
	}
	if {($s & 3) == 3} {
	    .c itemconfigure time -fill black -tags time
	    .c raise time
	} else {
	    .c itemconfigure time -fill red -tags "time blink"
	}
	if {($s & 8) == 8} {
	    .c itemconfigure battery -fill red -outline black -tags "battery blink"
	} else {
	    .c itemconfigure battery -fill #D9D9D9 -outline #DDD -tags battery
	}
	update_quality $q
    }
}

proc check_clockstats {last} {
    global clockstats peg alarm_id

    file stat $clockstats stat
    after [expr $peg - ([clock clicks] / 1000) % 1000]\
	    check_clockstats $stat(size)
    if {$stat(size) > $last} {
	set f [open $clockstats r]
	seek $f $last
	set stamp [lindex [read $f [expr $stat(size)-$last]] 3]
	close $f
	update_clock $stamp
    }
    set now [clock seconds]
    .c itemconfigure time -text [clock format $now -format "%H:%M:%S"]
    after cancel $alarm_id
    set alarm_id [after 300000 alarm]
}

proc save_state {} {
    global env ntp geometry

    set f [open $env(HOME)/.arcstate w]
    puts $f "set ntp $ntp"
    puts $f "set geometry [wm geometry .]"
    close $f
}

set ntp /usr/spool/ntp
set geometry +0+[expr [winfo screenheight .]-53]

if [file exists $env(HOME)/.arcstate] {
    source $env(HOME)/.arcstate
}

if [file exists $env(HOME)/.arcrc] {
    source $env(HOME)/.arcrc
}

set clockstats $ntp/clockstats
set peerstats $ntp/peerstats
set log $ntp/log

if ![file exists $clockstats] {
    puts stderr "$clockstats: No such file."
    exit 1
}

wm overrideredirect . 1
wm geometry . $geometry

canvas .c -width 64 -height 64 -highlightthickness 0 -relief raised -bd 2

pack .c
update
tower .c

bind .c <Double-ButtonPress-1> {
    catch {exec kill $pid}
    set pid [exec xterm -geometry 80x6+0+0 -title $log -e tail -f $log &]
}
bind .c <ButtonPress-1> {
    set xo %x
    set yo %y
    raise .
}
bind .c <Button1-Motion>   {
    wm geometry . +[expr %X-$xo]+[expr %Y-$yo]
    update
}
bind .c <ButtonRelease-1> {
    save_state
}
bind .c <Double-ButtonPress-2> {
    catch {exec kill $pid}
    set pid [exec xterm -geometry 80x6+0+0 -title $peerstats -e tail -f $peerstats &]
}
bind .c <ButtonPress-3> {
    save_state
    catch {exec kill $pid}
    exit
}

proc blink_lower {} {
    .c lower blink
    after 500 blink_raise
}

proc blink_raise {} {
    .c raise blink
    after 500 blink_lower
}

proc alarm {} {
    .c itemconfigure time -fill red -tags "time blink"
}

file stat $clockstats stat
set peg [expr ([clock clicks] / 1000) % 1000 + 1000]
after 1000 check_clockstats $stat(size)
after 500 blink_lower
set alarm_id [after 300000 alarm]
