#!/usr/local/bin/wish -f

# artts - anal retentive time tracking software
#
# Copyright 1994, 1995, Paul E Coad
# The author disclaims all warranties with regard to this software, including
# all implied warranties of merchantability and fitness.  In no event
# shall the author be liable for any special, indirect or consequential
# damages or any damages whatsoever resulting from loss of use, data or
# profits, whether in an action of contract, negligence or other
# tortuous action, arising out of or in connection with the use or
# performance of this software.
#
# This package is being released under the terms of Larry Wall's
# "Artistic license".

# artts - 1.0

# This script provides a simple tool for tracking time spent on tasks

proc tkerror {message} {
    puts "artts error: $message"
}

set artts_ver 1.0

set auto_path "$tk_library $auto_path"

#
# setup globally needed values
#
set artts(dot_width) ""
set artts(dot_height) ""
set artts(x_pos) 300
set artts(y_pos) 300
set artts(update_rate) 10000
set artts(colors) [list red blue green]
set artts(rpt_x) 300
set artts(rpt_y) 300
set list_changed 0
set current_task -1
set save_task 0
set current_task_start "" 
set current_time ""

# Default tasks 
set artts(tasks) [list "Real Work" "Mail" "News" "Meetings" "Lunch" \
		     "Wool Gathering"]
set artts(start_task) NONE

set but_label_index 0

# Set initial fonts

set artts(fixed) -adobe-courier-bold-r-normal--*-120-*-*-*-*-*-*
set artts(prop) -Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*

# The obligatory rc file
source ~/.arttsrc

# If the start task is set use it.  If it is not use NONE.
set current_task [lsearch -exact $artts(tasks) $artts(start_task)]

set TRUE 1
set FALSE 0

# This proc must be declared here since it is used in the creation of
# the interface.
proc get_current {} {
    global artts current_task
    if {$current_task == -1} {
	return "NONE"
    } else {
	return [lindex $artts(tasks) $current_task]
    }
}

#
# Initialize the window
#

# Setup dimensions and position
if {$artts(dot_width) != "" && $artts(dot_height) != ""} {
    # The dimensions were specified by the user, use them
    set dims [format "%ix%i" $artts(dot_width) $artts(dot_height)]
} else {
    set dims ""
}

set pos [format "+%i+%i" $artts(x_pos) $artts(y_pos)]
wm geometry . $dims$pos

# Setup title for main window
wm title . "Artts"

# This allows the window to be resized (not a good idea here)
# unfortunately the default was changed in tk4.0 so we don't have control 
# anymore
# wm minsize . 0 0

# Quitting the window is the same as quitting the application
wm protocol . WM_DELETE_WINDOW quit
wm protocol . WM_SAVE_YOURSELF quit

#
# Create the interface
#
frame .f -relief ridge -borderwidth 2
label .f.amount -text "00:00:00" -font "$artts(fixed)" 
frame .f1 -relief ridge -borderwidth 2
label .f1.task -text "[get_current]" -font "$artts(prop)"
frame .f2  -relief ridge -borderwidth 2

#
# Main buttons (upper frame)
#
button .f2.stop -text Stop -command stop_task -padx 1 -pady 1 \
	-font "$artts(prop)"
menubutton .f2.switch -text Tasks -underline 0 -menu .f2.switch.menu \
	-relief raised -padx 0 -font "$artts(prop)"
button .f2.new -text New -command new_task -padx 1 -pady 1 -font "$artts(prop)"
button .f2.more -text "+" -command more_buttons -padx 1 -pady 1 \
	-font "$artts(prop)"

frame .f3 -relief ridge -borderwidth 2

#
# Lower frame buttons
#
button .f3.report -text Report -command report_it -padx 1 -pady 1 \
	-font "$artts(prop)"
menubutton .f3.remove -text "Delete" -underline 0 -menu .f3.remove.menu \
	-relief raised -padx 0  -font "$artts(prop)"
button .f3.less -text "-" -command fewer_buttons -padx 1 -pady 1 \
	-font "$artts(prop)"
