#!/bin/sh

# Tcl/Tk front-end to the btg program
# Written by David Bindel

# This is a trick to get sh to start wish regardless of where
# it is located from system to system.
# \
exec wish -f "$0" ${1+"$@"}

##############################################################
# System specific settings
##############################################################

# These settings should be tailored for your installation
# Set the btg_program variable to the fully pathed name of the
#   btg engine program
# Set the btg_help variable to the fully pathed name of the
#   btg help file

set btg_program "~/class/stat/btg013/bin/btg-linux"
set btg_help "~/class/stat/btg013/btghelp.txt"

##############################################################
# Description of program / global variables
##############################################################

# The file selection box was adapted from public domain sources
# (see the copyright notices).  Some of the auxiliary routines
# are adapted from example code in Brent Welch's book
# "Practical Programming in Tcl and Tk"
# (I didn't use any of the code verbatim, but I got many of my
#  ideas for the interface from that book).
# Distribution plots are done using gnuplot.

# The tkbtg Tcl/Tk script provides a friendly interface to the
# btg prediction program.  The interface communicates with the
# driver program via a Unix pipe.
# The protocol used to communicate through the pipeline is:
#   tkbtg sends a command line (whitespace separated)
#   btg sends back two lines:
#     line 1 is a status flag (1 for success, 0 for failure)
#     line 2 is the output list (if successful),
#            or the error message (if unsuccessful)
# The output list passed back may be empty.
# Since input and output lists are just space-separated text,
# it is not necessary to translate any of the messages.

# The following globals are used by the program:
#
# btg_program - name/location of the btg program
#
# btg_path - path to the default directory; default is ~/btg_data
#
# btg_ready - flag used to selectively block program actions while
#   the computational engine is doing its thing.  btg_ready is 1
#   by default, unless the interface is waiting for output from
#   the pipe after a command
#
# btg_return_value - list containing the return codes from the
#   most recent command to btg
#
# btg_fid - file identifier for pipe to the btg program
#
# gnuplot_fid - file identifier for pipe to the gnuplot program
#
# fileselect() - array used to hold state information for
#   the file selection dialog
#
# btgpt() - array used to hold state information from the
#   point selection dialog
#
# btgmap() - array used to hold state information from the
#   map specification dialog
#
# btg_range_min, btg_range_max - specify the range of z0
#   for computing p(z0 | z)
#
# btg_mesh_size - determines the discretization of the range
#   of z0.  Used directly for plotting, and indirectly for
#   prediction (governs target precision for root finding).
#
# btg_sample_size - size of the random sample used in Monte Carlo
#   integration
#
# btg_trend_order - order of the (polynomial) covariate structure
#   to be used for the underlying Gaussian random field
#
# btg_lambda_min, btg_lambda_max - range of values to be considered
#   for the transformation index parameter lambda
#
# btg_correlation - name of the correlation function
#

##############################################################
# File selection box module
# Adapted from public domain sources.
##############################################################

#
# fileselect.tcl --
# simple file selector.
#
# Mario Jorge Silva			          msilva@cs.Berkeley.EDU
# University of California Berkeley                 Ph:    +1(510)642-8248
# Computer Science Division, 571 Evans Hall         Fax:   +1(510)642-5775
# Berkeley CA 94720                                 
# 

# Layout:
#
#  file:                  +----+
#  ____________________   | OK |
#                         +----+
#
#  +------------------+    Cancel
#  | ..               |S
#  | file1            |c
#  | file2            |r
#  |                  |b
#  | filen            |a
#  |                  |r
#  +------------------+
#  currrent-directory
#
# Copyright 1993 Regents of the University of California
# 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 California
# makes no representations about the suitability of this
# software for any purpose.  It is provided "as is" without
# express or implied warranty.
#

# Copyright 1996

# Slight modifications to and adoption to Tk4.0 were made to this
# fileselectionbox code by Lakshmi Sastry, Rutherford Appleton Laboratory,
# chilton, Didcot, OXON, OX11 0QX, UK.

# You can now type in a non-existing file name as well. This file name is
# returned for the application to open a new file to write to 

# AGOCG Tcl/Tk Cookbook
# Authors

# Lakshmi Sastry
# Computing and Information Systems Department
# Rutherford Appleton Laboratory, Chilton, Didcot. OX11 0QX
# lakshmi.sastry@rl.ac.uk

