#!/bin/sh
# Tcl sees the next lines as an assignment to variable `kludge'.
# For sh, the two shifts cancel the effect of the set, and then we
# run scotty on this script.

set kludge { $*
    shift
    shift
    if test -x ../scotty ; then
      exec ../scotty -nf $0 $*
    else
      exec scotty -nf $0 $*
    fi
}

##
## Copyright (c) 1993 St. Schoek
##                    TU Braunschweig, Germany
##                    Institute for Operating Systems and Computer Networks
##
## Permission to use, copy, modify, and distribute this
## software and its documentation for any purpose and without
## fee is hereby granted, provided that this copyright
## notice appears in all copies.  The University of Braunschweig
## makes no representations about the suitability of this
## software for any purpose.  It is provided "as is" without
## express or implied warranty.
##

##
## writes errormsg to stderr
##

proc scottyerror { msg } { 
    global errorInfo

    puts stderr "$msg\n$errorInfo"
}

##
## Delete an element from a list.
##

proc ldelete {list element} {
    upvar $list mylist
    set result ""
    foreach e $mylist {
        if {$e != $element} { lappend result $e }
    }
    return $result
}
 
##
## procedures for reading and setting the variables
##
##
## proc reads a list of filenames from 
##

proc read_data {} {
    global data_file
    global file_names

    if {[catch {open $data_file r} filehandle]} {
	syslog LOG_DEBUG "error: $filehandle" 
	exit
    }
    while {![eof $filehandle]} {
	if {[catch {gets $filehandle} line]} {
	    syslog LOG_DEBUG "error: $line" 
	    exit
	}
	if {$line != ""} {
	    foreach elem $line {
		lappend file_names $elem
	    }
	    break
	}
    }
    catch {close $filehandle}
}

##
## proc checks if files exists, delete if not
##

proc check_files {} {
    global file_names
    
    foreach file_elem $file_names {
	if {[catch {set a $file_elem} file_elem]} {
	    syslog LOG_DEBUG "error: syntax of filename-file not correct: \
                              $file_elem"
	    set file_names [ldelete file_names $file_elem]
	    continue
	}
	if {[llength $file_elem] != 2} {
	    set mess "error: syntax of filename-file not correct" 
	    syslog LOG_DEBUG $mess
	    set file_names [ldelete file_names $file_elem]
	    continue
	}
	if {$file_names == ""} {
	    syslog LOG_DEBUG "error: no filenames given to calculate.tcl"
	    set file_names [ldelete file_names $file_elem]
	    continue
	}  
	for {set i 0} {$i < "2"} {incr i} {
	    set name [lindex $file_elem $i]
	    if {![file exists $name]} {
		set file_names [ldelete file_names $file_elem]
	    }
	}
    }
}

##
## proc writes data to file
## periode gives the value for the index it can be 15_periode or 1h_periode
## interval_start is the time when the calculating of this periode
## was started
##