button .f3.quit -text Quit -command quit -padx 1 -pady 1 -font "$artts(prop)"

menu .f2.switch.menu
menu .f3.remove.menu


# Load menu options
set index 0
foreach i $artts(tasks) {
    .f2.switch.menu add radiobutton -label "$i" -variable current_task \
					-value $index -command switch_task 
    .f3.remove.menu add radiobutton -label "$i" -variable remove_task \
					-value $index -command delete_task 
    incr index
}

#
# Pack it up
#
pack .f -fill x  -expand no
pack .f.amount -side left -expand yes
pack .f1 -fill x -expand yes
pack .f1.task -side top -fill both -expand yes
pack .f2 -fill both -expand no -pady 0 -padx 0 -ipadx 0 -ipady 0
pack .f2.switch -side left -fill x -expand yes 
pack .f2.stop -side left -fill x -expand yes 
pack .f2.new -side left -fill x -expand yes 
pack .f2.more -side left -fill x -expand yes 

# Do version related stuff 
if {$tk_version > 3.6} {
    # Changes in tk4.0 made it harder to pack tightly, here's an attempt
    .f2.switch configure -height [expr [.f2.stop cget -height] + 1]
    .f2.switch configure -pady 2
}

#
# Proc definitions begin 
#

#---------------------------------------------------------------------
# more_buttons - show the second row of buttons on the main window
#
# returns nothing
#---------------------------------------------------------------------
proc more_buttons {} {
    global tk_version

    pack .f3 -fill both -expand no  -pady 0 -padx 0 -ipady 0 -ipadx 0
    pack .f3.remove -side left -fill x -expand yes 
    pack .f3.report -side left -fill x -expand yes 
    pack .f3.quit -side left -fill x -expand yes 
    pack .f3.less -side left -fill x -expand yes 

    if {$tk_version > 3.6} {
	# Changes in tk4.0 made it harder to pack tightly, here's an attempt
	.f3.remove configure -height [expr [.f3.quit cget -height] + 0]
	.f3.remove configure -pady 2
    }
    return ""
}

#---------------------------------------------------------------------
# fewer_buttons - hide the second row of buttons on the main window
#
# returns nothing
#---------------------------------------------------------------------
proc fewer_buttons {} {
    pack forget .f3
    return ""
}

#---------------------------------------------------------------------
# delete_task- Remove a task from the task menus
# 
# returns nothing
# side effects: changes task_list, current_task and Switch and Delete menus
#---------------------------------------------------------------------
proc delete_task {} {
    global artts remove_task current_task list_changed

    # Save the current task name in case it is being deleted
    set task_name [get_current]

    set artts(tasks) [lreplace $artts(tasks) $remove_task $remove_task]

    if {[lsearch -exact $artts(tasks) $task_name] == -1} {
	# The current task was removed
	stop_task $task_name
    }

    rebuild_menus
    set list_changed 1
    return ""
}

#---------------------------------------------------------------------
# rebuild_menus - rebuild Switch and Delete menus from task list
#
# returns nothing
#---------------------------------------------------------------------
proc rebuild_menus {} {
    global artts
    .f2.switch.menu delete 0 last
    .f3.remove.menu delete 0 last

    # Load menu options
    set index 0
    foreach i $artts(tasks) {
	.f2.switch.menu add radiobutton -label "$i" -variable current_task \
					-value $index -command switch_task  
	.f3.remove.menu add radiobutton -label "$i" -variable remove_task \
					-value $index -command delete_task
	incr index
    }
    return ""
}

