
# This code creates the user interface for tetra.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com

proc mesher_select {} {
    global config_dir tetin_file has_tetin
    
    set files ""
    foreach f [lsort [glob -nocomplain $config_dir(mesh)/tetin*]] {
	set t [file tail $f]
	if {$t != "tetin_pad"} { lappend files $t }
    }
    foreach f [lsort [glob -nocomplain $config_dir(mesh)/*.tin]] {
	set t [file tail $f]
	lappend files $t
    }
    if {$files == ""} {
	mess "Error: no tetin files available\n" red
	return 0
    }
    if [info exists tetin_file] {
	set def $tetin_file
    } else {
	set def tetin1
    }
    if ![file exists $config_dir(mesh)/$def] { set def "" }
    set mess "Please select a tetin file.  You can delete\
	    tetin files using the \"Delete\" button once you have\
	    selected them."
    set tf [choose_one $mess $files $def +300+300 mesher_delete_tetin]
    if {$tf == ""} {
	set has_tetin 0
	return 0
    } else {
	set tetin_file $tf
	set has_tetin 1
	return 1
    }
}

proc mesher_delete_tetin {name} {
    global config_dir
    
    set path $config_dir(mesh)/$name
    
    set mess "Delete tetin file \"$path\"?"
    if ![tk_dialog .delfile "Delete file" $mess "" -1 "Yes" "No"] {
	cmd_rm -f $path
	return 1
    }
    return 0
}

proc mesher_tetra {} {
    global config_dir tetin_file cut_domain uncut_domain tetra_log topform_geo
    global remote_host low_priority tetra_bin form_done_flag tetra_finished
    global after_run_cutter after_cutter_which
    global after_smoother_iters after_smoother_aspect spt_tradeoff
    global cutter_bw_flag is_win remote_acn cutter_fix_spikes
    global tetra_params_window_name cutter_close_gaps cutter_auto_orphan
    global n_processors
    
    if ![info exists cutter_auto_orphan] { set cutter_auto_orphan orphan }
    set cutter_fix_spikes 1
    if { [ file exists $config_dir(mesh)/$tetin_file ] == 0 } {
	set tetin_file ""
    }
    if { $tetin_file == "" } {
    	if ![mesher_select] return
    }
    
    set uncut_domain uncut_domain
    set cut_domain cut_domain
    set tetra_log tetra_log
    if {[scan $tetin_file "tetin%d" number] == 1} {
	set uncut_domain uncut_domain.$number
	set cut_domain cut_domain.$number
	set tetra_log tetra_log.$number
    }
    
    set d [form_init .tetra_params "Tetra parameters" mesher]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	
	set ln 4
	form_label $d.tetinl "Tetin file" "$ln 0"
	form_entry $d.tetin tetin_file string "$ln 1"

	incr ln
	form_label $d.uncutl "Uncut domain" "$ln 0" \
				{ { after_run_cutter 0 } }
	form_entry $d.uncut uncut_domain string "$ln 1" \
				{ { after_run_cutter 0 } }

	incr ln
	form_label $d.cutl "Cut domain" "$ln 0" \
				{ { after_run_cutter 1 } }
	form_entry $d.cut cut_domain string "$ln 1" \
				{ { after_run_cutter 1 } }

	incr ln
	form_label $d.logl "Log file" "$ln 0"
	form_entry $d.log tetra_log string "$ln 1"

	incr ln
	form_label $d.remotel "Remote machine" "$ln 0"
	form_entry $d.remote remote_host string "$ln 1"

	incr ln
	form_label $d.nprocl "Number of processors" "$ln 0"
	form_entry $d.nproc n_processors string "$ln 1"

	incr ln
	form_label $d.remacnl "Remote ICEM_ACN" "$ln 0"
	form_entry $d.remacn remote_acn string "$ln 1"

if !$is_win {
	incr ln
	form_checkbutton $d.lowpri "Low priority" low_priority "$ln 0"
}

	incr ln
	form_label $d.sptl "Space / time tradeoff:" "$ln 0"
	form_radiobutton $d.sp "Less memory" spt_tradeoff space "$ln 1"

	incr ln
	form_radiobutton $d.tt "Faster execution" spt_tradeoff time "$ln 1"
	
	$d.uncut configure -width 16
	$d.cut configure -width 16
	
	incr ln
	form_checkbutton $d.aftersc "Run cutter" after_run_cutter "$ln 0"

	incr ln
	form_label $d.afterl "   Action:" "$ln 0" after_run_cutter
	form_radiobutton $d.afteri "Interactive" after_cutter_which inter \
		"$ln 1" after_run_cutter

	incr ln
	form_radiobutton $d.afterv "Write volume" after_cutter_which volume \
		"$ln 1" after_run_cutter
	incr ln
	form_radiobutton $d.afters "Write surface" after_cutter_which surface \
		"$ln 1" after_run_cutter

	set ln [ create_cutter_buttons $d $ln ]

	set smm {
	    after_run_cutter
	    {after_cutter_which volume surface}
	}
if { 0 }  {
	incr ln
	form_checkbutton $d.sm "Run smoother" after_run_smoother "$ln 0"

	incr ln
	form_label $d.smil "  Iterations" "$ln 0" after_run_smoother
	form_entry $d.smi after_smoother_iters int "$ln 1" after_run_smoother

	incr ln
	form_label $d.smal "  Aspect ratio" "$ln 0" after_run_smoother
	form_entry $d.sma after_smoother_aspect float "$ln 1" after_run_smoother
}
	set tetra_params_window_name $d
	
	form_finish $topform_geo
    }

    bindtofiles $tetra_params_window_name.tetin $config_dir(mesh)
    bindtofiles $tetra_params_window_name.uncut $config_dir(domains)
    bindtofiles $tetra_params_window_name.cut $config_dir(domains)
    bindtofiles $tetra_params_window_name.log $config_dir(mesh)
    
    tkwait variable form_done_flag(.tetra_params)
    if !$form_done_flag(.tetra_params) return
    
    set tf $config_dir(mesh)/$tetin_file
    if { $uncut_domain == "" } {
	tk_dialog .err "Error" "no uncut domain selected" "" 0 Ok
	return
    }
    if { ! [ file exists $config_dir(domains) ] } {
	mess "directory $config_dir(domains) does not exist, I am creating it\n"
	file mkdir $config_dir(domains)
    }
    set uf $config_dir(domains)/$uncut_domain
    if {[file exists $tf] && [file exists $uf] && \
	    ([file mtime $uf] > [file mtime $tf])} {
	if [tk_dialog .newer "Newer" \
		" The uncut domain is more recent than the tetin file.\n\
		Do you really want to run the tetra mesher again?" \
		"" -1 Yes No] return
    }
    set logfile $config_dir(mesh)/$tetra_log
    set cmdfile $config_dir(mesh)/tetra_cmd
    
    build_tetra_param_file $config_dir(mesh)/tetra_params \
	$config_dir(mesh)/$tetin_file $config_dir(domains)/$uncut_domain
    
    set command ""
    if { [ info exists low_priority ] && $low_priority } {
	lappend command nice +4
    }

    lappend command $tetra_bin $config_dir(mesh)/tetra_params

    if { [ info exists n_processors ] && $n_processors != "" } {
	append command " -nproc $n_processors"
    }
    
    if {$remote_host != ""} {
	# This is kind of tricky.
	set cur [pwd]; cd; set home [pwd]; cd $cur
	if {![regexp "$home/(.*)" $cur dummy place]} { set place $cur }
	set command "[get_path rsh 1] $remote_host \"cd $place; setenv ICEM_ACN $remote_acn; $command\""
	mess "Command: $command\n"
    }
    
    cmd_rm -f $logfile
    if $is_win {
	eval exec $command >& $logfile &
    } else {
	set fp [open $cmdfile w]
	puts $fp "\#!/bin/csh -f"
	puts $fp $command
	close $fp
	exec chmod 0755 $cmdfile
	exec $cmdfile >& $logfile &
    }
    
    # Now wait for the log file.
    for {set i 0} {$i < 60} {incr i} {
	if [file exists $logfile] break
	after 1000
    }
    if {$i == 60} {
	mess "Error: tetra didn't start -- can't find log file\n" red
	return
    }
    mess "Tetra is running: logfile = [file tail $logfile].\n"
    
    if [file exists $logfile] {
	if ![show_logfile $logfile .tetra_monitor Tetra ] return
    }
    if $after_run_cutter {
	mess "Automatically starting cutter ...\n"
	mesher_cutter 0
	
	if {$after_cutter_which != "inter"} {
	    mess "Automatically saving $after_cutter_which mesh ...\n"
	    mesher_save $after_cutter_which 0
	    
	}
    }
}
proc bindtofiles { label_name directory } {
	set tetin_files [glob -nocomplain $directory/*]
	set ends ""
	foreach i $tetin_files {
		lappend ends [ file tail $i]
	}
	pathentry on $label_name $ends
}
proc create_cutter_buttons { d ln } {
	incr ln
	form_checkbutton $d.rep \
		"Automatically repair holes between material points" \
		cutter_repair "$ln 0 -cols 2"

	incr ln
	form_checkbutton $d.bw "Use black and white" \
		cutter_bw_flag "$ln 0 -cols 2"

	incr ln
	form_checkbutton $d.fnm "Fix spikes" \
		cutter_fix_spikes " $ln 0 -cols 2"

	incr ln
	form_radiobutton $d.an "Use existing material points" \
		cutter_auto_orphan existing "$ln 0 -cols 2"

	incr ln
	form_radiobutton $d.ao "Automatically add orphan points" \
		cutter_auto_orphan orphan "$ln 0 -cols 2"
	incr ln
	form_radiobutton $d.am "Automatically add material points" \
		cutter_auto_orphan auto_mat "$ln 0 -cols 2"

	return $ln
}

proc mesher_cutter {ask} {
    global n_processors max_binary
    global config_dir tetin_file cut_domain uncut_domain topform_geo
    global remote_host low_priority tetra_bin form_done_flag tetra_finished
    global cutter_bin display_flag cutter_repair has_tetin cutter_bw_flag
    global cutter_fix_spikes cutter_params_window_name
    global cutter_closegaps cutter_auto_orphan
    
    if ![info exists cutter_repair] { set cutter_repair 1 }
    if ![info exists cutter_closegaps] { set cutter_closegaps 0 }
    if ![info exists cutter_auto_orphan] { 
		set cutter_auto_orphan auto_mat 
    }
    
    if $ask {
	if { $tetin_file == "" } {
		if ![mesher_select] return
	}
	
	set uncut_domain uncut_domain.1
	set cut_domain cut_domain.1
	if {[scan $tetin_file "tetin%d" number] == 1} {
	    set uncut_domain uncut_domain.$number
	    set cut_domain cut_domain.$number
	}
	if { ![file exists $config_dir(domains)/$uncut_domain] } {
		set files [ glob -nocomplain $config_dir(domains)/*]
		set uncut_domain ""
		foreach f $files {
			set t [ file tail $f ]
			if { [ string match "*uncut*" $t ] } {
				set uncut_domain $t
				break
			}
		}
	}
	set cutter_bw_flag 0
	set cutter_fix_spikes 1
	
	set d [form_init .cutter_params "Cutter parameters" mesher]
	if {$d != ""} {
	    form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	    
	    set ln 4
	    form_label $d.tetinl "Tetin file" "$ln 0"
	    form_entry $d.tetin tetin_file string "$ln 1"

	    incr ln
	    form_label $d.uncutl "Uncut domain" "$ln 0"
	    form_entry $d.uncut uncut_domain string "$ln 1"

	    incr ln
	    form_label $d.cutl "Cut domain" "$ln 0"
	    form_entry $d.cut cut_domain string "$ln 1"
	    $d.uncut configure -width 16
	    $d.cut configure -width 16

	    set ln [ create_cutter_buttons $d $ln ]

	    incr ln
            form_label $d.nprocl "Number of processors" "$ln 0"
            form_entry $d.nproc n_processors string "$ln 1"

	    form_finish $topform_geo
	    set cutter_params_window_name $d
	}

# set the file completion for tetin file
	bindtofiles $cutter_params_window_name.tetin $config_dir(mesh)
	bindtofiles $cutter_params_window_name.uncut $config_dir(domains)
	bindtofiles $cutter_params_window_name.cut $config_dir(domains)


	tkwait variable form_done_flag(.cutter_params)
	if !$form_done_flag(.cutter_params) return
    }
    
    # Now start the cutter as a subprocess.
    if { $uncut_domain == "" } {
	tk_dialog .err "Error" "no uncut domain selected" "" 0 Ok
	return
    }
    set cutter "$cutter_bin $config_dir(domains)/$uncut_domain \
	    $config_dir(mesh)/$tetin_file $config_dir(domains)/$cut_domain"
    if { [ info exists n_processors ] && $n_processors != "" } { 
		append cutter " -nproc $n_processors"
    }
    if { [ info exists max_binary ] && $max_binary > 0 } {
		append cutter " -max_binary $max_binary"
    }
    if !$cutter_repair { append cutter " no_repair" }
    if $cutter_closegaps { append cutter " closegaps" }
    if $cutter_bw_flag { append cutter " -bw" }
    set has_tetin 1
    start_process cutter .v.view $cutter cutter%
    add_families
    set_phase_mesher 1
    set cmd "flood_fill"
    if { $cutter_auto_orphan == "auto_mat" } {
	append cmd " autovol"
    }
    command $cmd
    if { $cutter_auto_orphan == "auto_mat" } {
# auto_mat might create new families
	add_families
    }
    if { $cutter_auto_orphan == "orphan" } {
	command "auto_orphan"
    }
    if { $cutter_fix_spikes } {
	command "fix_spikes"
    }
    mesher_save volume 0
    foreach i {face face_bound face_root edge_single edge_multiple} {
	set display_flag($i) 1
    }
    set display_flag(face_internal) 0
    update_display
    command "orient +z"
}


proc cutter_running {} {
    global process_ident
    return [expr {$process_ident == "cutter"}]
}

proc build_tetra_param_file {file input output} {
    global spt_tradeoff
    
    set fd [open $file w]
    
    puts $fd "SurfaceFile	       \"$input\""
    puts $fd "DomainOutputFile	  \"$output\""
    if {$spt_tradeoff == "time"} {
	puts $fd "CacheIntersections	1"
    } else {
	puts $fd "CacheIntersections	0"
    }
    puts $fd "run_cutter 0"
    puts $fd "run_smoother 0"
    
    close $fd
}

proc time_sort {f1 f2} { return [expr {[lindex $f2 0] - [lindex $f1 0]}] }

proc mesher_monitor {} {
    global config_dir
    
    set logfiles [glob -nocomplain $config_dir(mesh)/tetra_log.*]
    switch [llength $logfiles] {
	0 { error "No tetra log files found" }
	1 { set logfile $logfiles }
	default {
	    set lfs ""
	    foreach lf $logfiles {
		file stat $lf stat
		lappend lfs [list $stat(mtime) [file tail $lf]]
	    }
	    set files ""
	    foreach f [lsort -command time_sort $lfs] {
		lappend files [lindex $f 1]
	    }
	    
	    set mess "Please select a tetra log file.\n\
		    (Newest files are first.)"
	    set file [choose_one $mess $files "" +300+300]
	    if {$file == ""} return
	    set logfile $config_dir(mesh)/$file
	}
    }
    show_logfile $logfile
}

proc mesher_degenerate {} {
    global botform_geo form_done_flag degen_threshhold
    
    set buts {{Done {form_done .degen; set form_done_flag(.degen) 0}}}
    
    set d [form_init .degen "Degenerate boundary" mesher $buts]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	form_button $d.display Display degen_display {0 0}
	form_button $d.remove Remove degen_remove {1 0}
	form_label $d.threshl Threshhold {2 0}
	form_entry $d.thresh degen_threshhold float {2 1}
	form_finish $botform_geo
	
	set degen_threshhold 0.4
    }
    tkwait variable form_done_flag(.degen)
    command "display_degen_boundary erase"
}

proc degen_display {} {
    global degen_threshhold
    command "display_degen_boundary $degen_threshhold"
}

proc degen_remove {} {
    global degen_threshhold
    command "remove_degen_boundary $degen_threshhold"
}

proc mesher_close_holes {} {
    command "close_hole"
    update_display face
}

proc mesher_flood_fill {} {
    global cutter_fix_spikes
    command "flood_fill"
    if { $cutter_fix_spikes } {
	command "fix_spikes"
    }
    update_display face
}

proc mesher_auto_orphan {} {
	command "auto_orphan"
}
proc mesher_fix_spikes {} {
	command "fix_spikes"
}
proc mesher_save {what {ask 1}} {
    global process_ident families config_dir cut_domain cutter_saved_once
    global last_line
    
    if {![info exists process_ident] || ($process_ident != "cutter")} {
	return 0
    }
    
    set files ""
    foreach f [glob -nocomplain $config_dir(domains)/*] {
	lappend files [file tail $f]
    }
    set allf ""; 
    foreach f $families { 
	if { $f != "ORFN" && $f != 0 } { 
		lappend allf $f
	} 
    }
    if $ask {
	set mess "Select a domain to save the current mesh to, or enter a new\
		name below.  You can delete\
		domain files using the \"Delete\" button once you have\
		selected them."
	set ff [choose_one $mess $files $cut_domain +300+300 delete_cut_domain]
	if {$ff == ""} { return 0 }
	set cut_domain $ff
	
	set actf [mesh_family_string]
	if {$allf != $actf} {
	    set mess "Not all families are currently visible.  You can save\
		    only the visible families, or all of them."
	    switch [tk_dialog .someblanked "Blanked families" $mess "" -1 \
		    "Save some" "Save all" Cancel] {
		1 { set actf $allf }
		2 { return 0 }
	    }
	}
    } else {
	set actf $allf
    }
    
    if {$what == "surface"} {
	command "save filename $cut_domain only_surface $actf"
    } else {
	command "save filename $cut_domain $actf"
    }
    set cutter_saved_once 1
    command "model_modified"
    if { $last_line } {
	set mess "The tetin file has been modified. \
		Orphan material points have been created. \
		Should the tetin file be saved ?"
        switch [tk_dialog .write_tetin "Write tetin fine" $mess "" -1 \
                    "Yes" "No" ] {
                0 { 
			command "write_tetin_file"
		}
        }
    }
    return 1
}

proc set_phase_mesher {in} {
    global cutter_saved_once
    
    if !$in {
	if ![info exists cutter_saved_once] {
	    mesher_save volume
	}
	finish_process
    }
}

# Generic stuff ----------------------------------------------

proc file_quit {} {
    if [tk_dialog .quit "Quit" "Really quit?" "" -1 "Yes" "No"] return
    command quit
    exit 0
}

proc file_hardcopy_print_special {} {
    global hardcopy process_ident
    
    if {$process_ident != "leo"} { return 0 }
    
    set file $hardcopy(file)
    
    if !$hardcopy(colorps) {
	mess "Saving color postscript image to file \"$file\" ...\n"
	command "write_postscript $file 1"
    } else {
	mess "Saving monochrome postscript image to file \"$file\" ...\n"
	command "write_postscript $file 0"
    }
    return 1
}

proc old__file_hardcopy {} {
    global form_done_flag hardcopy_file hardcopy_type hardcopy_print
    global hardcopy_printer hardcopy_colorps
    global botform_geo process_ident
    
    if ![file_hardcopy_form screen $botform_geo] return
    
    if 0 {
	set label "Job \"$job_name\", written by\
		[exec [get_path whoami]]@[exec [get_path hostname]] on\
		[exec [get_path date]], by $whoami"
    }
    
    case $hardcopy_type in {
	ps {
	    switch $process_ident {
		cutter {
		    if $hardcopy_colorps {
			mess "Saving color postscript image to file\
			    \"$hardcopy_file\" ...\n"
			command "plot $hardcopy_file color"
		    } else {
			mess "Saving monochrome postscript image to file\
			    \"$hardcopy_file\" ...\n"
			command "plot $hardcopy_file"
		    }
		}
		leo {
		    if $hardcopy_colorps {
			mess "Saving color postscript image to file\
				\"$hardcopy_file\" ...\n"
			command "write_postscript $hardcopy_file 1"
		    } else {
			mess "Saving monochrome postscript image to file\
				\"$hardcopy_file\" ...\n"
			command "write_postscript $hardcopy_file 0"
		    }
		}
	    }
	}
	image {
	    mess "Saving SGI image to file \"$hardcopy_file\" ...\n"
	    update
	    set x [winfo rootx .v.view]
	    set y [winfo rooty .v.view]
	    set w [winfo width .v.view]
	    set h [winfo height .v.view]
	    set sh [winfo screenheight .v.view]
	    exec [get_path scrsave] $hardcopy_file $x [expr {$x + $w}] \
		[expr {$sh - $y}] [expr {$sh - ($y + $h + 1)}]
	}
    }
    mess "Done.\n"
    
    if $hardcopy_print {
	case $hardcopy_type in {
	    ps {
		mess "Sending to printer...\n"
		exec [get_path lp] -d$hardcopy_printer $hardcopy_file
		mess "Done.\n"
	    }
	    image {
		set tops [get_path tops]
		if {$tops == ""} {
		    mess "Can't print file: the \"tops\" command wasn't\
			    located\n" red
		    return
		}
		mess "Converting to PostScript...\n"
		exec $tops $hardcopy_file -eps > $hardcopy_file.ps
		mess "Sending to printer...\n"
		exec [get_path lp] -d$hardcopy_printer $hardcopy_file.ps
		mess "Done.\n"
	    }
	}
    }
}

proc old__file_hardcopy_form {pref geo {format_choice 1}} {
    global form_done_flag hardcopy_file env hardcopy_printer
    global hardcopy_type hardcopy_colorps
    
    if ![info exists hardcopy_printer] { set hardcopy_printer PostScript }
    if ![info exists hardcopy_type]    { set hardcopy_type ps }
    if ![info exists hardcopy_colorps] { set hardcopy_colorps 0 }
    for {set num 1} 1 {incr num} {
	set hardcopy_file $pref.[format %02d $num]
	if ![file exists $hardcopy_file] break
    }
    
    set d [form_init .hardcopy_$pref "Hardcopy creation" file]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	
	if $format_choice {
	    form_label $d.typel "Hardcopy format:" {0 0 -cols -}
	    form_radiobutton $d.ps "PostScript" hardcopy_type ps {1 1}
	    set hps {{hardcopy_type ps}}
	    form_radiobutton $d.cps "Color" hardcopy_colorps 1 {1 2}
	    form_radiobutton $d.gps "Monochrome" hardcopy_colorps 0 {2 2} $hps
	    set sgi [expr {[get_path scrsave] != ""}]
	    form_radiobutton $d.image "SGI rgb format" hardcopy_type image \
		{3 1 -cols 2} $sgi
	}
	
	form_label $d.filel "Output file:" {7 0 -cols -}
	form_entry $d.file hardcopy_file string {8 1 -cols - -fill both}
	
	form_checkbutton $d.print "Send to printer" hardcopy_print \
		{9 0 -cols - -fill none}
	form_label $d.pname "Printer name" {10 1} {{hardcopy_print 1}}
	form_entry $d.printer hardcopy_printer string {10 2} \
		{{hardcopy_print 1}}
	
	form_colwidth $d 0 4 M
	form_rowheight $d 20 2
	form_finish $geo
    }
    tkwait variable form_done_flag(.hardcopy_$pref)
    set env(PRINTER) $hardcopy_printer
    return $form_done_flag(.hardcopy_$pref)
}

proc file_shell {} {
    global config_dir

    mess "Opening shell window in mesh directory ..."
    set here [pwd]
    cd $config_dir(mesh)
    catch { cmd_xterm -sb -geometry +0+0 & }
    cd $here
}
