#!/usr/local/bin/wish8.5 -f
#  'CBB' -- Check Book Balancer
#
#   balance.tcl -- Routines for balancing the account.
#
#  Written by Curtis Olson.  Started December 7, 1996.
#
#  Copyright (C) 1994 - 1997  Curtis L. Olson  - curt@sledge.mn.org
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id: balance.tcl,v 2.8 1997/04/03 03:40:00 curt Exp $
# (Log is kept at end of this file)


#------------------------------------------------------------------------------
# Procedures for balancing
#------------------------------------------------------------------------------

proc balance {} {
    global debits credits diff

    set debits 0.00
    set credits 0.00
    set diff [balanceCalcDiff]

    # create or bring forward window
    cbbWindow.bal

    # refresh the list
    balanceRefresh
}


# create window
proc cbbWindow.bal {} {
    global cbb debits credits diff

    if {[winfo exists .bal] == 1} {
	wm withdraw .bal
        wm deiconify .bal
	return                
    }

    toplevel .bal
    
    option add *font $cbb(dialog_font)

    wm title .bal "Balance ..."
    wm iconname .bal "Balance ..."
    frame .bal.frame -borderwidth 2 -relief raised
    frame .bal.frame.head1 -relief raised
    frame .bal.frame.head2 -relief raised
    frame .bal.frame.head3 -relief raised
    frame .bal.frame.f -relief raised
    frame .bal.frame.bar -relief sunken

    label .bal.frame.head1.label -text "Statement Starting Balance = "
    entry .bal.frame.head1.entry -textvariable cbb(state_start) -relief sunken \
	    -width 17 -font $cbb(default_font)
    label .bal.frame.head2.label -text "Statement Ending Balance   = "
    entry .bal.frame.head2.entry -textvariable cbb(state_end) -relief sunken \
	    -width 17 -font $cbb(default_font)
    label .bal.frame.head3.label \
    	    -text "Debits = $debits  Credits = $credits  Difference = $diff"

    listbox .bal.frame.f.list -width 47 -height 15 -relief sunken \
	-exportselection false -takefocus 0 \
	-yscrollcommand ".bal.frame.f.scroll set" -font $cbb(fixed_font)

    bind .bal <KeyPress-Down> { .bal.frame.f.list \
	    yview scroll 1 units }
    bind .bal <Control-KeyPress-n> { .bal.frame.f.list \
	    yview scroll 1 units }

    bind .bal <KeyPress-Up> { .bal.frame.f.list \
	    yview scroll -1 units }
    bind .bal <Control-KeyPress-p> { .bal.frame.f.list \
	    yview scroll -1 units }

    bind .bal <KeyPress-Next> { .bal.frame.f.list \
	    yview scroll 1 pages }
    bind .bal <Control-KeyPress-v> { .bal.frame.f.list \
	    yview scroll 1 pages }

    bind .bal <KeyPress-Prior> { .bal.frame.f.list \
	    yview scroll -1 pages }
    bind .bal <Alt-KeyPress-v> { .bal.frame.f.list \
	    yview scroll -1 pages }

    scrollbar .bal.frame.f.scroll -takefocus 0 -relief flat \
	    -command { .bal.frame.f.list yview }
	

    button .bal.frame.bar.refresh -text "Refresh" -font $cbb(button_font) \
	    -takefocus 0 -command { balanceRefresh }

    button .bal.frame.bar.update -text "Update" -font $cbb(button_font) \
	    -takefocus 0 -command {
	balanceUpdateSelected .bal.frame.f.list
	clear_entry_area
	destroy .bal
    }

    button .bal.frame.bar.dismiss -text "Dismiss" -font $cbb(button_font) \
	    -takefocus 0 -command {
	clear_entry_area
	destroy .bal
    }	

    pack .bal.frame -side top -fill both -expand 1
    pack .bal.frame.head1 -side top -fill x
    pack .bal.frame.head2 -side top -fill x
    pack .bal.frame.head3 -side top -fill x
    pack .bal.frame.bar -side bottom -fill x
    pack .bal.frame.f -side top -fill both -expand 1

    pack .bal.frame.head1.label .bal.frame.head1.entry -side left -anchor w
    pack .bal.frame.head2.label .bal.frame.head2.entry -side left -anchor w
    pack .bal.frame.head3.label -side top -anchor w
    pack .bal.frame.f.scroll -side right -fill y
    pack .bal.frame.f.list -side left -fill both -expand 1
    pack .bal.frame.bar.refresh .bal.frame.bar.update .bal.frame.bar.dismiss \
	    -side left -expand 1 -fill x -padx 8 -pady 4

    bind .bal.frame.head1.entry <FocusOut> {
        set diff [balanceCalcDiff]
        .bal.frame.head3.label configure \
    	     -text "Debits = $debits  Credits = $credits  Difference = $diff"
    }

    bind .bal.frame.head2.entry <FocusOut> {
        set diff [balanceCalcDiff]
        .bal.frame.head3.label configure \
    	     -text "Debits = $debits  Credits = $credits  Difference = $diff"
    }

    bind .bal.frame.f.list <Double-Button> {
	acctSetDirty
        balanceUpdateList .bal.frame.f.list [.bal.frame.f.list curselection]
        set diff [balanceCalcDiff]
        .bal.frame.head3.label configure \
    	     -text "Debits = $debits  Credits = $credits  Difference = $diff"
    }
    focus .bal.frame.head1.entry
}