proc write_data {interval_start periode} {
    global variable_control_table
    global variable_control_count
    global variable_data
    global statistic_file 

    case $periode in {
	{15_periode} {
	    set interval           900
	    set periode_count      15_value_count
	    set periode_res        15_res
	    set periode_peak       15_peak
	    set periode_peak_time  15_peak_time
	    set high_peak          1h_15_peak
	    set high_peak_time     1h_15_peak_time
	    set high_peak_plus     24h_15_peak
	    set high_peak_plus_time 24h_15_peak_time
	}
	{1h_periode} {
	    set interval           3600
	    set periode_count      1h_value_count
	    set periode_res        1h_res
	    set periode_peak       1h_peak
	    set periode_peak_time  1h_peak_time
	    set high_peak          24h_1h_peak
	    set high_peak_time     24h_1h_peak_time
	}
	{24h_periode} {
	    set interval           86400
	    set periode_count      24h_value_count
	    set periode_res        24h_res
	    set periode_peak       24h_peak
	    set periode_peak_time  24h_peak_time
	}
    }
    
    if {[catch {open $statistic_file a} filehandle]} {
	syslog LOG_DEBUG "can not open $statistic_file $filehandle"
	exit
    }
    
    for {set i 0} {$i <= $variable_control_count} {incr i} {
	## it can be that there are variables which was not measured
	## in that interval, because their periode was not
	## corresponding to the remaining interval time
	set tag [lindex $variable_control_table($i,var) 2]
	set var_periode [lindex $variable_control_table($i,var) 1]
	set peak_time $variable_data($tag,$periode_peak_time)
	set res0 $variable_data($tag,$periode_res) 
	set div $variable_data($tag,$periode_count)
	if {$div != 0} {
	    set res [expr {$res0 / $div}]
	} else  {
	    set res -1
	    set res0 -1
	}
	set dat $variable_data($tag,$periode_peak)
	case $variable_data($tag,measurement) in {
	    {Gauge} {
		set highres $res
		set res1 "$tag $var_periode aver $res peak $dat peak_time \
                           $peak_time  total -1"
	    } 
	    {TimeTicks} {
		set highres -1
		set res1 "$tag $var_periode aver -1 peak $dat peak_time\
                          $peak_time total -1"
	    }
	    {default} {
		set highres $res0
		set res1 "$tag $var_periode aver $res peak $dat peak_time\
                          $peak_time total $res0"
	    }
	}
	if {$periode != "24h_periode"} {
	    if {$highres > $variable_data($tag,$high_peak)} {
		## set the value from 1h_15_peak
		## or from 24h_1h_peak
		set variable_data($tag,$high_peak) $highres
		set variable_data($tag,$high_peak_time) $interval_start
	    }
	}
	if {$periode == "15_periode"} {
	    ## set the value from 24h_15_peak
	    if {$highres > $variable_data($tag,$high_peak_plus)} {
		set variable_data($tag,$high_peak_plus) $highres	
		set variable_data($tag,$high_peak_plus_time) $interval_start
	    }
	}
	set variable_data($tag,$periode_peak)      -1
	set variable_data($tag,$periode_peak_time) -1
	set variable_data($tag,$periode_count)     0
	set variable_data($tag,$periode_res)       0
	if {$periode == "1h_periode"} {
	    ## reset the values for aggregating new values of the next
	    ## 1h interval
	    lappend res1 1h_15_peak
	    lappend res1 $variable_data($tag,1h_15_peak)
	    lappend res1 1h_15_peak_time
	    lappend res1 $variable_data($tag,1h_15_peak_time)
	    set variable_data($tag,1h_15_peak) -1
	    set variable_data($tag,1h_15_peak_time) -1
	}
	if {$periode == "24h_periode"} {
	    lappend res1 24_15_peak
	    lappend res1 $variable_data($tag,24h_15_peak)
	    lappend res1 24_15_peak_time
	    lappend res1 $variable_data($tag,24h_15_peak_time)
	    lappend res1 24_1h_peak
	    lappend res1 $variable_data($tag,24h_1h_peak)
	    lappend res1 24_1h_peak_time
	    lappend res1 $variable_data($tag,24h_1h_peak_time)
	}
	lappend res2 $res1
    }
    set result $interval_start
    lappend result "[list $interval $res2]"
    catch {puts $filehandle $result}
    catch {close $filehandle}
}

##
## proc sets values of variable_data 
## periode gives the value for the index it can be 15_periode or 1h_periode
## in line_data are the values for the variables 
## option is to detect if we must add the values from line_data to the
## old one or if we must set the variables new
##

proc set_values {line_data periode current_time option} {
    global variable_data
    
    case $periode in {
	{15_periode} {
	    set periode_count      15_value_count
	    set periode_res        15_res
	    set periode_peak       15_peak
	    set periode_peak_time  15_peak_time
	}
	{1h_periode} {
	    set periode_count      1h_value_count
	    set periode_res        1h_res
	    set periode_peak       1h_peak
	    set periode_peak_time  1h_peak_time
	}
	{24h_periode} {
	    set periode_count      24h_value_count
	    set periode_res        24h_res
	    set periode_peak       24h_peak
	    set periode_peak_time  24h_peak_time
	}
    }

    foreach elem $line_data {
	set tag [lindex $elem 0]
	set value [lindex $elem 1]
	if {$value != -1} {
	    if {$option == "add"} {
		if {$variable_data($tag,$periode_peak) < $value} {
		    set variable_data($tag,$periode_peak)      $value
		    set variable_data($tag,$periode_peak_time) $current_time
		}
		if {$variable_data($tag,measurement) != "TimeTicks"} {
		    incr variable_data($tag,$periode_count)
		    set dat [expr {$variable_data($tag,$periode_res) + $value}]
		    set variable_data($tag,$periode_res) $dat
		} else {
		    set variable_data($tag,$periode_count) 1
		    set variable_data($tag,$periode_res)   $value
		}
	    } 
	    if {$option == "set" } {
		## we only sets the incoming values to the structures
		## the others are set to null in write_data 
		set variable_data($tag,$periode_peak)      $value
		set variable_data($tag,$periode_peak_time) $current_time
		set variable_data($tag,$periode_count)     1
		set variable_data($tag,$periode_res)       $value
	    }
	} else {
	    set dat [expr {$variable_data($tag,$periode_res) + 0}]  
	    set variable_data($tag,$periode_res) $dat
	}
    }
}