#                         and

# Venkat VSS Sastry
# Department of Applied Mathematics and Operational Research
# Cranfield University, RMCS Shrivenham, Swindon, SN6 8LA
# sastry@rmcs.cran.ac.uk

# 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 authors, RAL, RMCS Shrivenham, Cranfield University and AGOCG
# make no representations about the suitability of this
# software for any purpose.  It is provided "as is" without
# express or implied warranty. Likewise they accept no responsibility
# whatsoever for any public domain software modules used (which are
# hereby acknowledged) in this software 


# names starting with "fileselect" are reserved by this module
# no other names used.

# use the "option" command for further configuration

option add *Listbox*font \
    "-*-helvetica-medium-r-normal-*-12-*-*-*-p-*-iso8859-1" startupFile
option add *Entry*font \
    "-*-helvetica-medium-r-normal-*-12-*-*-*-p-*-iso8859-1" startupFile
option add *Label*font \
    "-*-helvetica-medium-r-normal-*-12-*-*-*-p-*-iso8859-1" startupFile


# Interface routine for btg
#
proc BtgGetFile { { fname "" } } {
    global fileselect
    set oldcursor [. cget -cursor]
    . config -cursor watch
    set pwd_saved [pwd]
    set fileselect(selectedfile) $fname
    fileselect
    tkwait variable fileselect(selectedfile)
    if {[string compare $fileselect(selectedfile) ""] != 0} {
	set pwd_now [pwd]
	set fileselect(selectedfile) "$pwd_now/$fileselect(selectedfile)"
    }
    cd $pwd_saved
    . config -cursor $oldcursor
    return $fileselect(selectedfile)
}

# this is the default proc  called when "OK" is pressed
# to indicate yours, give it as the first arg to "fileselect"

proc fileselect.default.cmd {f} {
    global fileselect
    set fileselect(selectedfile) $f
}


# this is the default proc called when error is detected
# indicate your own pro as an argument to fileselect

proc fileselect.default.errorHandler {errorMessage} {
    global fileselect
    LogAdd $errorMessage
    LogAdd ""
    set fileselect(selectedfile) ""
}

# this is the proc that creates the file selector box