# refresh balance window
proc balanceRefresh {} {
    global cbb eng debit debits credit credits desc cleared check nicedate 
    global cutdesc amt key index

    set debits 0.00
    set credits 0.00
    set diff [balanceCalcDiff]

    # wipe the current contents
    .bal.frame.f.list delete 0 end

    # get the statement starting balance
    puts $eng "get_cleared_bal"; flush $eng
    gets $eng cbb(state_start)

    # load the list
    puts $eng "first_uncleared_trans"; flush $eng
    gets $eng result
    while { $result != "none" } {
        update_globals $result

	# handles case where we have a $debit and a $credit
	set amt [expr $credit - $debit]

	set cutdesc [string range $desc 0 14]

        puts $eng "get_current_index"; flush $eng
        gets $eng index
	
        .bal.frame.f.list insert end \
		[format "%1s %5.5s %8s %-15s %12.2f   %-9s %5s"\
		$cleared $check $nicedate $cutdesc $amt $key $index]

        if { "$cleared" == "*" } {
	    set debits [expr $debits + $debit]
	    set credits [expr $credits + $credit]
        }

        puts $eng "next_uncleared_trans"; flush $eng
        gets $eng result
    }

    # avoid something like 6.5999999999999
    set debits [format "%.2f" $debits]
    set credits [format "%.2f" $credits]

    set diff [balanceCalcDiff]

    .bal.frame.head3.label configure \
	    -text "Debits = $debits  Credits = $credits  Difference = $diff"; \
}


proc balanceCalcDiff {} {
    global cbb debits credits

    set value [expr $cbb(state_start) - $cbb(state_end) - $debits + $credits]
    return [format "%.2f" $value]
}


# called when user double clicks on a line in the balance window
proc balanceUpdateList args {
    global cbb eng debits credits diff

    set arglist [split $args]
    set list [lindex $arglist 0]
    set sel [lindex $arglist 1]

    if { $cbb(debug) } { puts "$list $sel" }

    set line [$list get $sel]
    set key [string range $line 48 58]
    set index [expr [string range $line 60 64] * 2 - 1]
    set tail [string range $line 2 end]
    set amt [string range $line 34 45]
    if { $cbb(debug) } { puts "amt = $amt" }

    $list delete $sel
    if { "[string range $line 0 0]" != "*" } {
        $list insert $sel "* $tail"
        puts $eng "select_trans $key"; flush $eng
        gets $eng result
	if { $cbb(debug) } { puts $result }
	set pieces [split $result "\t"]
	set debit [lindex $pieces 4]
	set credit [lindex $pieces 5]

	if { "$credit" == "" } {
	    set credit 0.00
	}

	if { "$debit" == "" } {
	    set debit 0.00
	}

	set debits [expr $debits + $debit]
	set credits [expr $credits + $credit]
    } else {
        $list insert $sel "  $tail"
        puts $eng "unselect_trans $key"; flush $eng
        gets $eng result
	set pieces [split $result "\t"]
	set debit [lindex $pieces 4]
	set credit [lindex $pieces 5]

	if { "$credit" == "" } {
	    set credit 0.00
	}

	if { "$debit" == "" } {
	    set debit 0.00
	}

	set debits [expr $debits - $debit]
	set credits [expr $credits - $credit]
    }

    # avoid something like 6.5999999999999
    set debits [format "%.2f" $debits]
    set credits [format "%.2f" $credits]

    update_line $index $key

    if { $cbb(debug) } { puts $line; puts $key; puts $index }
}


proc balanceUpdateSelected list {
    global cbb eng

    .status.line configure -text "Updating all cleared transactions."
    update

    acctSetDirty

    puts $eng "clear_trans"; flush $eng
    gets $eng result

    update_rest 0 00000000-00

    goto [listGetSize]
}


# ----------------------------------------------------------------------------
# $Log: balance.tcl,v $
# Revision 2.8  1997/04/03 03:40:00  curt
# Fixed a small balance bug introduced recently.
#
# Revision 2.7  1997/03/05 18:58:32  curt
# Added additional bindings to scrolling lists: categories list, balance
# window list, text help, and report list.
#
# Revision 2.6  1997/02/19 18:08:05  curt
# Fixed a bug with long check numbers (> 5 char) in the balance window.
# Nailed a bug which caused cbb to forget the last check # entered when
# using +/- in the check number field.
#
# Revision 2.5  1997/01/02 04:38:30  curt
# Changes over the 1996 holidays:
#   - Converted listbox to text widget.  This allows us to do nice
#     things with alternating background colors, highliting, red
#     negative numbers, etc.
#   - Negative transactions are now drawn in red.
#   - Added a Goto <Today> option.
#   - <Home> & <End> were double bound.  Now, listbox can be traversed with
#     <Meta-Home> and <Meta-End>
#
# Revision 2.4  1996/12/17 20:15:43  curt
# Version incremented to 0.70.
# No longer save running total in .cbb files.
# Miscellaneous tweaks.
#
# Revision 2.3  1996/12/17 14:53:51  curt
# Updated copyright date.
#
# Revision 2.2  1996/12/11 04:15:14  curt
# Added a "Refresh" button.  Reworked some of the code.
#
# Revision 2.1  1996/12/08 07:37:50  curt
# Initial revision.
#
