# Library functions for the scripting library (scrib)
#
# File: scrib/lib/exec.tcl
#
# $Revision$ on $Date$
# 
# Copyright (c) 1993-2003 ICEM CFD Engineering
#
#--------------------------------------------------------------------
#
# --> if the name of the first proc already exists in interp, return
#
if {"" != [info commands scrib_lib_exec_medbatch]} { return }


## run med with the given script <em>script</em> with arguments <em>arg</em>
## logfile will be written to the optional arg <em>logfile</em> and
## the <em>interactive</em> argument specifies whether or not to run the gui.

proc scrib_lib_exec_medbatch {job_token base_script med_args exec_args} {
    global env
    
    set stat 0
    #
    # --> init defaults of and parse up the execution args
    #
    set logfile     ""
    set interactive 0
    set remote_host ""
    set remote_icemacn ""
    set batch_queueing_system ""
    set override_use_script ""
    
    if {"" != $exec_args} {
	set exec_args [scrib_lib_utils_strip_down_list $exec_args]
	foreach {n v} $exec_args {
	    if {"-" != [string range $n 0 0]} {
		mess "Warning: cannot interpret tag \"$n\" as option for med batch execution!\n" red
		continue
	    }
	    set [string range $n 1 end] $v
	}
    }
    
    set logdir .
    global proc_scrib_data
    if [info exists proc_scrib_data(wdir)] {
	set logdir $proc_scrib_data(wdir)
    }
    
    set custom_script ""
    if {"" == $override_use_script} {
	set custom_script [file join "$logdir" ${job_token}_med_script.tcl]
	set script [scrib_lib_exec_build_medscript $base_script $custom_script]
    } else {
	set script $override_use_script
    }
    
    set icemacn     ""
    
    if {("" == $remote_host) || ("localhost" == $remote_host)} {
	set mode [scrib_lib_exec_local]
    } else {
	set mode [scrib_lib_exec_remote]
	set icemacn $remote_icemacn
    }
    if {"" != $batch_queueing_system} {
	set mode [scrib_lib_exec_queued]
    }
    
    set prog [scrib_lib_exec_medbatch_progpath $icemacn $interactive]
    
    set args ""
    if {"" == $med_args} {
	#if { ( !$interactive ) && ( ![scrib_lib_utils_iswin] ) } { } since not using med_batch anymore
	if { !$interactive } {
	    append args "-batch "
	}
	append args "-script {$script} "
    }
    
    if {"" == $logfile} {
	set logfile [scrib_lib_utils_logfile "$logdir" "medlog"]
    }
    
    if {($mode == [scrib_lib_exec_remote]) || ($mode == [scrib_lib_exec_queued])} {
	set cshellscript [scrib_lib_exec_medbatch_cshellscript $icemacn $job_token $args]
    } else {
	set cshellscript ""
    }
    
    busy 1
    
    switch -- $mode {
	"REMOTE" {
	    set args ""
	    scrib_lib_exec_register_job $job_token HOST $remote_host REPLAYFILE "$script" \
		                        SHELLSCRIPT "$cshellscript" LOGFILE "$logfile" MODE $mode
	    #set stat [scrib_lib_remote_client_exec $job_token $remote_host $cshellscript $logfile $args]
	    set stat [scrib_lib_remote_rsh_exec $job_token $remote_host "$cshellscript" "$logfile" $args]
	    scrib_lib_exec_update_job_status $job_token [scrib_lib_exec_finished]
	}
	"BATCH_QUEUE" {
	    set stat [batch_queue::submit_job $batch_queueing_system -job_token $job_token \
			  -script "$cshellscript" -logfile "$logfile"]
	    scrib_lib_exec_register_job $job_token HOST "localhost" REPLAYFILE $script LOGFILE $logfile MODE $mode
	}
	default {
	    if {[info exists env(MED_DIR)] && (![string equal "" $env(MED_DIR)])} {
		set envname ""
		set prog med
	    } elseif {[info exists env(MED_ROOT)] && (![string equal "" $env(MED_ROOT)])} {
		set envname ""
		set prog med
	    } else {
		set envname ""
		if [scrib_lib_utils_iswin] {
		    if $interactive {
			set prog bin/med
		    } else {
			set prog bin/med_batch
		    }
		} else {
		    set prog bin/icemcfd
		}
	    }
	    scrib_lib_exec_register_job $job_token HOST "localhost" REPLAYFILE "$script" LOGFILE "$logfile" MODE $mode
	    #mess "\nDEBUG: here i am : scrib_lib_run_application_batch_exec_direct $prog $envname $args $logfile\n\n" red
	    if [catch {scrib_lib_run_application_batch_exec_direct "$prog" $envname $args "$logfile"} stat] {
		mess "Error: $prog exited with error status...$stat\n" red
		set stat -1 ;# not sure about this anymore... --jka fixme
	    }
	    scrib_lib_exec_update_job_status $job_token [scrib_lib_exec_finished]	    
	}
    }
    
    busy 0
    
    return $stat
}


## Create a C-shell script for running med in batch with the given
## ICEM_ACN <em>icemacn</em> and <em>med_args</em>. Returns the filename.

proc scrib_lib_exec_medbatch_cshellscript { replay_file {icemacn ""} } {
    
    set cmdfile [file join [file dirname $replay_file] "[file root [file tail $replay_file]]_med_startup.csh"]
    
    set medbin [scrib_lib_exec_medbatch_progpath $icemacn 0]
    set cmd "$medbin -batch -script $replay_file"
    
    set fp [open $cmdfile w]
    puts $fp "\#!/bin/csh -f"
    puts $fp "\#\n\# med startup script for job \"$replay_file\"\n"
    puts $fp "cd [file dirname $replay_file]"
    if {"" != $icemacn} {
	puts $fp "setenv ICEM_ACN $icemacn"
    }
    puts $fp $cmd
    close $fp
    cmd_chmod 0755 $cmdfile
    
    return $cmdfile
}