#-----------------------------------------------------------------------------
# flush_task - does the dirty work of stopping a task and writing it to disk
#
# arguments:	none
# returns:	1
# side-effects:	changes the value of current_time, sets current_task_time
#		current_task is set to -1 and the display task is set to NONE
#-----------------------------------------------------------------------------
proc flush_task {{use_task ""}} {
    global current_task_start current_time current_task save_task artts

    set current_time [get_date_time]
    set start_time [time_part $current_task_start]
    set stop_time [time_part $current_time]

    if {$current_task != -1} {
	# Get the current time
	set current_time [get_date_time]
	set start_time [time_part $current_task_start] 
	set stop_time [time_part $current_time]
	if {$use_task == ""} {
 	    set task [get_current] 
	} else {
	    set task $use_task
	}

	# Get the time diff
	if {[lindex $stop_time 0] < [lindex $start_time 0]} {
	    # Midnight crossed, get the time to the end of the day
	    set before_diff [time_diff $start_time [list 24 0 0]]
	    set diff [time_diff [list 0 0 0] $stop_time]

	    # Do an auto-change-over
	    set start [date_part $current_task_start]
	    set midnight_yesterday [list [lindex $start 0] [lindex $start 1] \
				[lindex $start 2] 24 0 0]

	    # Write yesterday's end of task
	    write_task $current_task_start $midnight_yesterday \
			$before_diff $task
	
	    # Reset task
	    set current_task_start [list [lindex $current_time 0] \
		[lindex $current_time 1] [lindex $current_time 2] 0 0 0] 
	} else {
	    # Business as usual
	    set diff [time_diff $start_time $stop_time]
	    write_task $current_task_start $current_time $diff $task
	}
        .f.amount configure -text "00:00:00"
        .f1.task configure -text "NONE"
	set current_task -1
	set save_task -1
    }
    return 1
}

#-----------------------------------------------------------------------------
# stop_task - stops accumulating time on the current task and resets the
#	      current task to none.
#
# args:	use_task	passes a task for using as the current task
# returns nothing
#-----------------------------------------------------------------------------
proc stop_task {{use_task ""}} {
    flush_task $use_task
    return ""
}

#-----------------------------------------------------------------------------
# switch_task - stops and writes the current tasks and starts a new task
# 
# returns nothing 
# side effects: changes current_time, current_task, task list
#-----------------------------------------------------------------------------
proc switch_task {} {
    global current_task_start current_time current_task artts save_task

    # Save the new task while flushing the old task
    set next_task $current_task
    set current_task $save_task
    flush_task

    # Restore the new task
    set current_task $next_task

    # Start the new task
    start_new_task
    set save_task $current_task 
    return ""
}

#-----------------------------------------------------------------------------
# start_new_task - starts a new task
#
# returns nothing
# side-effects:	resets the current_time and current_task_start and changes
#		the display of the current task to the current task
#-----------------------------------------------------------------------------
proc start_new_task {} {
    global current_task_start current_time artts current_task

    set current_task_start [get_date_time]
    set current_time [get_date_time]

    .f.amount configure -text "00:00:00"
    if {$current_task != -1} {
	.f1.task configure -text "[get_current]"
    } else {
	.f1.task configure -text "NONE"
    }
    return ""
}

#-----------------------------------------------------------------------------
# new_task - opens a dialog for accepting the input of a new task name
#
# returns nothing
#-----------------------------------------------------------------------------
proc new_task {} {
    global artts

    catch {destroy .top}
    toplevel .top
    wm title .top "New Task"
    wm geometry .top +300+300
    wm minsize .top 0 0

    # Build the window
    frame .top.f1 -relief ridge -borderwidth 2
    label .top.f1.label -text "Task:" -relief ridge -borderwidth 2 \
	-font "$artts(prop)"
    entry .top.f1.entry -relief ridge -borderwidth 2 -width 30 \
	-font "$artts(prop)"
    frame .top.f2 -relief ridge  -borderwidth 2
    button .top.f2.add -text Add -command "new_task_add .top.f1.entry" \
	-font "$artts(prop)"
    button .top.f2.cancel -text Cancel -command "destroy .top" \
	-font "$artts(prop)"

    pack .top.f1 -side top  -fill both -expand yes
    pack .top.f1.label -side left
    pack .top.f1.entry -side left -fill both -expand yes
    pack .top.f2 -side top  -fill x -expand yes
    pack .top.f2.add .top.f2.cancel -side left -fill x -expand yes

    bind .top.f1.entry <Return> ".top.f2.add invoke"
    return ""
}

