
proc cget {widget option} {
    return [lindex [$widget configure $option] 4]
}
#----------------------------------------------------------------------
# NAME
#    WatchSwitchForeBackGround - exchange foreground and background
#
# SYNOPSIS
#    WatchSwitchForeBackGround what
#
# DESCRIPTION
#    what: a wigdet
#    
#    Exchange foreground and background of widget Watch($what)
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WatchSwitchForeBackGround {what} {
    global Watch
    set foreground [cget $Watch($what) -foreground]
    set background [cget $Watch($what) -background]
    $Watch($what) configure -bg $foreground
    $Watch($what) configure -fg $background
}

#----------------------------------------------------------------------
# WRISTWATCH_O_BEEP
#
# make the Watch(watch_frame) blinking BEEP times
#
proc WRISTWATCH_O_BEEP { beep } {
    global Watch
    set delay 0
    for {set i 0} {$i<$beep} {incr i} {
	bell
	after [incr delay 100] $Watch(watch_frame) configure -bg red
	after [incr delay 100] $Watch(watch_frame) configure -bg black
    }
}


#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_START_ENHANCING - start highlighting
#
# SYNOPSIS
#    WRISTWATCH_O_START_ENHANCING w
#
# DESCRIPTION
#    w: text widget
#    
#    Highlights text widget w
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_START_ENHANCING {w} {
    WatchSwitchForeBackGround $w
}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_STOP_ENHANCING - stop highlighting
#
# SYNOPSIS
#    WRISTWATCH_O_STOP_ENHANCING w
#
# DESCRIPTION
#    w: text widget
#    
#    reverse action of WRISTWATCH_O_START_ENHANCING
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_STOP_ENHANCING {w} {
    WatchSwitchForeBackGround $w
}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_MAIN_DISPLAY - update main display
#
# SYNOPSIS
#    WRISTWATCH_O_MAIN_DISPLAY hour_or_mn mn_or_sec sec_or_cent time_mode
#
# DESCRIPTION
#    hour_or_mn   : hours or minutes
#    mn_or_sec    : minutes or secondes
#    sec_or_cent  : seconds or centieth
#    time_mode    : mode
#    
#    Updates the main display with the strings passed as parameter
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_MAIN_DISPLAY { \
	hour_or_mn \
	mn_or_sec \
	sec_or_cent \
	time_mode} {
    global Watch

    $Watch(main,hour_or_mn) configure -text "$hour_or_mn"
    # getting digits
    $Watch(main,10mn_or_sec) configure -text [string index "$mn_or_sec" 0]
    $Watch(main,mn_or_sec) configure -text [string index "$mn_or_sec" 1]
    $Watch(main,sec_or_cent) configure -text "$sec_or_cent"    
    $Watch(main,time_mode) configure -text "$time_mode"

}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_MINI_DISPLAY - update mini display
#
# SYNOPSIS
#    WRISTWATCH_O_MINI_DISPLAY hour_or_day sep mn_or_month
#
# DESCRIPTION
#    hour_or_day: hour or day
#    sep        : separator
#    mn_or_month: minutes or month
#    
#    update the mini display.
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_MINI_DISPLAY {hour_or_day sep mn_or_month} {
    global Watch
    $Watch(mini,hour_or_day) configure -text "$hour_or_day"
    $Watch(mini,sep) configure -text "$sep"
    $Watch(mini,mn_or_month) configure -text "$mn_or_month"
}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_ALPHABETIC_DISPLAY - update the alphabetic display
#
# SYNOPSIS
#    WRISTWATCH_O_ALPHABETIC_DISPLAY s
#
# DESCRIPTION
#    s: string to display
#    
#    Updates the alphabetic display with the string s
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_ALPHABETIC_DISPLAY {s} {
    global Watch
    $Watch(alphabetic) configure -text "$s"
}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_CHIME_STATUS - set chime status
#
# SYNOPSIS
#    WRISTWATCH_O_CHIME_STATUS s
#
# DESCRIPTION
#    set: boolean
#    
#    Set or unset chime status according to set
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_CHIME_STATUS {set} {
    global Watch
    set text [cget $Watch(main,chime_alarm) -text]
    if {$set} {
	regsub {(.. )....( ..)} $text {\1(())\2} text
    } else {
	regsub {\(\(\)\)} $text {    } text

    }
    $Watch(main,chime_alarm) configure -text "$text"
}