proc fileselect {
    {cmd fileselect.default.cmd} 
    {purpose "File:"} 
    {w .fileSelectWindow} 
    {errorHandler fileselect.default.errorHandler}} {

    catch {destroy $w}

    toplevel $w
    grab $w
    wm title $w "Select File"


    # path independent names for the widgets
    global fileselect
    global selected
    set fileselect(entry) $w.file.eframe.entry
    set fileselect(list) $w.file.sframe.list 
    set fileselect(scroll) $w.file.sframe.scroll
    set fileselect(ok) $w.bframe.okframe.ok
    set fileselect(cancel) $w.bframe.cancel
    set fileselect(dirlabel) $w.file.dirlabel

    # widgets
    frame $w.file -bd 10 
    frame $w.bframe -bd 10
    pack append $w \
        $w.file {left filly} \
        $w.bframe {left expand frame n}

    frame $w.file.eframe
    frame $w.file.sframe
    label $w.file.dirlabel -anchor e -width 24 -text [pwd] 

    pack append $w.file \
        $w.file.eframe {top frame w} \
	$w.file.sframe {top fillx} \
	$w.file.dirlabel {top frame w}


    label $w.file.eframe.label -anchor w -width 24 -text $purpose
    entry $w.file.eframe.entry -relief sunken 
    $fileselect(entry) delete 0 end
    $fileselect(entry) insert 0 $fileselect(selectedfile)

    pack append $w.file.eframe \
		$w.file.eframe.label {top expand frame w} \
                $w.file.eframe.entry {top fillx frame w} 


    scrollbar $w.file.sframe.yscroll -relief sunken \
	 -command "$w.file.sframe.list yview"
    listbox $w.file.sframe.list -relief sunken -selectmode single \
	-yscroll "$w.file.sframe.yscroll set" 
    #$fileselect(list) configure -selectmode single
    pack append $w.file.sframe \
        $w.file.sframe.yscroll {right filly} \
 	$w.file.sframe.list {left expand fill} 

    # buttons
    frame $w.bframe.okframe -borderwidth 2 -relief sunken
 
    button $w.bframe.okframe.ok -text OK -relief raised -padx 10 \
        -command "fileselect.ok.cmd $w $cmd $errorHandler"

    button $w.bframe.cancel -text cancel -relief raised -padx 10 \
        -command "fileselect.cancel.cmd $w"
    pack append $w.bframe.okframe $w.bframe.okframe.ok {padx 10 pady 10}

    pack append $w.bframe $w.bframe.okframe {expand padx 20 pady 20}\
                          $w.bframe.cancel {top}

    # Fill the listbox with a list of the files in the directory (run
    # the "/bin/ls" command to get that information).
    # to not display the "." files, remove the -a option and fileselect
    # will still work
 
    $fileselect(list) insert end ".."
    foreach i [exec /bin/ls -a [pwd]] {
        if {[string compare $i "."] != 0 && \
	    [string compare $i ".."] != 0 } {
            $fileselect(list) insert end $i
        }
    }

   # Set up bindings for the browser.
    bind $fileselect(entry) <Return> {eval $fileselect(ok) invoke} 
    bind $fileselect(entry) <Control-c> {eval $fileselect(cancel) invoke}

    bind $fileselect(list) <Button-1> {
        # puts stderr "button 1 release"
	set x [$fileselect(list) curselection]
	$fileselect(entry) delete 0 end
	$fileselect(entry) insert 0 [%W get [%W nearest %y]]
    }

    bind $fileselect(list) <Key> {
	set x [$fileselect(list) curselection]
        $fileselect(entry) delete 0 end
	$fileselect(entry) insert 0 [%W get [%W nearest %y]]
    }

    bind $fileselect(list) <Double-ButtonPress-1> {
        # puts stderr "double button 1"
       	set x [$fileselect(list) curselection]
	$fileselect(entry) delete 0 end
	$fileselect(entry) insert 0 [%W get [%W nearest %y]]
	$fileselect(ok) invoke
    }

    bind $fileselect(list) <Return> {
	set x [$fileselect(list) curselection]
	$fileselect(entry) delete 0 end
	$fileselect(entry) insert 0 [%W get [%W nearest %y]]
	$fileselect(ok) invoke
    }

    # set kbd focus to entry widget

    focus $fileselect(entry)

}


# auxiliary button procedures

proc fileselect.cancel.cmd {w} {
    global fileselect
    set fileselect(selectedfile) ""
    destroy $w
}

proc fileselect.ok.cmd {w cmd errorHandler} {
    global fileselect
    global selected
    set selected [$fileselect(entry) get]

    # some nasty file names may cause "file isdirectory" to return an error
    set sts [catch { 
	file isdirectory $selected
    }  errorMessage ]
    
    if { $sts != 0 } then {
	$errorHandler $errorMessage
	destroy $w
	return
    }

    # clean the text entry and prepare the list
    $fileselect(entry) delete 0 end
    $fileselect(list) delete 0 end
    $fileselect(list) insert end ".."

    # perform globbing on the selection. 
    # If globing returns an error (no match) check if a non-null name is
    # entered. If name string is non-empty return it as a new file name
    # else give an error message.
    # If resulting list length > 1, put the list on the file listbox and return
    # If globing expands to a list of filenames in multiple directories,
    # the indicated regexp is invalid and the error handler is called instead.
    set globlist 0

    set sts [catch {
	set globlist [glob [list $selected]]
    } errorMessage ]

    if { $sts != 0 } then {
	if { [llength $globlist] == 1 } {
	    destroy $w
	    $cmd $selected
	    return 
	} else {
	    $errorHandler $errorMessage
	    destroy $w
	    return
	}	
    } 

    if {[llength $globlist] > 1} {
	if {[regexp "/" $globlist] != 0} {
	    $errorHandler [list "Invalid regular expression, " $selected, "."]
	    destroy $w
	    return
	}
	foreach i $globlist {
	    if {[string compare $i "."] != 0 && \
		[string compare $i ".."] != 0} {
		$fileselect(list) insert end $i
	    }
	}
	return
    }

    # selection may be a directory. Expand it.

    if {[file isdirectory $selected] != 0} {
	cd $selected
	set dir [pwd]
	$fileselect(dirlabel) configure -text $dir

	foreach i [exec /bin/ls -a $dir] {
	    if {[string compare $i "."] != 0 && \
		[string compare $i ".."] != 0} {
		$fileselect(list) insert end $i
	    }
	}
	return
    }

    destroy $w
    $cmd $selected

}