#-----------------------------------------------------------------------------
# new_task_add - (callback for the Add button on the New Task window)
#		 gets the entered string, adds it to the menu of available
#		 tasks and destroys the New Task window.
# returns nothing
#-----------------------------------------------------------------------------
proc new_task_add {w} {
    global current_task save_task artts list_changed 

    # Write out old task
    flush_task
    set task [$w get]

    # Don't allow an empty task to be specified
    if {$task != ""} {
	lappend artts(tasks) $task
	set current_task [lsearch -exact $artts(tasks) $task]
	set save_task $current_task 
	set list_changed 1
	start_new_task
	.f2.switch.menu add radiobutton -label "$task" -variable current_task \
				-value $current_task -command switch_task 
	.f3.remove.menu add radiobutton -label "$task" -variable remove_task \
				-value $current_task -command delete_task 
	destroy .top
    }
    return ""
}

#-----------------------------------------------------------------------------
# quit - (callback for the Quit button) flushes the current task, writes
#	 the current task list to the ~/.jrandom file and destroys the . window
#-----------------------------------------------------------------------------
proc quit {} {
   global artts list_changed

   flush_task

   # Write the task list if the list has been changed
   if {$list_changed == 1} {
	set file [open ~/.arttsrc a]
	puts -nonewline $file "set artts(tasks) \[list "
	foreach i $artts(tasks) {
	    puts -nonewline $file "\"$i\" "
	}
	puts $file "\]"
	close $file
    }
    destroy .
}

#---------------------------------------------------------------
# time_diff - calculates the number of seconds between two times
#	      This assumes that the two times are in the same day.
#
# args:	h1	the begin hour value (0 - 23)
#	m1	the begin minute value (0 - 59)
# 	s1	the begin second value (0 - 60)
#	h2	the stop hour value (0 - 23)
#	m1	the stop minute value (0 - 59)
# 	s1	the stop second value (0 - 60)
# args: t1 	the begin time list (hour, min, sec)
# 	t2 	the stop time list (hour, min, sec)
#---------------------------------------------------------------
proc time_diff {t1 t2} {
    # Start time
    set h1 [lindex $t1 0]; set m1 [lindex $t1 1]; set s1 [lindex $t1 2]

    # End time
    set h2 [lindex $t2 0]; set m2 [lindex $t2 1]; set s2 [lindex $t2 2]

    # Get hour difference in seconds
    if {$h1 > $h2} {
    	# crossed midnight
    	set crossed_midnight 1
    	set h_diff [expr (($h2 + 24) - $h1) * 3600]
    	set h_before [expr (24 - $h1) * 3600]
    	set h_after [expr $h2 * 3600]
    } else {
    	set h_diff [expr ($h2 - $h1) * 3600]
    }
    # Get minute difference in seconds
    if {$m1 > $m2} {
    	set m_diff [expr (($m2 + 60) - $m1) * 60]
    	# Change the hour difference if necessary
    	if {$h_diff > 0} {
    		set h_diff [expr $h_diff - 3600]
    	} else {
    		set h_diff [expr 23 * 3600]
    	}
    } else {
    	set m_diff [expr ($m2 - $m1) * 60]
    }
    if {$s1 > $s2} {
    	set s_diff [expr ($s2 + 60) - $s1]
    	# change the minute difference if necessary
    	if {$m_diff > 0} {
	    set m_diff [expr $m_diff - 60]
	} else {
	    set m_diff [expr 59 * 60]
	    # Change the hour difference if necessary
	    if {$h_diff > 0} {
		set h_diff [expr $h_diff - 3600]
	    } else {
		set h_diff [expr 23 * 3600]
	    }
	}
    } else {
	set s_diff [expr $s2 - $s1]
    }
    set total_diff [expr $s_diff + $m_diff + $h_diff]
    return $total_diff
}