## Are we being exec'd in the med_batch interp?

proc scrib_lib_exec_inside_of_med {} {
    
    set cmd "ic_uns_is_loaded"
    return [string equal $cmd [info commands $cmd]]
}

# -----------------------------------------------------------------------------------------------------------------

proc scrib_lib_exec_remote {}     { return "REMOTE" }
proc scrib_lib_exec_local {}      { return "LOCAL" }
proc scrib_lib_exec_queued {}     { return "BATCH_QUEUE" }

proc scrib_lib_exec_running {}    { return "RUNNING"    }
proc scrib_lib_exec_terminated {} { return "TERMINATED" }
proc scrib_lib_exec_finished {}   { return "FINISHED"   }
proc scrib_lib_exec_unknown {}    { return "UNKNOWN"    }
proc scrib_lib_exec_misconfig {}  { return "MISCONFIGURED"  }

proc scrib_lib_exec_success {}    { return "SUCCESS"    }
proc scrib_lib_exec_failure {}    { return "FAILURE"    }

proc scrib_lib_exec_job_properties_list {} {
    return [concat [scrib_lib_exec_job_tmpfiles_list] [list HOST MODE PID]]
}
proc scrib_lib_exec_job_tmpfiles_list {} {
    return [list LOGFILE SHELLSCRIPT REPLAYFILE]
}

proc scrib_lib_exec_succeeded {stat} {
    if [string equal $stat [scrib_lib_exec_success]] { return 1 } else { return 0 }
}
proc scrib_lib_exec_failed {stat} {
    if [string equal $stat [scrib_lib_exec_failure]] { return 1 } else { return 0 }
}

## Register a job as running, optionally specifying job-properties

proc scrib_lib_exec_register_job {job_token args} {
    global scrib_lib_exec_job_status
    
    set scrib_lib_exec_job_status($job_token) [scrib_lib_exec_running]
    
    foreach {n v} $args {	
	scrib_lib_exec_set_job_datum $job_token $n $v
    }    
}


## 

proc scrib_lib_exec_set_job_datum {job_token datum_name val} {
    global scrib_lib_exec_job_data    
    set scrib_lib_exec_job_data($job_token,$datum_name) $val
}


## 

proc scrib_lib_exec_get_job_datum {job_token datum_name} {
    global scrib_lib_exec_job_data
    
    if ![info exists scrib_lib_exec_job_data($job_token,$datum_name)] {
	#mess "Warning: cannot find datum \"$datum_name\" for job \"$job_token\"\n" red FIXME
	return "__NONE__"
    }
    return $scrib_lib_exec_job_data($job_token,$datum_name)
}


## 

proc scrib_lib_exec_summarize_jobs {} {
 
    set job_token_list [scrib_lib_exec_job_token_list]
    set njobs [llength $job_token_list]
    if {0 >= $njobs} {
	mess "No known jobs to summarize\n" red
	return $njobs
    }
    
    set color green
    set job_incr 1
    mess "\nSummarizing known jobs:\n" $color
    foreach job_token $job_token_list {
	
	mess "\t--Job $job_incr: $job_token: [scrib_lib_exec_get_job_status $job_token]\n" $color
	foreach prop [scrib_lib_exec_job_properties_list] {
	    mess "\t\t$prop: [scrib_lib_exec_get_job_datum $job_token $prop]\n" $color
	}
	
	incr job_incr
    }
    
    mess "Reported $njobs jobs\n\n" $color
    
    return $njobs
}


## 

proc scrib_lib_exec_remove_job_traces {job_token} {
    global scrib_lib_exec_job_data
    
    set status [scrib_lib_exec_get_job_status $job_token]
    
    if {[scrib_lib_exec_running] == $status} {
	
	mess "Error: cannot remove job-traces for \"$status\" job \"$job_token\"" red
	return [scrib_lib_exec_failure]
	
    } elseif {[scrib_lib_exec_unknown] == $status} {
	
	mess "Error: cannot remove job-traces for \"$status\" job \"$job_token\"" red
	return [scrib_lib_exec_failure]
    }
    
    foreach prop [scrib_lib_exec_job_tmpfiles_list] {
	
	set tmpfile [scrib_lib_exec_get_job_datum $job_token $prop]	
	if [file isfile $tmpfile] {
	    cmd_rm $tmpfile
	    scrib_lib_exec_set_job_datum $job_token $prop "__NONE__"
	}
    }
}

##

proc scrib_lib_exec_update_job_status {job_token {status ""}} {
    global scrib_lib_exec_job_status    
    set scrib_lib_exec_job_status($job_token) $status
}

## 

proc scrib_lib_exec_get_job_status {job_token} {
    global scrib_lib_exec_job_status
    
    if {[info exists scrib_lib_exec_job_status] && \
	    [info exists scrib_lib_exec_job_status($job_token)]} {
	return $scrib_lib_exec_job_status($job_token)
    }
    
    return [scrib_lib_exec_unknown]
}

## Get a unique job token

proc scrib_lib_exec_get_unique_job_token {base} {
    global scrib_lib_exec_job_status
    for {set i 0} {[info exists scrib_lib_exec_job_status(${base}_${i})]} {incr i} {}
    return ${base}_${i}
}

## Get a list of all job tokens

proc scrib_lib_exec_job_token_list {} {
    global scrib_lib_exec_job_status
    
    if ![info exists scrib_lib_exec_job_status] {
	return ""
    }
    return [array names scrib_lib_exec_job_status]
}

## Is the given job still running?

proc scrib_lib_exec_job_is_running {job_token} {
    global scrib_lib_exec_job_status
    
    if [string equal [scrib_lib_exec_running] [scrib_lib_exec_get_job_status $job_token]] {
	return 1
    }
    
    return 0
}

## Are jobs still running?