##############################################################
# Auxiliary routines for the btg program
##############################################################

# Scrolled text box
#
proc ScrolledText { f args } {
    frame $f
    eval {text $f.text \
	      -yscrollcommand [list $f.scroll set]} $args
    scrollbar $f.scroll -orient vertical \
	-command [list $f.text yview]
    pack $f.scroll -side right -fill y
    pack $f.text -side left -fill both -expand true
    pack $f -side top -fill both -expand true
    return $f.text
}

# Browse a file
#
proc Browse { fname {tname .browser} {s "Browser"} } {
    catch {destroy $tname}
    toplevel $tname
    wm title $tname $s
    set t [ScrolledText $tname.win]
    $t config -state normal
    if [catch {open $fname} in] {
	$t insert end $in
    } else {
	$t insert end [read $in]
	close $in
    }
    $t config -state disabled
}

# Add "OK" and "Cancel" buttons to the bottom of a dialog
#
proc AddOKCancel { w flag } {
    set f [frame $w.buttons]
    button $f.ok -text OK -command "set $flag 1"
    button $f.cancel -text Cancel -command "set $flag 0"
    pack $f -side bottom
    pack $f.ok -side left
    pack $f.cancel -side right
}


# Add a frame for entering some range data
#
proc AddRangeFrame { frame_name prompt_text minfld maxfld } {
    global $minfld $maxfld
    set f [frame $frame_name]
    label $f.l1 -text $prompt_text
    label $f.l2 -text " to "
    entry $f.min -width 8 -textvariable $minfld
    entry $f.max -width 8 -textvariable $maxfld
    pack $f -side top -fill x
    pack $f.l1 $f.min $f.l2 $f.max -side left
}


# Add a frame for displaying range data
#
proc AddRangeDisplayFrame { frame_name prompt_text minfld maxfld } {
    global $minfld $maxfld
    set f [frame $frame_name]
    label $f.l1 -text $prompt_text
    label $f.l2 -text " to "
    entry $f.min -state disabled -width 8 -relief flat -textvariable $minfld
    entry $f.max -state disabled -width 8 -relief flat -textvariable $maxfld
    pack $f -side top -fill x
    pack $f.l1 $f.min $f.l2 $f.max -side left
}


# Add a frame for entering some single value
#
proc AddEntryFrame { frame_name prompt_text entryfld { wid 8 } } {
    global $entryfld
    set f [frame $frame_name]
    label $f.l -text $prompt_text
    entry $f.e -width $wid -textvariable $entryfld
    pack $f -side top -fill x
    pack $f.l $f.e -side left
}


# Give focus/control to a dialog box until flag changes
#
proc StartDlg { w field flag } {
    global $flag
    set oldcursor [. cget -cursor]
    . config -cursor watch
    focus $field
    grab $w
    tkwait variable $flag
    grab release $w
    . config -cursor $oldcursor
}


# Get a point location
#
proc GetPoint { } {
    global btgpt

    catch {destroy .pointdlg}
    toplevel .pointdlg
    wm title .pointdlg "Point"

    set f [frame .pointdlg.coord]
    label $f.l1 -text "Point: "
    label $f.l2 -text ","
    entry $f.x -width 8 -textvariable btgpt(x)
    entry $f.y -width 8 -textvariable btgpt(y)
    pack $f -side top -fill x
    pack $f.l1 $f.x $f.l2 $f.y -side left

    AddOKCancel .pointdlg btgpt(ok)

    StartDlg .pointdlg .pointdlg.coord.x btgpt(ok)
    destroy .pointdlg

    return $btgpt(ok)
}

# Get the information needed to draw a map
#
proc GetMap { } {
    global btgmap

    catch {destroy .mapdlg}
    toplevel .mapdlg
    wm title .mapdlg "Map"

    AddRangeFrame .mapdlg.xrange "x range: " btgmap(xmin) btgmap(xmax)
    AddRangeFrame .mapdlg.yrange "y range: " btgmap(ymin) btgmap(ymax)
    AddEntryFrame .mapdlg.step "Grid box step size: " btgmap(step)
    AddEntryFrame .mapdlg.medfname "Prediction output: " btgmap(medfname) 30
    AddEntryFrame .mapdlg.errfname "Uncertainty output: " btgmap(errfname) 30
    AddOKCancel .mapdlg btgmap(ok)

    StartDlg .mapdlg .mapdlg.xrange.min btgmap(ok)
    destroy .mapdlg

    return $btgmap(ok)
}