#---------------------------------------------------------------
# get_date_time - gets the current date and time 
#
# args:	none
# returns: list	- (two digits each) year month day hour minute second
#---------------------------------------------------------------
proc get_date_time {} {
    catch {exec date +%y:%m:%d:%H:%M:%S} date_time_value
    scan $date_time_value "%d:%d:%d:%d:%d:%d" year month day hours mins secs
    return [list $year $month $day $hours $mins $secs]
}

#---------------------------------------------------------------
# update_clock - updates the current time and flushes the current
#		 task if it has crossed midnight (local)
#---------------------------------------------------------------
proc update_clock {} {
    global current_task_start current_time current_task artts 

    if {$current_task != -1} {
	set current_time [get_date_time]
	set start_time [time_part $current_task_start] 
	set stop_time [time_part $current_time]
	if {[lindex $stop_time 0] < [lindex $start_time 0]} {
	    # Midnight crossed, get the time to the end of the day
	    set before_diff [time_diff $start_time [list 24 0 0]]
	    set diff [time_diff [list 0 0 0] $stop_time]

	    # Do an auto-change-over
	    set start [date_part $current_task_start]
	    set midnight_yesterday [list [lindex $start 0] [lindex $start 1] \
				[lindex $start 2] 24 0 0]
	    set task [get_current] 
	    write_task $current_task_start $midnight_yesterday $before_diff \
			$task
	
	    set current_task_start [list [lindex $current_time 0] \
		[lindex $current_time 1] [lindex $current_time 2] 0 0 0] 

	} else {
	    # Business as usual
	    set diff [time_diff $start_time $stop_time]
	}

        # Actually update the time
        .f.amount configure -text [format_time $diff]
    }
    if {[winfo exists .rpt]} {report_it}
    after $artts(update_rate) update_clock
}

#---------------------------------------------------------------
# time_part - gets the time part of a date-time list
#
# arguments:	date_time	date-time list (yy mm dd hh mm ss)
# returns: 	list - hh mm ss
#---------------------------------------------------------------
proc time_part {date_time} {
    return [list [lindex $date_time 3] [lindex $date_time 4] \
		[lindex $date_time 5] ]
}

#---------------------------------------------------------------
# date_part - gets the date part of a date-time list
#
# arguments:	date_time	date-time list (yy mm dd hh mm ss)
# returns: 	list - yy mm dd
#---------------------------------------------------------------
proc date_part {date_time} {
    return [list [lindex $date_time 0] [lindex $date_time 1] \
		[lindex $date_time 2] ]
}

#---------------------------------------------------------------
# format_time - put the time in seconds in a pretty format
#
# arguments:	seconds (int)
# returns:	formatted string hh:mm:ss
#---------------------------------------------------------------
proc format_time {seconds} {
    set hours [expr (($seconds / 3600) % 3600)]
    set minutes [expr (($seconds - ($hours * 3600)) / 60) % 60]
    set secs [expr ($seconds - ($hours * 3600) - ($minutes * 60))]
    return [format "%02i:%02i:%02i" $hours $minutes $secs]
}

#---------------------------------------------------------------
# write_task - write the start, stop, elapsed time and task to the db file
#
# arguments:	start 	list yy mm dd hh mm ss
# 		stop  	list yy mm dd hh mm ss
#		diff  	seconds difference between start and stop
#		task	name of task
# returns:	{}
#---------------------------------------------------------------
proc write_task {start stop diff task} {
    set file [open ~/.arttsdb a]
    puts $file "$start $stop $diff $task"
    close $file
    return {} 
}

#---------------------------------------------------------------------
# current_total - get the number of seconds for the current task so far
#---------------------------------------------------------------------
proc current_total {} {
    global current_task_start current_time current_task artts

    set task NONE
    set diff 0
    if {$current_task != -1} {
	set curr_time [get_date_time]
	set start_t [time_part $current_task_start]
	set stop_t [time_part $curr_time]
	set diff [time_diff $start_t $stop_t]
	set task [get_current]
    }
    return "{$task} {$diff}"
}