#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_ALARM_STATUS - set alarm status
#
# SYNOPSIS
#    WRISTWATCH_O_ALARM_STATUS s
#
# DESCRIPTION
#    set: boolean
#    
#    Set or unset alarm status according to set
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_ALARM_STATUS {set} {
    global Watch
    set text [cget $Watch(main,chime_alarm) -text]
    if {$set} {
	regsub {..( .... )..} $text {((\1))} text
    } else {
	regsub {..( .... )..} $text {  \1  } text

    }
    $Watch(main,chime_alarm) configure -text "$text"
}


#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_STOPWATCH_RUN_STATUS - set or unset stopwatch run status
#
# SYNOPSIS
#    WRISTWATCH_O_STOPWATCH_RUN_STATUS set
#
# DESCRIPTION
#    set: boolean
#    
#    Set or unset run status according to set.
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_STOPWATCH_RUN_STATUS {set} {
    global Watch
    if {$set} {
	$Watch(run) configure -text "run"
    } else {
	$Watch(run) configure -text "   "
    }
}


#----------------------------------------------------------------------
# NAME
#    WRISTWATCH_O_STOPWATCH_LAP_STATUS - set or unset stopwatch lap status
#
# SYNOPSIS
#    WRISTWATCH_O_STOPWATCH_LAP_STATUS set
#
# DESCRIPTION
#    set: boolean
#    
#    Set or unset lap status according to set.
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WRISTWATCH_O_STOPWATCH_LAP_STATUS {set} {
    global Watch
    if {$set} {
	$Watch(lap) configure -text "lap"
    } else {
	$Watch(lap) configure -text "   "
    }
}

#======================================================================
#
# Events handling
#
#======================================================================
# the input event fifo
set Watch(inputs) {}
# to check whether or not the automaton is running
set Watch(running) 0

#----------------------------------------------------------------------
# NAME
#    WatchAppendEvent - add events
#
# SYNOPSIS
#    WatchAppendEvent events
#
# DESCRIPTION
#    args: list of event to add
#    
#    Append event to Watch(inputs). Call the automaton if it is not
#    running 
#
# SIDE EFFECTS
#    
#
# RETURN
#    
#
#----------------------------------------------------------------------
proc WatchAppendEvent {args} {
    global Watch
    foreach event $args {
	if {[lsearch $Watch(inputs) $event]==-1} {
	    lappend Watch(inputs) $event
	}
    }
    if { $Watch(running) == 0} {
	if {[catch WatchHandleEvents error]} {
	    puts stderr "error $error"
	}
    }
}

#----------------------------------------------------------------------
#
# WatchHandleEvents
#
# main handler.
#
#
proc WatchHandleEvents {} {
    global Watch
    set Watch(running) 1
    while {[llength $Watch(inputs)] != 0} {
	foreach event $Watch(inputs) {
	    WRISTWATCH_I_$event
	}
	if { $Watch(send_to_server) } {
	    if {[catch {XesClient::SendCsimulEvent \
			    [concat $Watch(inputs) ";"] } ] } {
		if { [tk_dialog .err Error "No more server ?" error 0 \
			 Continue Exit] } {
		    exit 0
		} else {
		    WatchConnect 0
		}
	    }
	}
	set Watch(inputs) {}
	WRISTWATCH
    }
    set Watch(running) 0
}


####################################
# Socket management - client part - 
####################################

namespace eval XesClient {
    variable client_socket
    set client_socket -1
}

proc XesClient::InitConnection  { {serverInfoFile xesport.esp} } {
    variable client_socket
    if {[file extension $serverInfoFile] != ".esp"} {
	append serverInfoFile ".esp"
    }
    if { [catch {open $serverInfoFile r} fd] } {
	# ERROR: cannot open file
	return -code error
    }
    while {[gets $fd line]} {
	if {[regexp {(\S+)\s+(\d+)} $line dummy host port]} {
	    if {[catch {socket $host $port} client_socket]} {
		# ERROR: cannot open socket
		return -code error
	    } else {
		return 
	    }
	}
    }
    # ERROR: bad xesport.esp file
    return -code error
}

proc XesClient::SendCsimulEvent { { string {} } } {
    variable client_socket
    if {[catch {puts $client_socket $string; flush $client_socket} err]} {
	return -code error
    }
}

proc XesClient::CloseConnection {} {
    variable client_socket
    catch {close $client_socket}
}

