#!/usr/bin/wish -f
#  graphbal - Graph running balance
#
#  Written by Arlindo L. Oliveira (aml@inesc.pt)
#
#  Copyright (C) 1996  Arlindo L. Oliveira (aml@inesc.pt)
#
# $Id: graphbal,v 0.9.0.1 2001/01/17 20:26:04 genemagnier Exp $


set data(0,0) " "
set data(0,1) " "
set cnt 1
while {[gets stdin line] >= 1} {
     set data($cnt,0) [lindex $line 0]
     set data($cnt,1) [lindex $line 1]
     if {$data($cnt,0) == $data([expr $cnt-1],0)} {
         set data([expr $cnt-1],1)  $data($cnt,1)
     } else {
         incr cnt
     }
}


set gm0 15
set gm1 60
set gm2 30
set gm3 15

proc graphData {graph row col} {
    global data
    return $data($row,$col)
}

proc graphCols {canvas} {
    return 1
}

proc graphRows {canvas} {
    global cnt
    return [expr $cnt-1]
}

#
# createColumnGraph
# rows : number of data rows 1 ... rows
# cols : number of data cols 1 ... cols
# data(0,i) contains data labels
# data(i,0) contains abcissa labels
#

set barColors(1) "blue"
set barColors(2) "green"
set barColors(3) "red"
set barColors(4) "yellow"
set barColors(5) "brown"

proc graphColor {i} {
    global barColors
    return $barColors($i)
}

proc defGraphMargin {} {
    return 60
}

proc defGraphHeight {} {
    return 300
}

proc defGraphWidth {} {
    return 450
}

proc defGraphWinHeight {} {
#    return [expr [defGraphHeight]+2*[defGraphMargin]]
    global gm0 gm1 gm2 gm3
    return [expr [defGraphHeight]+$gm0+$gm2]
}

proc defGraphWinWidth {} {
#    return [expr [defGraphWidth]+[defGraphMargin]+[defGraphMargin]]
    global gm0 gm1 gm2 gm3
    return [expr [defGraphWidth]+$gm1+$gm3]
}

proc cutZero {st} {
    if {[string range $st 0 0] == 0} {
        return [string range $st 1 2]
    } else {
        return $st
    }
}

set months(01) Jan
set months(02) Feb
set months(03) Mar
set months(04) Apr
set months(05) May
set months(06) Jun
set months(07) Jul
set months(08) Aug
set months(09) Sep
set months(10) Oct
set months(11) Nov
set months(12) Dec

proc month {date} {
    global months
    return $months([string range $date 4 5])
}

proc year {date} {
    return [string range $date 0 3]
}

proc monthval {date} {
    return [cutZero [string range $date 4 5]]
}

proc day {date} {
    return [cutZero [string range $date 6 7]]
}

proc daysBetween {first last} {
    set y1 [string range $first 0 3]
    set m1 [cutZero [string range $first 4 5]]
    set d1 [cutZero [string range $first 6 7]]

    set fm [expr int (($m1 - 14) / 12.0)]
    set mj1 [expr $d1 + int(1461*($y1 + 4800 + $fm)/4) + int(367*($m1 - 2 - 12*$fm)/12) - int(3*int(($y1 + 4900 + $fm)/100)/4)]

    #f1 = (int)((nowtm.tm_mo - 14)/12)
    #jd = day + (int)(1461*(year + 4800 + f1)/4) + (int)(367*(mo - 2 - f1*12)/12) - (int)(3*(int)((year + 4900 + f1)/100)/4);

    set y1 [string range $last 0 3]
    set m1 [cutZero [string range $last 4 5]]
    set d1 [cutZero [string range $last 6 7]]

    set fm [expr int (($m1 - 14) / 12.0)]
    set mj2 [expr $d1 + int(1461*($y1 + 4800 + $fm)/4) + int(367*($m1 - 2 - 12*$fm)/12) - int(3*int(($y1 + 4900 + $fm)/100)/4)]

    # we use a modified version of Julian day (dropping constants) to get the true days between
    # seems to have a problem at jan 31 / feb 28,29??  check formula

    return [expr $mj2 - $mj1]
}

proc normalize {value} {
    global logten

    set logten 0

    while {$value >= 10} {
      set value [expr $value/10]
      incr logten
      }

   return $value
}