##
## proc reads values from header_files
##

proc read_header_data {headerfilename datafilename} {
    global variable_control_table
    global variable_control_count
    global variable_data

    ## unset all vars, because we can have more than one data_file
    if {[info exists variable_control_count]} {
	for {set i 0} {$i <= $variable_control_count} {incr i} {
	    catch {unset variable_control_table($i,host)}
	    catch {unset variable_control_table($i,data_file)}
	    set tag [lindex $variable_control_table($i,var) 2]
	    catch {unset variable_control_table($i,var)}
	    catch {unset variable_data($tag,measurement)}

	    catch {unset variable_data($tag,15_peak)}
	    catch {unset variable_data($tag,15_res)}
	    catch {unset variable_data($tag,15_peak_time)}
	    catch {unset variable_data($tag,15_value_count)}

	    catch {unset variable_data($tag,1h_peak)}
	    catch {unset variable_data($tag,1h_res)}
	    catch {unset variable_data($tag,1h_peak_time)}
	    catch {unset variable_data($tag,1h_15_peak)}
	    catch {unset variable_data($tag,1h_15_peak_time)}
	    catch {unset variable_data($tag,1h_value_count)}

	    catch {unset variable_data($tag,24h_res)}
	    catch {unset variable_data($tag,24h_peak)}
	    catch {unset variable_data($tag,24h_peak_time)}
	    catch {unset variable_data($tag,24h_15_peak)}
	    catch {unset variable_data($tag,24h_15_peak_time)}
	    catch {unset variable_data($tag,24h_1h_peak)}
	    catch {unset variable_data($tag,24h_1h_peak_time)}
	    catch {unset variable_data($tag,24h_value_count)}
	}
 	catch {unset tag}
	catch {unset variable_control_count}
    }
    set header_name [lindex $headerfilename 0]
    if {[catch {open $header_name r} filehandle]} {
	syslog LOG_DEBUG "error: $filehandle"
	return
    }
    if {[catch {gets $filehandle} line]} {
	syslog LOG_DEBUG "error: $line"
	return
    }
    while {![eof $filehandle]} {
	if {[lindex $line 0] == "DEVICE"} {
	    set host [lindex $line 1]
	}
	if {[catch {gets $filehandle} line]} {
	    syslog LOG_DEBUG "error: $line"
	    return
	}
	if {[lindex $line 0] == "variablename"} {
	    if {[catch {gets $filehandle} line]} {
		syslog LOG_DEBUG "error: $line"
		return
	    }
	    while {(![eof $filehandle]) && ([lindex $line 0] != "DEVICE") \
		&& ([lindex $line 0] != "END_DEVICE_SECTION") } {
		    if {$line != ""} {
			if {![info exists variable_control_count]} {
			    set variable_control_count 0
			} else {
			    incr variable_control_count
			}
			set tmp $variable_control_count
			set variable_control_table($tmp,host) $host
			set variable_control_table($tmp,data_file) \
                            $datafilename
			set variable_control_table($tmp,var)  $line
		    }
		    if {[catch {gets $filehandle} line]} {
			syslog LOG_DEBUG "error: $line"
			return
		    }
		}
	}
    }
    catch {close $filehandle}
}

##
## proc reads values from data_files and append the read values to
## variable_control_table
##