proc scrib_lib_exec_jobs_are_running {} {
    global scrib_lib_exec_job_status
    
    foreach job_token [scrib_lib_exec_job_token_list] {
	if [scrib_lib_exec_job_is_running $job_token] {
	    return 1
	}
    }
    
    # no jobs are still running    
    return 0
}

## Get a list of all RUNNING job tokens

proc scrib_lib_exec_running_job_token_list {} {
    global scrib_lib_exec_job_status

    set running_jobs ""
    
    foreach job_token [scrib_lib_exec_job_token_list] {	
	if [scrib_lib_exec_job_is_running $job_token] {
	    lappend running_jobs $job_token
	}
    }
    
    return $running_jobs
}

## Kill all job-associated files

proc scrib_lib_exec_remove_traces {} {
    foreach job_token [scrib_lib_exec_job_token_list] {
	scrib_lib_exec_job_remove_job_traces $job_token
    }
}

##  Kill a job, whether remote, local or batch_queue

proc scrib_lib_exec_kill_job {job_token} {
    
    set mode [scrib_lib_exec_get_job_datum $job_token MODE]
    set status [scrib_lib_exec_get_job_status $job_token]
    if {[scrib_lib_exec_finished] == $status} {
	return [scrib_lib_exec_success]
    }
    
    switch -- $mode {
	"REMOTE" {
	    return [scrib_lib_remote_kill_job $job_token]
	}
	"BATCH_QUEUE" {
	    return [scrib_lib_queue_kill_job $job_token]
	}
	"LOCAL" - default {
	    set pid [scrib_lib_exec_get_job_datum $job_token PID]
	    if {"__NONE__" != $pid} {
		return [scrib_lib_exec_kill_local_process $pid]
	    }
	}
    }
    
    set host   [scrib_lib_exec_get_job_datum  $job_token HOST]
    mess "Error: could not kill $mode job \"$job_token\" on \"$host\"; job seems to be $status\n" red
    return [scrib_lib_exec_failure]
}

## Kill the given LOCAL process <em>pid</em>

proc scrib_lib_exec_kill_local_process {pid} {
    
    if {"" == $pid} {
	return [scrib_lib_exec_failure]
    }

    if {![catch {exec kill -9 $pid}]} {
	return [scrib_lib_exec_success]
    } else {
	mess "Error: could not kill process $pid\n" red
	return [scrib_lib_exec_failure]
    }
}

## Kill job and all associated files

proc scrib_lib_exec_nuke_job {job_token} {
    scrib_lib_exec_kill_job          $job_token
    scrib_lib_exec_remove_job_traces $job_token
}

## Nuke all jobs and their files

proc scrib_lib_exec_armageddon {} {
    foreach job_token [scrib_lib_exec_job_token_list] {
	scrib_lib_exec_nuke_job $job_token
    }
    # fixme: close all sockets, etc. too? clear queues too?
}

## execute the given command <em>command</em> for all files of the
## given cad system <em>cadsys</em> in the directory or list
## of files <em>dir_or_file_list</em>.

proc scrib_lib_exec_commands_foreach_file {commands files working_dir args {skipto_num 0} } {
    #
    # --> make sure the command exists; remove any which do not exist.
    #
    set valid_commands ""
    foreach command $commands {
	if {"" == [info commands $command]} {
	    mess "Error: couldn't get the command given: $command\n" red
	} else {
	    lappend valid_commands $command
	}
    }
    set commands $valid_commands
    if {"" == $commands} {
	mess "Error: no valid command to execute on the given files\n"
	return $files
    }
    #
    # --> check that we have some files to work on
    #
    set nfiles [llength $files]
    if {0 >= $nfiles} {
	mess "Error: no given files on which to execute commands\n"
	return ""
    }
    #
    # --> check for funny characters in the filenames
    #
    set files [scrib_lib_exec_filenames_validate $files]
    #
    # --> cd into the working directory
    #
    if {("" != $working_dir) && (![file isdirectory $working_dir])} {
	scrib_lib_utils_mkdir $working_dir
	cd $working_dir
    }
    #
    # --> now go through each of the files in the list
    #
    set number [llength $files]
    set counter 1
    foreach f $files {
	if {$counter < $skipto_num} {incr counter; continue}
	#
	# --> the file may be zipped up
	#
	set item [scrib_lib_utils_unzip_file $f]
	#
	# --> tell the user what's happening
	#
	set text "Working on $counter of $number files"
	mess "\n$text:\n\t$item\n\n"
	scrib_app_status_update "$text: [file tail $item]"
	#
	# --> Try each command, etc.
	#
	foreach command $commands {
	    #
	    # --> do the meshing and output for this file	
	    #	    
	    set stat [$command $item $args]
	    #
	    # maybe the command was killed. ben wants this to break the whole loop
	    # for now. --jka
	    #
	    if {0 >= $stat} {
		mess "$command has been interrupted for file $item...\n" red
		scrib_app_status_update "Execution interrupted by user"
		break
	    }	    
	}
	if ![string equal $item $f] {
	    scrib_lib_utils_zip_file $f "gzip"
	}
	
	if {0 >= $stat} {
	    break
	}

	incr counter
    }
    #
    # --> cd back to original directory
    #
    if {[info exists orig_dir] && [file isdirectory $orig_dir]} {
	cd $orig_dir
    }
    
    return $files
}

## get thed med executable program path based on current env vars

proc scrib_lib_exec_medbatch_progpath {{icemacn ""} {interactive 0}} {
    global env
    
    # --> MED_DIR, MED_ROOT: this is for me...    
    
    if { ( [info exists env(MED_DIR)]  && ![string equal "" $env(MED_DIR)]  ) || \
	     ( [info exists env(MED_ROOT)] && ![string equal "" $env(MED_ROOT)] )} {
	
	set prog med
	
    } else {
	
	if {"" == $icemacn} {
	    set icemacn $env(ICEM_ACN)
	}
	
	if {[scrib_lib_utils_iswin] && !$interactive} {
	    set prog [file join $icemacn bin med_batch]
	} else {
	    set prog [file join $icemacn bin med]
	}
    }
    
    return $prog
}