# Add a line to the log window
#
proc LogAdd { line } {
    .log.text insert end $line\n
    .log.text see end
}


# Run a btg command
#
proc Btg { args } {
    global btg_fid btg_return_value btg_ready
    set oldcursor [. cget -cursor]
    . config -cursor watch
    update idletasks
    puts $btg_fid $args
    flush $btg_fid
    set btg_ready 0
    tkwait variable btg_ready
    gets $btg_fid btg_return_status
    gets $btg_fid btg_return_value
    if { ! $btg_return_status } {
	LogAdd $btg_return_value
	LogAdd ""
    }
    . config -cursor $oldcursor
    return $btg_return_status
}

# Load a data file
#
proc LoadData { filename } {
    global btg_return_value
    global btg_x_min btg_x_max btg_y_min btg_y_max btg_z_min btg_z_max btg_data
    if [Btg load $filename] {
	set btg_x_min [lindex $btg_return_value 0]
	set btg_x_max [lindex $btg_return_value 1]
	set btg_y_min [lindex $btg_return_value 2]
	set btg_y_max [lindex $btg_return_value 3]
	set btg_z_min [lindex $btg_return_value 4]
	set btg_z_max [lindex $btg_return_value 5]
	set btg_data [lindex $btg_return_value 6]
	LogAdd "Loaded $filename"
	LogAdd ""
    }
}


# Load a script file
#
proc LoadScript { filename } {
    global btg_trend_order btg_correlation
    global btg_lambda_min btg_lambda_max
    global btg_range_min btg_range_max
    global btg_mesh_size
    global btg_sample_size
    global btg_path
    if [catch {source $filename} err] {
        LogAdd $err
        LogAdd ""
    }
}


# Save a script file
#
proc SaveScript { fname } {
    global btg_trend_order btg_correlation
    global btg_lambda_min btg_lambda_max
    global btg_range_min btg_range_max
    global btg_mesh_size
    global btg_sample_size
    global btg_data
    if [catch {set fid [open $fname "w"]} err] {
        LogAdd $err
        LogAdd ""
    }
    puts $fid "set btg_trend_order $btg_trend_order"
    puts $fid "set btg_correlation $btg_correlation"
    puts $fid "set btg_lambda_min $btg_lambda_min"
    puts $fid "set btg_lambda_max $btg_lambda_max"
    puts $fid "set btg_range_min $btg_range_min"
    puts $fid "set btg_range_max $btg_range_max"
    puts $fid "set btg_mesh_size $btg_mesh_size"
    puts $fid "set btg_sample_size $btg_sample_size"
    puts $fid "LoadData $btg_data"
    puts $fid "Update"
    close $fid
}


# Refresh settings variables
#
proc Refresh { } {
    global btg_ready
    if {!$btg_ready} {
	return
    }
    global btg_return_value
    global btg_range_min btg_range_max
    global btg_mesh_size btg_sample_size btg_trend_order
    global btg_lambda_min btg_lambda_max
    global btg_correlation btg_data btg_path
    if [ Btg refresh ] {
	set btg_range_min [lindex $btg_return_value 0]
	set btg_range_max [lindex $btg_return_value 1]
	set btg_mesh_size [lindex $btg_return_value 2]
	set btg_sample_size [lindex $btg_return_value 3]
	set btg_trend_order [lindex $btg_return_value 4]
	set btg_lambda_min [lindex $btg_return_value 5]
	set btg_lambda_max [lindex $btg_return_value 6]
	set btg_correlation [lindex $btg_return_value 7]
    }
}


# Update settings variables
#
proc Update { } {
    global btg_ready
    if {!$btg_ready} {
	return
    }
    global btg_return_value btg_return_status
    global btg_range_min btg_range_max
    global btg_mesh_size btg_sample_size btg_trend_order
    global btg_lambda_min btg_lambda_max
    global btg_correlation btg_data btg_path
    Btg update $btg_range_min $btg_range_max \
	$btg_mesh_size $btg_sample_size $btg_trend_order \
	$btg_lambda_min $btg_lambda_max \
	$btg_correlation
}