proc WatchConnect {connect {file ""}} {
    global Watch

    if { ! $connect } {
	set Watch(send_to_server) 0
	set Watch(connect:status) 0
	set Watch(connect:label) "Connect..."
	XesClient::CloseConnection
	catch {
	    set menu [lindex $Watch(connect:entry) 0]
	    set item [lindex $Watch(connect:entry) 1]
	    $menu entryconfigure $item -label $Watch(connect:label)
	}
	return
    }

    if  { $file == "" } {
	set file [tk_getOpenFile \
		      -defaultextension ".esp" \
		      -filetypes [list \
				      {{Server Port} .esp} \
				      {{All files} *}] \
		      -title "Server Port File"]

	if { $file == "" } {
	    set Watch(connect:status) 0	
	    return
	}
    }

    # waiting for file existence 
    # (if launched from command line option)
    set max_try 5
    for {set try 0} {$try < $max_try} {incr try} {
	if {[file exists $file]} {
	    after 500
	    break
	}
	after 1000
    }

    if {($try == $max_try) || \
	    [catch {XesClient::InitConnection $file} ] } {
	if {[tk_dialog .err "Error" "Cannot connect to \"$file\"" \
		 error 0 \
		 Continue Exit] } {
	    exit 0
	}
	set Watch(connect:status) 0

    } else {
	set Watch(send_to_server) 1
	set Watch(connect:status) 1
	set Watch(connect:label)  "Disconnect"
	catch {
	    set menu [lindex $Watch(connect:entry) 0]
	    set item [lindex $Watch(connect:entry) 1]
	    $menu entryconfigure $item -label $Watch(connect:label)
	}
    }
}

global Watch
wm withdraw .
set Watch(send_to_server) 0
set Watch(connect:status) 0
set Watch(connect:label) "Connect..."

for {set argc 0} {$argc < [llength $argv]} {incr argc} {
    set arg [lindex $argv $argc]
    switch -glob --  $arg {
	-slow|-fast {
	    WatchSetSpeed $arg
	}
	-client:* {
	    regsub -- {-client:} [lindex $argv $argc] {} file
	    WatchConnect 1 $file
	}
    }
    incr argc
}

#----------------------------------------------------------------------
# Fonts spec
#----------------------------------------------------------------------
set Watch(large_font)  {-adobe-helvetica-bold-r-*-*-*-180-*}
set Watch(medium_font) {-adobe-helvetica-bold-r-*-*-*-140-*}
set Watch(small_font)  {-adobe-helvetica-bold-r-*-*-*-120-*}


set Watch(watch) .watch
set Watch(input) {}

catch {destroy $Watch(watch)}
toplevel $Watch(watch) -menu .watch.menubar

menu .watch.menubar
menu .watch.menubar.file -tearoff false

.watch.menubar add cascade \
    -label File \
    -menu .watch.menubar.file

.watch.menubar.file add checkbutton \
    -label $Watch(connect:label) \
    -command {WatchConnect [expr $Watch(connect:status) ?0:1]}
set Watch(connect:entry) {.watch.menubar.file 0}

.watch.menubar.file add command \
    -label Quit \
    -command {exit 0}



set Watch(left_frame)   [frame $Watch(watch).left_frame] 
set Watch(right_frame)	[frame $Watch(watch).rigth_frame]
set Watch(watch_frame)	[frame $Watch(watch).watch_frame -bg black] 
set Watch(screen_frame) [frame $Watch(watch).watch_frame.screen]

pack $Watch(left_frame) -side left -fill y
pack $Watch(right_frame) -side right -fill y
pack $Watch(watch_frame) -side top -fill both -expand 1

pack $Watch(screen_frame) -padx 5 -pady 5 -expand 1 -fill both

#----------------------------------------------------------------------
# buttons
#----------------------------------------------------------------------
set Watch(UL) [button $Watch(left_frame).ul -text UL]
set Watch(LL) [button $Watch(left_frame).ll -text LL]
set Watch(UR) [button $Watch(right_frame).ur -text UR]
set Watch(LR) [button $Watch(right_frame).lr -text LR]
pack $Watch(UL) -expand 1
pack $Watch(LL) -expand 1
pack $Watch(UR) -expand 1
pack $Watch(LR) -expand 1


$Watch(UL) configure -command {WatchAppendEvent UL}
$Watch(LL) configure -command {WatchAppendEvent LL}
$Watch(LR) configure -command {WatchAppendEvent LR}
$Watch(UR) configure -command {WatchAppendEvent UR}