## Write a standalone script <em>outscript</em> with the current
## scrib_data, comprising the scripts <em>bodyscripts</em>.

proc scrib_lib_exec_build_medscript {bodyscripts outscript} {
    global env proc_scrib_data
    #
    # check input a bit
    #
    if {"" == $bodyscripts} {
	error "asdf"
	mess "cannot open null body scripts\n" red
	return
    }
    if {"" == $outscript} {
	set outscript "[file root [file tail $body_script]]_standalone.tcl"
	mess "set unspecified output script to $outscript\n" red
    }
    #
    # open up the outscript for writing
    #
    if [catch {open $outscript w} fp] {
	mess "Error: could not open script file for writing: " red
	if ![file writable $outscript] {
	    mess " check permissions on directory\n" red
	}
	mess " [file dirname $outscript]\n" red
	return
    }
    #
    # copy in all of the array data
    #
    puts $fp "# this file created by scrib_lib_exec_build_medscript"
    puts $fp "# in \"$::ScribApp::_app_name\" built on ICEM CFD ScribApp v.$::ScribApp::_version\n"
    puts $fp "global proc_scrib_data"
    puts $fp [scrib_lib_utils_format_array proc_scrib_data]
    puts $fp "global proc_mesh_param_data"
    puts $fp [scrib_lib_utils_format_array ::ScribApp::_mesh_param_data proc_mesh_param_data]
    #
    # copy in all of the array data and source commands
    #
    puts $fp "global env"
    set libpath    [file join $env(ICEM_SCRIB) lib]
    set setup_file [file join $libpath setup.tcl]
    puts $fp "source \"$setup_file\"\n"
    #
    # note that this list has to be updated when a lib/*.tcl file is added xxxxxxx
    # it could be gotten from ::ScribLib::_lib_files
    #
    set req_files [scrib_lib_source_files_get]
    putdebug "req_files $req_files----\n"
    if {"" == $req_files} {
	#set req_files [glob -nocomplain -type f $libpath/*.tcl]
    }
    puts $fp "set required_files \{ $req_files \}\n"
    
    puts $fp "scrib_lib_setup_source_files \$required_files"
    #
    # now copy in the source code of the $bodyscript scripts
    #
    foreach bod $bodyscripts {
	#
	set properbod [scrib_lib_exec_script_path_get $bod] 
	#
	puts $fp "#\n# --> BEGIN source from script $properbod ---------\n#"
	set ifp [open $properbod r]
	puts $fp [read $ifp]
	close $ifp
	puts $fp "# --> END source from script $properbod -----------\n#\n#"
    }
    #
    # write out the end of the script
    #
    puts $fp "if {\[info exists proc_scrib_data(interactive)\] && \
	    \$proc_scrib_data(interactive)} {\n \
	    \tscrib_lib_exec_med_display_update\n}\n"
    
    close $fp
    
    return $outscript
}

## determine whether or not the script is being run in the ai_env context.

proc scrib_lib_exec_running_aienv {} {
    global env
    if {[info exists env(ICEM_AI_ENVIRONMENT)] && (1 == $env(ICEM_AI_ENVIRONMENT))} {
	return 1
    }
    return 0
}

## update the display based on the med_gui implementation

proc scrib_lib_exec_med_display_update {} {
    
    if [scrib_lib_exec_running_aienv] {
	
	if [catch { aie_create_initial_assemblies } res] { mess "$res\n" red }
	if [catch { aie_initGeoVis } res] { mess "$res\n" red }
	if [llength [info commands aie_getBatchGeomDisplay]] {aie_getBatchGeomDisplay}

	if [ic_uns_is_loaded] {
	    if [catch { aie_updateMeshVis } res] { mess "$res\n" red }
	    scrib_lib_quality_show
	    aie_changeMeshDisplay style color_by_quality
	    if [catch { aie_getBatchMeshDisplay 1} res] { mess "$res\n" red }
#	    aie_initialize_tree_props_and_icons
	}
	
    } else {
	
	if [catch { display_update } res] { mess "$res\n" red }
	if [catch { med_home } res] { mess "$res\n" red }
	if [ic_uns_is_loaded] {	scrib_lib_quality_show }
    }    
}

## Load a params file into the med/ai_env app

proc scrib_lib_exec_med_display_load_params {file} {
    
    if {("" == $file) || ![file exists $file]} {
	mess "Error: cannot load params file \"$file\"\n" red
	return 0
    }
    
    if [scrib_lib_exec_running_aienv] {	
	if [catch { aie_load_params_file $file} res] {
	    mess "$res\n" red
	    return 0
	}
    } else {
	if [catch {famboco_edit_load_param_values $file} res] {
	    mess "$res\n" red
	    return 0
	}
    }
    
    return 1
}

## returns a valid path to the given script name

proc scrib_lib_exec_script_path_get {script} {
    global env
        
    if [file exists $script] {
	return $script
    }    
    #
    # try it as having been given as a some other path
    #
    if [file exists [file join $env(ICEM_SCRIB) scripts $script]] {
	set script [file join $env(ICEM_SCRIB) scripts ${script}]
    } elseif [file exists [file join $env(ICEM_SCRIB) scripts ${script}.tcl]] {
	set script [file join $env(ICEM_SCRIB) scripts ${script}.tcl]
    } else {
	mess "Error: cannot find script file $script"
	return ""
    }
    return $script
}

## 

proc scrib_lib_exec_name_validate {filename {extension ""}} {
    
    set path    [file dirname   $filename]
    set f       [file tail      $filename]
    if {"" == $extension} {
	set tailend [file extension $filename]
    } else {
	set tailend ".$extension"
	set tailend ".$extension"
    }
    while ![string is wordchar -failindex find $f] {
	set lastind [expr $find + [string length $tailend]]
	set thisthing [string range $f $find $lastind]
	if [string match $thisthing $tailend] {
	    break
	}
	set f [string replace $f $find $find "_"]
	if [string is wordchar -failindex find $f] {
	    break
	}
    }
    if {"." == $path} {	return $f } else { return [file join $path $f] }
}