# Set the data file
#
proc Data { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btg_return_value
    global btg_x_min btg_x_max btg_y_min btg_y_max btg_z_min btg_z_max btg_data
    set fname [BtgGetFile]
    if {[string compare $fname ""] != 0} {
	LoadData $fname
    }
}


# Load/execute a script (normally used to load settings)
#
proc Load { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    set fname [BtgGetFile]
    if {[string compare fname ""] != 0} {
	LogAdd "Loading script..."
	LoadScript $fname
	LogAdd ""
    }
}


# Save a settings script
#
proc Save { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    set fname [BtgGetFile]
    if {[string compare fname ""] != 0} {
	LogAdd "Saving script..."
	SaveScript $fname
	LogAdd ""
    }
}


# Quit the program
#
proc Quit { } {
    global btg_fid gnuplot_fid
    catch {close $btg_fid}
    catch {close $gnuplot_fid}
    exit
}


# Initialize the prediction engine
#
proc Init { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btg_return_value
    if [Btg initialize] {
	LogAdd "Initialized prediction engine"
	LogAdd ""
    }
}


# Plot predictive density
#
proc Plot { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btgpt
    global gnuplot_fid
    if [ GetPoint ] {
	set fname [BtgGetFile "plot.out"]
	if {[string compare $fname ""] != 0} {
	    LogAdd "Writing out plot at ($btgpt(x), $btgpt(y)) to $fname"
	    Btg plot $btgpt(x) $btgpt(y) $fname 1
	    LogAdd ""
	    catch {close $gnuplot_fid}
	    catch {
		set gnuplot_fid [open "| gnuplot" "w"]
		puts $gnuplot_fid "plot \"$fname\""
		flush $gnuplot_fid
	    }
	}
    }
}


# Point prediction
#
proc Pred { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btgpt btg_return_value
    if [ GetPoint ] {
	LogAdd "Predicting at ($btgpt(x), $btgpt(y)) ..."
	if [Btg predict $btgpt(x) $btgpt(y)] {
	    set med [lindex $btg_return_value 0]
	    set lb [lindex $btg_return_value 1]
	    set rb [lindex $btg_return_value 2]
	    LogAdd "Median:  $med"
	    LogAdd "95 \% PI: ($lb, $rb)"
	    LogAdd ""
	}
    }
}


# Estimate standard Monte Carlo error
#
proc Phi { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btgpt btg_return_value
    if [ GetPoint ] {
	LogAdd "Estimating Monte Carlo error at ($btgpt(x), $btgpt(y)) ..."
	if [ Btg phi $btgpt(x) $btgpt(y) ] {
	    LogAdd "Phi: $btg_return_value"
	}
	LogAdd ""
    }
}


# Estimate model parameters
#
proc Model { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btg_return_value
    LogAdd "Computing a posteriori parameter estimates"
    if [ Btg model ] {
	set lambda [lindex $btg_return_value 0]
	set theta [lrange $btg_return_value 1 end]
	LogAdd "Lambda: $lambda"
	LogAdd "Theta: $theta"
    }
    LogAdd ""
}


# Cross-validate
#
proc Validate { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    set fname [BtgGetFile validate.out]
    if {[string compare $fname ""] != 0} {
	LogAdd "Writing cross-validation information to $fname"
	if [ Btg validate $fname ] {
	    LogAdd "Validation complete"
	    LogAdd ""
	    Browse $fname
	}
    }
}


# Map a region
#
proc Map { } {
    global btg_ready
    if {!$btg_ready} {
        return
    }
    global btgmap gnuplot_fid
    if [ GetMap ] {
	LogAdd "Mapping..."
	set pwd [pwd]
	if [ Btg map $btgmap(xmin) $btgmap(xmax) \
		 $btgmap(ymin) $btgmap(ymax) \
		 $btgmap(step) "$pwd/$btgmap(medfname)" "$pwd/$btgmap(errfname)" 0 ] {
	    LogAdd "Done mapping."
	    LogAdd ""
	}
    }
}


# Get help
#
proc Help { } {
    global btg_help
    Browse $btg_help .help "Help browser"
}