#----------------------------------------------------------------------
#
# Mini display
#
#----------------------------------------------------------------------
set Watch(top_display) [frame $Watch(screen_frame).top_display]
pack $Watch(top_display) -fill x

set Watch(alphabetic)  \
	[label $Watch(top_display).alphabetic \
	-font $Watch(large_font) -width 3 -text MO]

set Watch(mini_display) \
	[frame $Watch(top_display).mini_display -bd 2 -relief ridge]

set Watch(mini,hour_or_day)  \
	[label $Watch(mini_display).hour_or_day \
	-font $Watch(large_font) -width 2 -anchor e \
	-text 9]
set Watch(mini,mn_or_month)  \
	[label $Watch(mini_display).mn_or_month \
	-font $Watch(large_font) -width 2 -anchor w \
	-text 11]
set Watch(mini,sep) \
	[label $Watch(mini_display).sep -font $Watch(large_font) -text "-"]
set Watch(lap) \
	[label $Watch(top_display).lap -font $Watch(small_font) -text lap]
set Watch(run) \
	[label $Watch(top_display).run -font $Watch(small_font) -text run]

pack $Watch(alphabetic) -side left -padx 4 

pack $Watch(mini_display) -side right -padx 4
pack $Watch(mini,mn_or_month) -side right
pack $Watch(mini,sep) -side right
pack $Watch(mini,hour_or_day) -side right

pack $Watch(lap)
pack $Watch(run)

# a separation
pack [frame $Watch(screen_frame).sep -bd 1 -height 2 -relief sunken ] -fill x


#----------------------------------------------------------------------
#
# Main display
#
#----------------------------------------------------------------------
set Watch(main_display) [frame $Watch(screen_frame).main_display]
pack $Watch(main_display) -fill x
set Watch(top_main) [frame $Watch(main_display).top]
set Watch(bot_main) [frame $Watch(main_display).bot]
pack $Watch(top_main) -fill x
pack $Watch(bot_main) -fill x

set Watch(main,time_mode) \
	[label $Watch(top_main).time_mode \
	-font $Watch(small_font) -width 3 \
	-anchor e \
	-text PM]
set Watch(main,chime_alarm)     \
	[label $Watch(top_main).chime_alarm -font $Watch(small_font) \
	-text {(( (()) ))}]
$Watch(top_main).chime_alarm configure -width 11
pack $Watch(main,time_mode) -side left -expand 1 -anchor e -fill x
pack $Watch(main,chime_alarm) -side right -padx 4

set Watch(main,hour_or_mn)  \
	[label $Watch(bot_main).hour_or_mn \
	-font $Watch(large_font) -width 2 -anchor e \
	-text 11]
set Watch(main,sep)         \
	[label $Watch(bot_main).sep -font $Watch(large_font) \
	-text {:}]
set Watch(main,10mn_or_sec)   \
	[label $Watch(bot_main).10mn_or_sec \
	-font $Watch(large_font) -anchor e -width 1 -padx 0\
	-text 1]
set Watch(main,mn_or_sec)   \
	[label $Watch(bot_main).mn_or_sec \
	-font $Watch(large_font) -anchor w -width 1 -padx 0\
	-text 2]
set Watch(main,sec_or_cent) \
	[label $Watch(bot_main).sec_or_cent \
	-font $Watch(medium_font) -width 2 \
	-text 43]

pack $Watch(main,hour_or_mn) -side left -expand 1 -anchor e
pack $Watch(main,sep) -side left
pack $Watch(main,10mn_or_sec) -side left 
pack $Watch(main,mn_or_sec) -side left  -anchor w
pack $Watch(main,sec_or_cent) -side left -expand 1 -anchor w -padx 4




#
# some bindings
#
focus $Watch(watch)
bind $Watch(watch) <q> {exit 0}
bind $Watch(watch) <Q> {exit 0}

#
# wait for the main window
#
tkwait visibility $Watch(watch)

# fix some geometry constraints
pack propagate $Watch(mini_display) 0
pack propagate $Watch(top_display) 0
pack propagate $Watch(main_display) 0
pack propagate $Watch(top_main) 0
pack propagate $Watch(bot_main) 0

# update all
update idletasks

# start timer
WatchStartTimer

tkwait window $Watch(watch)
exit 0