## needs doc.

proc scrib_lib_exec_filenames_validate {files {extension ""}} {
    #
    # --> check for funny characters in the filenames
    #
    for {set i 0} {$i < [llength $files]} {incr i} {
	set init [lindex $files $i]
	set f [scrib_lib_exec_name_validate $init $extension]
	if ![string match $f $init] {
	    set files [lreplace $files $i $i $f]
	    mess "must rename peculiar filename $init to $f\n" green
	    cmd_mv $init $f
	}
    }
    return $files
}

## needs doc.

proc scrib_lib_exec_messages_save {fname} {
    global message_save_directory mess_frame is_win
    
    if {"" == $fname} {
	set dir .
	if [info exists message_save_directory] {
	    set dir $message_save_directory
	}
	for {set num 1} 1 {incr num} {
	    set fname [file join $dir messages.[format %02d $num]]
	    if $is_win { append fname .txt }
	    if ![file exists $fname] break
	}
	set fname [file_selection -message "Select the file to save messages to." \
		       -default $fname -new_ok 1 -mkdir_button 1]
	if {$fname == ""} return
    }
    
    set fp [open $fname w]
    
    set username [cmd_whoami]
    set host [cmd_uname_n]
    set date [cmd_date]
    
    puts $fp "----- Message log saved by $username@$host at $date"
    puts $fp [$mess_frame.text get 1.0 end]
    close $fp
    
    return $fname
}


## Manage interrupt of operations. Interface to that used in guibase/interrupt.tcl
# But, "interrupt" of gui interp should be accessible to script interp in med. fixme--jka

proc scrib_lib_exec_interrupt {args} {
    global env
    
    if {"" == [info commands interrupt]} {
	
	if [info exists env(GUIBASE_DIR)] {
	    set interrupt_file [file join $env(GUIBASE_DIR) interrupt.tcl]
	} elseif [info exists env(ICEM_ACN)] {
	    set interrupt_file [file join $env(ICEM_ACN) lib guibase interrupt.tcl]
	} else {
	    mess "Error: cannot find good place from which to get the interrupt command\n"
	}
	
	if {[info exists interrupt_file] && [file exists $interrupt_file]} {
	    source $interrupt_file
	}
	if {"" == [info commands interrupt]} {
	    mess "Error: could not provide interrupt command from within scriblib\n"
	    return 0
	}
    }
    
    return [interrupt $args]
}

# map guibase_mess to the body of the current guibase- mess proc

#eval "proc guibase_mess \{line \{color \"\"\} \{font \"\"\} \{update 1\} \{show_tail 1\}\} \{\n [info body mess] \n\}"

#puts "\n[info args guibase_mess] ... [info body guibase_mess]\n"

## Like guibase mess, but will handle debugging prints, and timing data

proc scrib_lib_mess {text {color black} {font ""} {update 1} {show_tail 1}} {
    global proc_scrib_data debug
    
    # --> return if this is only a debugging print & debugging is not on
    
    set debug_text ""
    if {"debug" == $color} {
	if ![info exists debug] {
	    return
	} else {
	    # else set the color to....blue?
	    set color "blue"
	    if 0 { set debug_text "\n#** scrib_debug: " } ;# no extra string....not now --jka
	}
    }
    
    # --> if we are timing then prepend the string with some timing info
    
    set time_text ""
    if [info exists proc_scrib_data(timing)] {
	
	# --> ...could be relative or absolute timing
	
	set time_text ""
	switch -- $proc_scrib_data(timing) {
	    
	    "relative" - "rel" {
		set start_time 
		append time_text "\n\[[expr [clock seconds] - $start_time] s\]: "
	    }
	    
	    "absolute" - "abs" {
		append time_text "\n\[[clock format [clock seconds]]\]: "
	    }
	    
	}
    }
    
    mess "${debug_text}${time_text}${text}" $color
}


## Just gets mapped to scrib_lib_mess

#proc mess {line {color black} {font ""} {update 1} {show_tail 1}} {
#    return [scrib_lib_mess $line $color $font $update $show_tail]
#}














##

proc unused_scrib_lib_exec_command {command args} {
    
    switch -- $mode {
	"BATCH_QUEUE" {
	    eval scrib_lib_exec_command_queue $command $args
	}
	"LOCAL" {
	    eval scrib_lib_exec_command_local $command $args
	}
	"REMOTE" {
	    eval scrib_lib_exec_command_remote $command $args
	}
	default {
	    mess "Error: cannot execute in mode $mode\n" red
	}
    }
}

## needs doc