proc createColumnGraph {graphName {canv 0}} {
    global graphCnt canvas logten
    global gm0 gm1 gm2 gm3

    set cols [graphCols $graphName]
    set rows [graphRows $graphName]

    wm withdraw .
    if {$canv == 0} {
        toplevel .graph$graphCnt
        set canvas [canvas .graph$graphCnt.graph -width [defGraphWinWidth] \
                -height [defGraphWinHeight] -bg white]
        button .graph$graphCnt.dismiss -text dismiss \
                -command {destroy .}
        button .graph$graphCnt.print -text Print \
                -command {
                        toplevel .m
                        message .m.msg -font 12x24 -text "Printing to file bal.ps"
                        pack .m.msg
                        wm geometry .m +300+300
                        after 2000 {destroy .m}
                        $canvas postscript -file bal.ps -pagewidth 19c
                }


    }

    pack $canvas 
    pack .graph$graphCnt.dismiss -fill x
    pack .graph$graphCnt.print -fill x

    
    #
    # Width of each bar
    #
    
    set gw [defGraphWidth]
    set gh [defGraphHeight]
    set gm [defGraphMargin]

    $canvas create rectangle $gm1 $gm0 [expr $gm1+$gw] [expr $gm0+$gh] \
        -fill gray80 -outline black


    set max 0
    set min 0
    for {set j 1} {$j <= $cols} {incr j} {
        for {set i 1} {$i <= $rows} {incr i} {
            set x [graphData graphName $i $j]
            if {$x < $min} {set min $x}
            if {$x > $max} {set max $x} 
        }
    }

    set max_min_diff 1.0
    if {$max > [expr $min+1]} {set max_min_diff [expr $max-$min]}


    #
    # Auto-scaling
    #

    set dy [normalize [expr $max_min_diff/10]]

    #  5<dy<10  --> dy=10
    #  2<dy<=5  --> dy=5
    #  1<dy<=2  --> dy=2
    #  1<=dy    --> dy=1

    if { $dy > 5 } {
     set dy 10
    } else { if { $dy > 2 } {
     set dy 5
    } else { if { $dy > 1 } {
     set dy 2
    } else {
     set dy 1
    } } }

    set dy [expr $dy*pow(10,$logten)]

    set mintick [expr int($min/$dy)]
    if { $mintick < 0 } { set mintick [expr $mintick-1] }
    set maxtick [expr int($max/$dy+1)]
    if { $maxtick < 0 } { set mintick [expr $maxtick-1] }

    set min [expr $dy*$mintick]
    set max [expr $dy*($maxtick+0.3)]

    set max_min_diff [expr $max-$min]


    set yscale [expr $gh/($max_min_diff)]
    set zero [expr $gh+$gm0+$min/($max_min_diff)*$gh]
    set nlevels [expr $rows/8]
    set ndays [daysBetween [graphData $graphName 1 0] \
        [graphData $graphName $rows 0]]
    if {$ndays !=  0} {
	set xscale [expr $gw/1.0/$ndays]
    } else {
	set xscale [expr $gw/1.0]	
    }


    #
    # Draw axes
    # 

    $canvas create line $gm1 $zero [expr $gm1+$gw] $zero
    $canvas create line $gm1 [expr $gm0+$gh] $gm1 $gm0  -arrow last

    for {set i $mintick} {$i <= $maxtick} {incr i} {
        set val [expr $i*$dy]
        if {$val <= $max && $val >= $min} {
            $canvas create text [expr $gm1-8] [expr $zero-$val*$yscale] \
		    -text $val -anchor e
            $canvas create line $gm1 [expr $zero-$val*$yscale] \
                               [expr $gm1-5] [expr $zero-$val*$yscale]
        }
    } 

    #
    # Draw a tic marking the final balance for period graphed.
    #

    set finbal [graphData $graphName $rows 1]
    $canvas create line $gm1 [expr $zero-$finbal*$yscale] \
                  [expr $gm1-5] [expr $zero-$finbal*$yscale] -fill red



    # find date range, set date scale:
    set firstdate [graphData $graphName 1 0]
    set lastdate [graphData $graphName $rows 0]

    set nday [daysBetween $firstdate $lastdate]

    puts "nday: $nday"
 
    set dday 0
    set dmonth 0
    if {$nday >   0 && $nday <=   20} { set dmonth 1 ; set dday  1 }
    if {$nday >  20 && $nday <=   60} { set dmonth 1 ; set dday  7 }
    if {$nday >  60 && $nday <=  180} { set dmonth 1 ; set dday 15 }
    if {$nday > 180 && $nday <=  360} { set dmonth 2 }
    if {$nday > 360 && $nday <=  720} { set dmonth 3 }
    if {$nday > 720 && $nday <= 1500} { set dmonth 6 }

    if {$dmonth > 0} {
	# write the months
	set y1 [year $firstdate]
	set y2 [year $lastdate]
	
	set m1 [monthval $firstdate]
	set m2 [expr 12*($y2-$y1) + [monthval $lastdate]]
	
	set j [expr $m1 - ($m1 % $dmonth) + 1]
	for {set i $m1} {$i <= $m2} {incr i $dmonth} {
	    if {$j > 12} {
		set y1 [expr $y1 + ($j / 12)]
		set j  [expr $j % 12]
	    }
	    set date [format "%4s%02d01" $y1 $j]
	    puts "date: $date, $y1, $i, $j"
	    set x1 [daysBetween $firstdate $date]
	    if {$x1 > 0} {
		set mt [month $date]
		$canvas create text [expr $gm1+$x1*$xscale+2] [expr $gm0+$gh+10] -anchor w -text $mt
		$canvas create line [expr $gm1+$x1*$xscale] [expr $gm0+$gh+10] [expr $gm1+$x1*$xscale] [expr $gm0+$gh]
	    } else {
		if {$x1 > -20} {
		    set mt [month $date]
		    $canvas create text [expr $gm1+2] [expr $gm0+$gh+10] -anchor w -text $mt
		}
	    }	    
	    incr j $dmonth
	}
    }

    # write the years
    set y1 [year $firstdate]
    set y2 [year $lastdate]
    set dyear 1
    
    # if $y1 == $y2, print year in plot center
    for {set i $y1} {$i <= $y2} {incr i $dyear} {
	set date [format "%4s0101" $i]
	puts "date: $date, $y1, $i"
	set x1 [daysBetween $firstdate $date]
	if {$x1 > 0} {
	    $canvas create text [expr $gm1+$x1*$xscale+2] [expr $gm0+$gh+25] -anchor w -text $i
	    $canvas create line [expr $gm1+$x1*$xscale] [expr $gm0+$gh+25] [expr $gm1+$x1*$xscale] [expr $gm0+$gh]
	} else {
	    if {$x1 > -20} {
		$canvas create text [expr $gm1+2] [expr $gm0+$gh+25] -anchor w -text $i
	    }
	}	    
    }

    if {$dday > 0} {
	# write the days
	set d1 [day $firstdate]
	set d2 [expr [day $lastdate] + 30*($m2 - $m1)]
	
	set j [expr $d1 - ($d1 % $dday)]
	for {set i $d1} {$i <= $d2} {incr i $dday} {
	    if {$j > 30} {
		set di [expr $j - 31]
		set j 1
		set i [expr $i - $di]
	    }
	    set x1 [expr $i - $d1]
	    puts "day $i $j\n"
	    if {$x1 > 0} {
		$canvas create text [expr $gm1+$x1*$xscale+2] [expr $gm0+$gh+25] -anchor w -text $j
		$canvas create line [expr $gm1+$x1*$xscale] [expr $gm0+$gh+25] [expr $gm1+$x1*$xscale] [expr $gm0+$gh] -fill red
	    } else {
		if {$x1 > -20} {
		    $canvas create text [expr $gm1+2] [expr $gm0+$gh+25] -anchor w -text $j
		}
	    }	    
	    incr j $dday
	}
    }

    # plot the balance
    set startday [graphData $graphName 1  0]
    for {set i 2} {$i <= $rows} {incr i} {
	set d [graphData $graphName [expr $i-1] 0]
        set x1 [daysBetween $startday [graphData $graphName [expr $i-1] 0]]
        set x2 [daysBetween $startday [graphData $graphName $i 0]]
	# puts "$d - $startday -- $x1"
	set y1 [graphData $graphName [expr $i-1] 1] 
	set y2 [graphData $graphName $i 1] 
	set nb 1
	if { [expr {$y1 < 0} || {$y2 < 0} ] } { 
	    if { [expr {$y1 < 0} && {$y2 < 0} ] } { 
		set color red
	    } else {
		set dx [expr $y1 * ($x2-$x1) / ($y2-$y1)]
		set xi [expr $x1 - $dx]
		set yi 0
		set nb 1
		puts "$x1 $y1, $x2 $y2 $dx $xi"
	    }
	} else {
            set color black
	}
	
	if { $nb } {
	    $canvas create line \
		    [expr $gm1+$x1*$xscale] [expr $zero-$y1*$yscale] \
		    [expr $gm1+$x2*$xscale] [expr $zero-$y2*$yscale] -fill $color
	} else {
	    if {$y1 > 0} { set color black } else { set color red}
	    $canvas create line \
               [expr $gm1+$x1*$xscale] [expr $zero-$y1*$yscale] \
               [expr $gm1+$xi*$xscale] [expr $zero-$yi*$yscale] -fill $color

	    if {$y2 > 0} { set color black } else { set color red}
	    $canvas create line \
               [expr $gm1+$xi*$xscale] [expr $zero-$yi*$yscale] \
               [expr $gm1+$x2*$xscale] [expr $zero-$y2*$yscale] -fill $color
	}
    }

    
}
set graphCnt 0
createColumnGraph lixo 0


#        $canvas create polygon \
#               [expr $gm1+$x1*$xscale] [expr $zero-[graphData $graphName [expr $i-1] 1]*$yscale] \
#               [expr $gm1+$x2*$xscale] [expr $zero-[graphData $graphName $i 1]*$yscale] \
#               [expr $gm1+$x2*$xscale] $zero \
#               [expr $gm1+$x1*$xscale] $zero \
#               -fill $color