#---------------------------------------------------------------------
# report_it - displays a graphical task/time chart
#---------------------------------------------------------------------
proc report_it {} {
    global artts  tk_version

    if {![winfo exists .rpt]} {
	toplevel .rpt
	wm title .rpt "Artts Report"
	set geometry_string [format "200x200+%d+%d" $artts(rpt_x) $artts(rpt_y)]
	wm geometry .rpt $geometry_string
    }

    catch {destroy .rpt.canvas}
    canvas .rpt.canvas
    pack .rpt.canvas -fill both -expand yes

    set tasks [build_task_list "~/.arttsdb"]

    set current_state [current_total]

    set todays_tasks [total_today $tasks]
    set tot_time [total_time $todays_tasks]
    set totals_for_day [total_by_task $todays_tasks]

    # Setup initial coordinates
    set y 20
    set y2 30
    set index 0
    set something_printed 0
    set current_found 0

    # See if the current task is in the tasklist
    foreach i $totals_for_day {
	if {[lindex $i 0] == [lindex $current_state 0]} {
	    incr tot_time [lindex $current_state 1]
	    set current_found 1
	    break;
	}
    }

    set offset 5

    # Display the names of the tasks and a bar for each
    foreach i $totals_for_day {
	set day_time [lindex $i 1]
	if {$day_time != "" } {
	    if {[lindex $i 0] == [lindex $current_state 0]} {
		# This task matches the current task
		incr day_time [lindex $current_state 1]
	    }
	    set percent [expr ($day_time * 100) / $tot_time]
	    set dpercent [expr ($day_time * 100.0) / $tot_time]
	    .rpt.canvas create text $offset [expr $y - 15] -font "$artts(prop)"\
			-anchor nw -text "[lindex $i 0] \
			([format_time $day_time]) \
			[format "%.2f%s" $dpercent "%"]"
	    catch {.rpt.canvas create rectangle $offset $y \
			[expr $percent + $offset] \
			$y2 -fill [lindex $artts(colors) $index] }
	    incr y2 30
	    incr y 30
	    incr index
	    set index [expr $index % [llength $artts(colors)]]
	    set something_printed 1
	    lappend task_times [list $i $percent]
	}
    }
    if {$something_printed == 0 && [lindex $current_state 0] != "NONE"} {
	# Nothing has been printed show the current total time
	set day_time [lindex $current_state 1]
	set tot_time [lindex $current_state 1]
	set percent [expr ($day_time * 100) / $tot_time]
	set dpercent [expr ($day_time * 100.0) / $tot_time]
	.rpt.canvas create text $offset [expr $y - 15] \
			-anchor nw -text "[lindex $current_state 0] \
			([format_time $day_time]) \
			[format "%.2f%s" $dpercent "%"]"
	.rpt.canvas create rectangle $offset $y [expr $percent + $offset] $y2 \
			-fill [lindex $artts(colors) $index]
    } else {
	if {$current_found == 0 && [lindex $current_state 0] != "NONE"} {
	    # The current task is the first time today add it to the display
	    set day_time [lindex $current_state 1]
	    incr tot_time [lindex $current_state 1]
	    set percent [expr ($day_time * 100) / $tot_time]
	    set dpercent [expr ($day_time * 100.0) / $tot_time]
	    .rpt.canvas create text $offset [expr $y - 15] \
			-anchor nw -text "[lindex $current_state 0] \
			([format_time $day_time]) \
			[format "%.2f%s" $dpercent "%"]"
	    .rpt.canvas create rectangle $offset $y [expr $percent + $offset] \
			$y2 -fill [lindex $artts(colors) $index]
	}
    }

    # Set the size of the window depending on the size on the items in it.
    .rpt.canvas addtag all_tag all
    set bbox [.rpt.canvas bbox all_tag]
    if {$bbox != ""} {
        wm geometry .rpt [format "%sx%s" [lindex $bbox 2] $y2]
    }
}