proc unused_scrib_lib_exec_command_local {commands inputfile outputfile success_checks failure_checks failure_callbacks} {
    
    #
    # --> get the export file name for this file
    #
    set exportformat [string totitle $proc_scrib_data(export)]
    set exportfile [scrib_lib_export_filename_get $proc_scrib_data(export_dir) $file \
	    $proc_scrib_data(export_extension)]

    set empty_export [scrib_lib_export_filename_get $proc_scrib_data(export_dir) $file \
	    $proc_scrib_data(export_extension) empty]
    #
    # --> if that file already exists, then continue. it must have been created.
    #
    if [file exists $exportfile] {
	return 1
    }
    if [file exists $empty_export] {
	return 1
    }
    #
    # --> this list of values is given to the batch mode run of med
    #
    #     for a standard scrib/script/*.tcl file, use this proc
    #     to get the args for the call to scrib_lib_exec_medbatch
    #
    set proc_scrib_data(model) $inputfile
    
    foreach command $command {
	
	set stat [scrib_lib_exec_medbatch "$script" "" "" $proc_scrib_data(interactive)]
	
	if [eval $success_callbacks] {
	    
	    mess "Finished with model $file\n\n-------------------------------------------------------\n"
	    return $stat
	}
	
	
    }

    if {0 > $stat} {
	# xxxxxxxx this may not be completely descriptive???... --jka
	return -1
    }
    
    if [file exists $exportfile] {
	#
	# --> everything is ok
	#
	scrib_lib_utils_report_message \
		"Created $exportformat export file:\n\t[file tail $exportfile]\n"
	#
 	# --> it's possible that the mesher script did not find surfaces,
    	#     and so would have created an empty_export type file
    	#
    } elseif [file exists $empty_export] {
	#
	# --> we have an empty surfs file, so report that
	#
	scrib_lib_utils_report_message "There were no surfs in file $file\n"
	#
    } else {
	#
	# --> otherwise, try running second script file
	#
	scrib_lib_utils_report_message \
		"Could not create $exportformat file:\n\t[file tail $exportfile]\n"
	#
	# --> make a "failed" directory, and copy the file there
	#   
	if ![info exists proc_scrib_data(failed_dir)] {
	    set proc_scrib_data(failed_dir) [file join $proc_scrib_data(wdir) failed_dir]
	}
	if ![file exists $proc_scrib_data(failed_dir)] {
	    file mkdir $proc_scrib_data(failed_dir)
	}
	scrib_lib_utils_report_message \
		"Copying $proc_scrib_data(cadsys) file to $proc_scrib_data(failed_dir)\n"
	catch { file copy [file join $proc_scrib_data(cad_dir) $file] $proc_scrib_data(failed_dir) }
	#
	# --> try running second script if available
	#
	if [file exists $script2] {
	    scrib_lib_utils_report_message "Trying to mesh with [file tail [file rootname $script2]] \n"
	    set stat [scrib_lib_exec_medbatch "$script2" $args record $proc_scrib_data(interactive)]
	    mess "Finished trying [file tail [file rootname $script2]] on the model $file.\n"
	}
    }
    
}

## execute the given command <em>command</em> for all files of the
## given cad system <em>cadsys</em> in the directory or list
## of files <em>dir_or_file_list</em>.

proc unused_scrib_lib_exec_foreach_file {command cadsys dir_or_file_list {working_dir ""}} {
    #
    # --> make sure the command exists
    #
    if {"" == [info commands $command]} {
	mess "Error: couldn't get the command given: $command\n" red
	return ""
    }
    #
    # --> base behavior on the cad system
    #
    set extension [scrib_lib_geo_cadsys_extension_get $cadsys]
    if {"" == $extension} {
	mess "Error: don't know what to do with files of type: $cadsys\n" red
	return ""
    }
    
    if {1 < [llength $dir_or_file_list] || [file isfile [lindex $dir_or_file_list 0]]} {
	
	# then we have a file_list	
	set files $dir_or_file_list
	
    } elseif [file isdirectory $dir_or_file_list] {
	#
	# --> if these files are in a specific directory, cd there
	#     save the starting directory path
	#
	set orig_dir [pwd]
	if [file isdirectory $dir_or_file_list] {
	    cd $dir_or_file_list
	} else {
	    mess "Warning: could not cd into directory $dir_or_file_list\n" red
	}
	#
	# --> get a list (files) of all the files in the directory
	#     with the proper extension
	#
	set files ""
	foreach item [glob -nocomplain -type f *.$extension] {
	    if {($cadsys == "domain") && ([string range [file root $item] end-5 end] == "offset")} {
		continue
	    }
	    lappend files $item
	}
    }
    
    set nfiles [llength $files]
    #
    # --> the files may be gzip'ed
    #
    set regzfiles ""
    foreach item [glob -nocomplain -type f *.${extension}.gz] {
	exec gunzip $item
	set item [file rootname $item]
	lappend files $item
	lappend regzfiles $item
    }
    if ![llength $files] {
	mess "Found no .$extension files in [pwd]...returning\n" red
	cd $orig_dir
	return ""
    }
    #
    #
    mess "\nFound .$extension files:\n"
    foreach f $files { mess "\t$f\n" }
    mess "in directory [pwd]\n"
    set nregzfiles [llength $regzfiles]
    if { 0 <$nregzfiles} {
	mess "$nregzfiles of the files [expr {($nregzfiles == 1) ? "was" : "were"}] gzip'ed; \
		$nfiles [expr {($nfiles == 1) ? "was" : "were"}] not\n"
    }
    #
    # --> check for funny characters in the filenames
    #
    set files [scrib_lib_exec_filenames_validate $files $extension]
    #
    # --> cd into the working directory
    #
    if {("" != $working_dir) && ($working_dir != $dir_or_file_list)} {
	if ![file isdirectory $working_dir] {
	    scrib_lib_utils_mkdir $working_dir
	}
	cd $working_dir 
    }
    #
    # --> now go through each of the files in the list
    #
    set number [llength $files]
    set counter 1
    foreach file $files {
	#
	# --> tell the user what's happening
	#
	mess "\nWorking on $counter of $number files:\n\t$file\n\n"
	#
	# --> do the meshing and output for this file	
	#
	set stat [$command $file]
	# maybe the command was killed. ben wants this to break the whole loop
	# for now. --jka
	if {0 >= $stat} {
	    mess "$command has been interrupted...\n" red
	    break
	}
	incr counter
    }
    #
    # --> re-gzip those files that were gzip'd
    #
    foreach item $regzfiles {
	exec gzip $item
    }
    #
    # --> cd back to original directory
    #
    if {[info exists orig_dir] && [file isdirectory $orig_dir]} {
	cd $orig_dir
    }
    
    return $files
}


## This is duplication to run_application_batch_exec_direct which itself is a duplication of run_application_batch
## I think that run_application_batch_exec_direct is now useless, but not sure, I am just trying to fix Jason's stuff
## so I can get the batch mesher working again...  BEN  maybe this can get combined with run_application_batch, 
## but not sure of how this is used.