proc read_data_files {} {
    global file_names
    global statistic_file 
    global variable_control_table
    global variable_control_count
    global variable_data
    
    set 15_periode 900
    set 1h_periode 3600

    foreach file_elem $file_names {
	set headerfilename [lindex $file_elem 0]
	set data_name  [lindex $file_elem 1]
	read_header_data $headerfilename $data_name

	## get information about the filenames, so that we can
	## give the corresponding filename to the statisticalfile
 	set file_header [file dirname $headerfilename]
	set day [lindex [split $headerfilename -] 2]
	set extension "-[lindex [split $headerfilename -] 3]"
	if {$extension == "-"} {
	    set extension ""
	}
	set statistic_file "$file_header/statistical-data-$day$extension"

	if {[catch {open $data_name r} filehandle]} {
	    syslog LOG_DEBUG "can not open $data_name $filehandle" 
	    continue
	}
	for {set i 0} {$i <= $variable_control_count} {incr i} {
	    set tag [lindex $variable_control_table($i,var) 2]
	    set variable_data($tag,measurement) [lindex \
                                        $variable_control_table($i,var) 3] 

	    set variable_data($tag,15_res)         0
	    set variable_data($tag,15_peak)        -1
	    set variable_data($tag,15_peak_time)   -1
	    set variable_data($tag,15_value_count) 0

	    set variable_data($tag,1h_res)         0
	    set variable_data($tag,1h_peak)        -1
	    set variable_data($tag,1h_peak_time)   -1
	    set variable_data($tag,1h_15_peak)     -1
	    set variable_data($tag,1h_15_peak_time) -1
	    set variable_data($tag,1h_value_count) 0

	    set variable_data($tag,24h_res)         0
	    set variable_data($tag,24h_peak)        -1
	    set variable_data($tag,24h_peak_time)   -1
	    set variable_data($tag,24h_15_peak)     -1
	    set variable_data($tag,24h_15_peak_time) -1
	    set variable_data($tag,24h_1h_peak)     -1
	    set variable_data($tag,24h_1h_peak_time) -1
	    set variable_data($tag,24h_value_count) 0

	}
	if {[catch {gets $filehandle} line]} {
	    syslog LOG_DEBUG "error: $line"
	    continue
	}
	while {![eof $filehandle]} {
	    ## set times
	    ## calculate them so that we can predestinate
	    ## the endtime for each periode
	    ## the start and endtimes are calculated in ticks
	    ## but we get the first time periode_name_interval_start
	    ## from the datafile
	    set timestamp [lindex [list [lindex $line 0]] 0]
	    set line_data [lindex $line 1]
	    set hh [lindex [split [lindex $timestamp 3] :] 0]
	    set min  [lindex [split [lindex $timestamp 3] :] 1]
	    set current_time "$hh:$min"
	    set data_time [lindex [split [expr {[expr {$hh * 3600}] + \
                                                [expr {$min * 60}]}] .] 0]
	    
	    if {![info exists 15_interval_start]} {
		set 15_interval_start $current_time
		set 1h_interval_start $current_time
		set 24h_interval_start $current_time
		set starttime [lindex [split [expr [expr {$data_time / \
                                                       900}] * 900] .] 0]
		set 15_endtime [expr {$starttime + $15_periode}]
		set starttime [lindex [split [expr [expr {$data_time / \
                                                       3600}] * 3600] .] 0]
		set 1h_endtime [expr {$starttime + $1h_periode}]
	    }
	    ## check if we are already in the periode
	    ## if yes set new values 
	    if {$data_time < $15_endtime} {
		set_values $line_data 15_periode  $current_time add
		set_values $line_data 1h_periode  $current_time add
		set_values $line_data 24h_periode $current_time add
	    } else {
		## if not write data to file
		## and set new values
		write_data $15_interval_start 15_periode 
		## set the new values with the correct time
		set_values $line_data 15_periode $current_time set
		##
		## set the values for the 24h-hour periode correct
		set_values $line_data 24h_periode $current_time add
		## calculate new endtimes and startimes for the periode
		## check if we are in the right interval given by
		## interval-start 
		## and interval-end
		while {$data_time >= $15_endtime} {
		    set 15_endtime [expr {$15_endtime + $15_periode}]
		    set 15_interval_start $current_time
		}
		## for the 1-hour values we must check if we are reaching
		## the endtime of the
		## 1 hour endtime 
		if {$data_time >= $1h_endtime} {
		    ## we are not in the periode
		    ## write data  to file
		    ## and set new values
		    write_data $1h_interval_start 1h_periode
		    set_values $line_data 1h_periode $current_time set
		    ## calculate new endtimes and startimes for the periode
		    ## check if we are in the right interval given by
		    ## interval-start 
		    ## and interval-end
		    while {$data_time >= $1h_endtime} {
			set 1h_endtime [expr {$1h_endtime + $1h_periode}]
			set 1h_interval_start $current_time
		    }
		} else {
		    ## we are still in the 1h periode
		    ## only set new values
		    set_values $line_data 1h_periode $current_time add
		} 
	    }
	    if {[catch {gets $filehandle} line]} {
		syslog LOG_DEBUG "error: $line"
		break
	    }
	}
	## last line was read, and the 15-periode result was not written
	## to file
	## now calculate the last averages and etc. for last 15-periode
	write_data $15_interval_start 15_periode 
	write_data $1h_interval_start 1h_periode
	write_data $24h_interval_start 24h_periode
	catch {close $filehandle}
	unset 15_interval_start
	unset 1h_interval_start
	unset 24h_interval_start
    }
}

proc main {} {
    global argv 
    global data_file 
    global file_names
    
    if {[llength $argv] != 1} {
	puts stderr "error calc-tool: wrong number of arguments"
	flush stderr
	exit
    }

    ## set some important variables 
    ## we get them by reading argv
 
    set data_file "$argv/statconf"
    set file_names ""

    ## end

    read_data

    check_files

    read_data_files

}

main