#---------------------------------------------------------------
# Build a list containing all of the data from the database file
#
# arguments:	file_name  name of file containing the database
#
# returns:	list	index 	meaning
#			0	task name
#			1	total seconds
#			2	start time list yy mm dd hh mm ss
#			3	stop  time list yy mm dd hh mm ss
#---------------------------------------------------------------
proc build_task_list {file_name} {
    set task_list ""
    set file [open $file_name r]
    while {[eof $file] != 1} {
        set x [gets $file]
        set y [split $x]

        # The first 6 fields are the start time
        set start [lrange $y 0 5]
        # The second 6 fields are the stop time
        set stop [lrange $y 6 11]
        # The next field is the elapsed time
        set time [lindex $y 12]
        # The remaining fields are the task name
        set task [join [lrange $y 13 end] ]

        lappend tlist [list $task $time $start $stop]
    }
    return $tlist
}

#---------------------------------------------------------------------
# total_today - extract the tasks for today
#
# arguments:	task list
# returns:	task list of todays tasks
#---------------------------------------------------------------------
proc total_today {tlist} {
    global arttsrpt

    set day 0
    set task_list ""
    set dlist ""
    set first 0
    set last 0
    set out_list ""
    set today [get_ymd [get_date_time]]
    set this_day [get_ymd [get_start [lindex $tlist 0]]

    foreach i $tlist {
        set prev_day $day
        set day [get_day [get_start $i]]
        if {$day != $prev_day && $prev_day != 0} {
            # The day changed
            if {$this_day == $today} {
		# Start at the first -1 or the first task will be missed
                set out_list [lrange $tlist [expr ($first - 1)] [expr $last-1] ]
            }
            incr last
            set first $last
        } else {
            incr last
        }
        set this_day [get_ymd [get_start $i]]
    }
    return $out_list
}

#---------------------------------------------------------------------
# total_time - calculates total time on all tasks in seconds
#
# arguments:	task list
# returns:	seconds
#---------------------------------------------------------------------
proc total_time {tlist} {
    set total 0
    foreach i $tlist {
	if {[lindex $i 1] != ""} {incr total [lindex $i 1]}
    }
    return $total
}

#---------------------------------------------------------------------
# total_by_task - totals time for each task in a task list
#
# arguments:	l	task_list
# returns:	list 	list of lists each element consists of a task
#			and a total number of seconds
#---------------------------------------------------------------------
# Get the totals for each task from a tasklist
proc total_by_task {l} {
    foreach i $l {
        set task [get_task $i]
        if {[info exists total($task)]} {
            set total($task) [expr [get_seconds $i] + $total($task)]
        } else {
            set total($task) [get_seconds $i]
        }
    }

    set tot_list ""
    if {[info exists total]} {
	foreach j [array names total] {
            if {$j != ""} {
		lappend tot_list [list $j $total($j)]
	    }
        }
    }
    return $tot_list
}

#---------------------------------------------------------------------
# Convenience Procs for dealing with task list elements
#---------------------------------------------------------------------
proc get_ymd {time} { return [lrange $time 0 2] }
proc get_task {task_line} { return [lindex $task_line 0] }
proc get_seconds {task_line} { return [lindex $task_line 1] }
proc get_start {task_line} { return [lindex $task_line 2] }
proc get_stop {task_line} { return [lindex $task_line 3] }
proc get_year {time} { return [lindex $time 0] }
proc get_month {time} { return [lindex $time 1] }
proc get_day {time} { return [lindex $time 2] }
proc get_hms {time} { return [lrange $time 3 5] }

#
# Initialize the time values to the current time
#
catch {exec date +%H:%M:%S} time_value
scan $time_value "%2i:%2i:%2i" hours mins secs
catch {exec date +%d:%b:%y} date_value
scan $date_value "%2i:%3s:%2i" day month year

# Start the clock

set current_task_start [get_date_time]
set current_time [get_date_time]
update_clock