proc scrib_lib_run_application_batch_exec_direct {path envname extra {logfile ""}} {
    global application_batch_done env is_win application_pid
    global application_running
    global application_but_status application_but_terminate
    global application_is_remote application_exec_direct
    
    set logfile_tmp 0
    if [info exists application_running] {
	set mess "An application ($application_running) is already running. Terminate it and run new application?"
	set ret [tk_dialog .tivc "Terminate" $mess "" 0 "Terminate it" "Don't run new application"]
	if { $ret } {
		return -1
	}
	application_terminated
    }

    if {($envname != "") && [info exists env($envname)]} {
	# The value of the environment variable is the path to the exec
	set progpath $env($envname)
	if $is_win {
	    regsub -all \\\\ $progpath / progpath	
	}
    } else {
	set progpath [get_program [file dirname $path] [file tail $path] 0]
    }
    if $is_win {
        set command "\"$progpath\" $extra"
    } else {
        set command "$progpath $extra"
    }

    if {$logfile == ""} {
        set logfile_tmp 1
	set logfile [cmd_tempfile medlog .tmp]
    }
    
    set application_running [file tail $path]
    
    set application_is_remote 0
    set application_exec_direct 1
    mess "Running: $command\n"
    set pid [eval exec "$command >& {$logfile} &"]
    set cmdfile ""
    
    # Now wait for the log file.
    for {set i 0} {$i < 60} {incr i} {
	if [file exists "$logfile"] break
	if {$i > 40} {
	    mess "Warning: file exists $logfile -> 0\n" red
	}
	after 1000
    }
    if {$i == 60} {
	mess "Error: program didn't start -- can't find log file\n" red
	unset application_running
	return 0
    }
    mess "Program is running: pid = $pid\n"

    catch {unset application_batch_done}

    set application_pid $pid
    application_check_exists
    
    set application_but_status [message_add_button status \
				    "Show status" "application_status"]
    set application_but_terminate [message_add_button terminate \
				       "Terminate" "scrib_lib_exec_application_terminated"]
    message_enable_button $application_but_status active
    message_enable_button $application_but_terminate active

    set fp [open $logfile r]
    tail_dashf $fp "tail_application_log $fp $pid"

    if ![info exists application_batch_done] {
	vwait application_batch_done
    }

    update idle
    tail_dashf_cancel $fp
    
    close $fp
    
    set fp [open $logfile r]
    set line ""
    while { ![eof $fp ] } {
	set last_line $line
	set line [ gets $fp ]
    }
    close $fp
    set error_exit 0
    if { $last_line == "status 1" } {
	mess "Application did not finish correctly.\n" red
	set error_exit 1
    } else {
        mess "Application is finished.\n"
    }
    
    message_remove_button status
    message_remove_button terminate
    if {$cmdfile != ""} { rm_tmp_file $cmdfile }
    if { $logfile_tmp } {
        rm_tmp_file $logfile
    }
    catch {unset application_running}
    
    if { $application_batch_done && $error_exit == 0 } {
# okay exit
	return 1
    } elseif { $application_batch_done } {
# error exit
	return 0
    } elseif { 0 == $application_batch_done} {
# killed exit
	return -1
    } else {
	error "ill-considered case in run_application_batch_exec_direct"
    }
}

## This is duplicated from application_terminated in guibase/run_application.tcl  
## Needed due to fact that batch mesher has multiple applications to terminate.

proc scrib_lib_exec_application_terminated {} {
    global application_pid application_batch_done application_running
    global application_is_remote
    
    # This is because when we press the button we're in the gui interp but
    # the real work is being done in the batch interp.
    if [interp exists batch_interp] {
	batch_interp eval application_terminated
	return
    }
    
    if ![info exists application_pid] {
	mess "Can't terminate process: PID is not known (yet).\n" red
	catch {unset application_running}
	return
    }
    set done 0
    set x [tk_dialog .really_kill "Kill job" " Really terminate job?\n\
	    Intermediate data will be lost." "" -1 Yes No All] 
    switch $x {
	0 {set done 1}
	1 {return}
	2 {set done 0}
	default {mess "not supported kill method in scrib_lib_exec_application_terminated\n" ; return}
    }
    
    if $application_is_remote {
	if [catch {application_exec "kill -9 $application_pid" "" 1} res] {
	    mess "$res\n" red
	}
	
    } else {
	if [catch {cmd_kill $application_pid 9} res] {
	    mess "$res\n" red
	}
    }
    
    mess "Job killed.\n"
    catch {after cancel application_check_exists}
    set application_batch_done $done
}


proc scrib_lib_exec_generate_script {commands file working_dir args {skipto_num 0} } {
    #
    # --> make sure the command exists; remove any which do not exist.
    #
    set valid_commands ""
    foreach command $commands {
	if {"" == [info commands $command]} {
	    mess "Error: couldn't get the command given: $command\n" red
	} else {
	    lappend valid_commands $command
	}
    }
    set commands $valid_commands
    if {"" == $commands} {
	mess "Error: no valid command to execute on the given files\n"
	return $files
    }
    #
    # --> check that we have some files to work on
    #
    set nfiles [llength $file]
    if {0 >= $nfiles} {
	mess "Error: no given files on which to execute commands\n"
	return ""
    }
    #
    # --> check for funny characters in the filenames
    #
    set file [scrib_lib_exec_filenames_validate $file]
    #
    # --> cd into the working directory
    #
    if {("" != $working_dir) && (![file isdirectory $working_dir])} {
	scrib_lib_utils_mkdir $working_dir
	cd $working_dir
    }
    #
	# --> Try each command, etc.
	#
	foreach command $commands {
	    #
	    # --> do the meshing and output for this file	
	    #	    
	    set stat [$command $item $args]
	    #
	    # maybe the command was killed. ben wants this to break the whole loop
	    # for now. --jka
	    #
	    if {0 >= $stat} {
		mess "$command has been interrupted for file $item...\n" red
		scrib_app_status_update "Execution interrupted by user"
		break
	    }	    
	}
	
	if {0 >= $stat} {
	    break
	}

	incr counter
    }
    #
    # --> cd back to original directory
    #
    if {[info exists orig_dir] && [file isdirectory $orig_dir]} {
	cd $orig_dir
    }
    
    return $file
}