##############################################################
# btg interface setup module
##############################################################

wm title . "TkBTG"

frame .menu
pack .menu -side top -fill x

menubutton .menu.file -text File -menu .menu.file.m
set m [menu .menu.file.m]
$m add command -label "Load script" -command Load
$m add command -label "Save script" -command Save
$m add command -label "Quit" -command Quit
pack .menu.file -side left

menubutton .menu.compute -text Compute -menu .menu.compute.m
set m [menu .menu.compute.m]
$m add command -label "Plot density" -command Plot
$m add command -label "Predict" -command Pred
$m add command -label "Phi" -command Phi
$m add separator
$m add command -label "Estimate parameters" -command Model
$m add command -label "Cross-validate" -command Validate
$m add command -label "Map" -command Map
$m add separator
$m add command -label "Initialize engine" -command Init
pack .menu.compute -side left

menubutton .menu.help -text Help -menu .menu.help.m
set m [menu .menu.help.m]
$m add command -label "View help file" -command Help
pack .menu.help -side right

set f [frame .log]
text $f.text -width 80 -height 20 \
    -borderwidth 2 -relief sunken -setgrid true \
    -yscrollcommand "$f.scroll set"
scrollbar $f.scroll -command "$f.text yview"
pack $f -side top -fill both -expand true
pack $f.scroll -side right -fill y
pack $f.text -side left -fill both -expand true

frame .settings
pack .settings -side bottom

set f [frame .settings.load]
label $f.l -text "Current data file: "
entry $f.e -width 40 -state disabled -relief flat -textvariable btg_data
pack $f -side top -fill x
pack $f.l -side left
pack $f.e -side left -fill x -expand 1

AddRangeDisplayFrame .settings.rangex "x range: " btg_x_min btg_x_max
AddRangeDisplayFrame .settings.rangey "y range: " btg_y_min btg_y_max
AddRangeDisplayFrame .settings.rangez "z range: " btg_z_min btg_z_max

AddRangeFrame .settings.distrib "Range of z0: " btg_range_min btg_range_max
set f [frame .settings.mesh]
label .settings.distrib.lmesh -text "; mesh size of "
entry .settings.distrib.emesh -width 8 -textvariable btg_mesh_size
pack .settings.distrib.lmesh .settings.distrib.emesh -side left

AddEntryFrame .settings.sample "Sample size: " btg_sample_size
AddRangeFrame .settings.lambda "Lambda range: " btg_lambda_min btg_lambda_max

set f [frame .settings.correlation]
label $f.l -text "Correlation"
radiobutton $f.exp -text "Exponential" \
    -variable btg_correlation -value "exponential"
radiobutton $f.matern -text "Matern" \
    -variable btg_correlation -value "matern"
radiobutton $f.rational -text "Rational quadratic" \
    -variable btg_correlation -value "rational"
radiobutton $f.spherical -text "Spherical" \
    -variable btg_correlation -value "spherical"
pack $f -side top -fill x
pack $f.l $f.exp $f.matern $f.rational $f.spherical -side left

set f [frame .settings.covariate]
label $f.l -text "Trend order"
radiobutton $f.o0 -text "0" \
    -variable btg_trend_order -value 0
radiobutton $f.o1 -text "1" \
    -variable btg_trend_order -value 1
radiobutton $f.o2 -text "2" \
    -variable btg_trend_order -value 2
pack $f -side top -fill x
pack $f.l $f.o0 $f.o1 $f.o2 -side left

set f [frame .settings.buttons]
button $f.data -text "Open data" -command Data
button $f.refresh -text "Update settings" -command Update
pack $f -side top
pack $f.data $f.refresh -side left

##############################################################
# Main program code
##############################################################

if [catch {
	set btg_fid [open "| $btg_program" "r+"]
	fileevent $btg_fid readable {set btg_ready 1}
	set btg_ready 1
    }] {
    puts "Error: could not open btg program"
    exit
}
set btg_range_min 0
set btg_range_max 0
set btg_mesh_size 1000
set btg_sample_size 500
set btg_trend_order 0
set btg_lambda_min -3
set btg_lambda_max 3
set btg_correlation "exponential"
set btg_data ""
set btg_path "~/btg_data"
catch {source ~/.btgrc}
catch {cd $btg_path}
Update