proc scrib_lib_exec_commands_foreach_model {commands file working_dir args {skipto_num 0} } {

    global gettings

    #
    # --> make sure the command exists; remove any which do not exist.
    #
    set valid_commands ""
    foreach command $commands {
	if {"" == [info commands $command]} {
	    mess "Error: couldn't get the command given: $command\n" red
	} else {
	    lappend valid_commands $command
	}
    }
    set commands $valid_commands
    if {"" == $commands} {
	mess "Error: no valid command to execute on the given files\n"
	return $files
    }
    #
    # --> check that we have some files to work on
    #
    set nfiles [llength $file]
    if {0 >= $nfiles} {
	mess "Error: no given files on which to execute commands\n"
	return ""
    }
    #
    # --> check for funny characters in the filenames
    #
    set file [scrib_lib_exec_filenames_validate $file]
    #
    # --> cd into the working directory
    #
    if {("" != $working_dir) && (![file isdirectory $working_dir])} {
	scrib_lib_utils_mkdir $working_dir
	cd $working_dir
    }
    #
    # --> now go through each of the files in the list
    #
    foreach f $file {
	if {$counter < $skipto_num} {incr counter; continue}
	#
	# --> the file may be zipped up
	#
	set item [scrib_lib_utils_unzip_file $f]
	#
	# --> tell the user what's happening
	#
	set text "Working on $settings(counter) of $settings(no_models) files"
	mess "\n$text:\n\t$item\n\n"
#        mess "Here I am \n"   
	scrib_app_status_update "$text: [file tail $item]"
	#
	# --> Try each command, etc.
	#
	foreach command $commands {
	    #
	    # --> do the meshing and output for this file	
	    #	    
	    set stat [$command $item $args]
	    #
	    # maybe the command was killed. ben wants this to break the whole loop
	    # for now. --jka
	    #
	    if {0 >= $stat} {
		mess "$command has been interrupted for file $item...\n" red
		scrib_app_status_update "Execution interrupted by user"
		break
	    }	    
	}
	if ![string equal $item $f] {
	    scrib_lib_utils_zip_file $f "gzip"
	}
	
	if {0 >= $stat} {
	    break
	}

	incr settings(counter)
    }
    #
    # --> cd back to original directory
    #
    if {[info exists orig_dir] && [file isdirectory $orig_dir]} {
	cd $orig_dir
    }
    
    return $file
}



proc scrib_lib_exec_build_script {bodyscripts outscript} {
    global env proc_scrib_data
  
    set host [hostname]
 #
    # check input a bit
    #
    if {"" == $bodyscripts} {
	error "asdf"
	mess "cannot open null body scripts\n" red
	return
    }
    if {"" == $outscript} {
	set outscript "[file root [file tail $body_script]]_standalone.tcl"
	mess "set unspecified output script to $outscript\n" red
    }
    #
    # open up the outscript for writing
    #
    if [catch {open $outscript w} fp] {
	mess "Error: could not open script file for writing: " red
	if ![file writable $outscript] {
	    mess " check permissions on directory\n" red
	}
	mess " [file dirname $outscript]\n" red
	return
    }
    #
    # copy in all of the array data
    #
    puts $fp "# this file created by scrib_lib_exec_build_medscript"
    puts $fp "# in \"$::ScribApp::_app_name\" built on ICEM CFD ScribApp v.$::ScribApp::_version\n"
    puts $fp "global proc_scrib_data"
    puts $fp [scrib_lib_utils_format_array proc_scrib_data]
    puts $fp "global proc_mesh_param_data"
    puts $fp [scrib_lib_utils_format_array ::ScribApp::_mesh_param_data proc_mesh_param_data]
    #
    # copy in all of the array data and source commands
    #
    puts $fp "global env"
    set libpath    [file join $env(ICEM_SCRIB) lib]
    set setup_file [file join $libpath setup.tcl]
    puts $fp "source \"$setup_file\"\n"
    #
    # note that this list has to be updated when a lib/*.tcl file is added xxxxxxx
    # it could be gotten from ::ScribLib::_lib_files
    #
    set req_files [scrib_lib_source_files_get]
    putdebug "req_files $req_files----\n"
    if {"" == $req_files} {
	#set req_files [glob -nocomplain -type f $libpath/*.tcl]
    }
    puts $fp "set required_files \{ $req_files \}\n"
    
    puts $fp "scrib_lib_setup_source_files \$required_files"
    #
    # now copy in the source code of the $bodyscript scripts
    #
    foreach bod $bodyscripts {
	#
	set properbod [scrib_lib_exec_script_path_get $bod] 
	#
	puts $fp "#\n# --> BEGIN source from script $properbod ---------\n#"
	set ifp [open $properbod r]
	puts $fp [read $ifp]
	close $ifp
	puts $fp "# --> END source from script $properbod -----------\n#\n#"
    }
    #
    # write out the end of the script
    #
    puts $fp "if {\[info exists proc_scrib_data(interactive)\] && \
	    \$proc_scrib_data(interactive)} {\n \
	    \tscrib_lib_exec_med_display_update\n}\n"
    puts $fp "if \[file exists $host-is-busy]\ \{\n\teval cmd_rm_r $host-is-busy\n\}\n"
   puts $fp "set done_replay \[open $host-is-done w\]" 
   puts $fp "close \$done_replay" 

   close $fp
    
 return $outscript
}








