
# This code creates the user interface for the mesh editor.
#
# Copyright (c) 1997 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Jari Spaete jari.spaete@ansys.com
# $Revision$ on $Date$

# This file contains special comments of the form ## html ... which are
# used to automatically generate documentation

## <h3>Utility functions</h3>

## Print the given message to the message window or the standard output if
## med is being run in batch mode.  There may be 1 or 2 arguments.  The first
## is the string and the second if given is the color to print the message
## in.

proc ic_mess {args} {
    # Need to translate from embedded \n to real newline.  Why this needs 4 \ I don't know
    regsub -all \\\\n $args \n args
    return [eval mess $args]
}

proc ic_mess_skipped {args} {
    
    return [ic_mess "Skipped: $args\n" darkgreen]
}

proc status_message {args} {
    # debug version; uses gui_interp proc status_message
  		vic_eval status_message $args 
  		vic_eval update idletasks 
}

## Print the error log <b>res</b> to the screen in red. If there are more
## than 64 lines, they will all be saved to a temporary file such as the
## default /tmp/ERROR_LOG0.tmp

proc ic_print_error_log {res} {
    set np 0
    foreach r $res {
        ic_mess "\t$r"
        incr np
        if {$np > 64} {
            set file [cmd_tempfile ERROR_LOG .tmp]
            set fp [open $file w]
            puts $fp $res
            close $fp
            ic_mess "[expr [llength $res] - 64] more messages - not printed\n" red
            ic_mess "All messages saved to file $file\n" red
            break
        }
    }
}

## Create a file with some stuff in it

proc ic_write_file {name text} {
    # there might be \n's in the text (not a control-R, but 2 characters)
    regsub -all \\\\n $text \n text
    set fp [open $name w]
    puts -nonewline $fp $text
    close $fp
}

## Quit med and save the current project settings.

proc ic_quit {} {
    global batch_mode

    if $batch_mode {
	ic_undo_stop
	exit 0
    }
    file_quit 0
}

## Call the <b>tk_dialog</b> utility function.

proc ic_dialog {args} {
    return [eval tk_dialog $args]
}

## Query the user to input a string value.

proc ic_question {args} {
    return [eval question_box $args]
}

## Present a dialog with a message and one button that says Ok that just
## dismisses the dialog.

proc ic_confirm {mess} {
    global batch_mode

    if !$batch_mode {
        tk_dialog .lpopup_message Message $mess "" -1 Ok
    }
}

## Present a dialog with a message and 2 buttons, which say Yes or No.
## Returns 1 or 0 depending on which is pressed.

proc ic_yes_or_no {mess} {
    return [expr ![tk_dialog .lpopup_message Query $mess "" -1 Yes No]]
}

## Present a dialog with a message and multiple buttons with the given
## labels.  Returns the ordinal of the one that the user presses.

proc ic_multiple_choice {mess args} {
    return [eval tk_dialog .lpopup_message Query \{$mess\} \{\} -1 $args]
}

## Same as <em>ic_multiple_choice</em> but <em>default</em> gives the index of the
## button that is to be the default button for the dialog. If less than zero then
## there won't be any default button.

proc ic_multiple_choice_default {default mess args} {
    return [eval tk_dialog .lpopup_message Query \{$mess\} \{\} $default $args]
}

## Wait for <em>ms</em> milliseconds, processing regular Tk events, and then
## return.

proc ic_pause {ms} {
    global ic_pause_variable
    set ic_pause_variable 0
    after [expr int($ms)] set ic_pause_variable 1
    vwait ic_pause_variable
}

## Check for batch mode.

proc ic_batch_mode {} {
    global batch_mode

    if $batch_mode {return 1}
    return 0
}
set dont_record_command(ic_batch_mode) 1

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

## Run some external application.

proc ic_run_application_command {dir progdir progname arguments} {
    set olddir [pwd]
    if [catch {cd $dir} res] {
	mess "Can't change directory: $res\n"
    }
    if {$progdir == ""} {
	set app $progname
    } else {
	set app [get_program $progdir $progname]
    }
    catch {
	run_application_command "\"$app\" $arguments"
    }
    cd $olddir
}

## Run some external application in batch mode

proc ic_run_application_batch {dir progdir progname envname arguments \
		{ logfile "" } } {
    set olddir [pwd]
    if [catch {cd $dir} res] {
	    mess "Can't change directory: $res\n"
    }
    if [catch {
	    run_application_batch $progdir/$progname $envname $arguments $logfile
    } res] {
	    user_error $res
    }
    cd $olddir
    return $res
}

## Run some external application, given the full path

proc ic_run_application_exec {dir progdir progname arguments } {
    set olddir [pwd]
    if [catch {cd $dir} res] {
        mess "Can't change directory: $res\n"
    }
    if {$progdir == ""} {
        set app $progname
    } else {
        set app [get_program $progdir $progname]
    }
    if [catch {
        run_application_exec "\"$app\" $arguments"
    } res] {
        user_error $res
    }
    cd $olddir
    return $res
}

## A simplified version of this.

proc ic_exec {args} {
    global env batch_mode

    if [catch {eval exec $args} res] {
	    user_error $res
    } else {
        if {!$batch_mode && [ic_wb2_is_running] && [string match "*output-interfaces*" "$args"]} {
            if ![ic_wb2_input_parameter_mode] {
                ic_socket_send_to_wb2 "wb_status 7"
            }
        }
    }
    return $res
}

## Run an application ...

proc ic_run_application_direct {dir progdir progname envname arguments} {
    global env black_and_white use_xwindows is_win
    
    if $black_and_white { set bw -bw } else { set bw "" }
    switch $use_xwindows {
	0 { set x "" }
	1 { set x -x }
	2 { set x -ogl }
    }
    
    #set env($rootenv) $env(ICEM_ACN) JKA: in favor of:
    set env($envname) $env(ICEM_ACN)
    
    set command "$bw $x $dir $arguments"
    ic_run_application_command . $progdir $progname $command
}

set dont_record_command(ic_unique_id) 1

proc ic_unique_id { } {
	global ic_fp_unique_num
	if { ! [ info exists ic_fp_unique_num ] } { 
		set ic_fp_unique_num 1
	}
	set fp_ext ic_file$ic_fp_unique_num
	incr ic_fp_unique_num
	return $fp_ext
}

proc ic_open { filename read_write fp_ext } {
	global ic_file_descriptors 
	
	mess "ic_open $filename $read_write $fp_ext\n"
	set fp [ open $filename $read_write ]
	if [ info exists ic_file_descriptors($fp_ext) ] {
		error "that file descriptor is already in use"
	}
	set ic_file_descriptors($fp_ext) $fp
	return $fp_ext
}


proc ic_puts { fp_ext string } {
	global ic_file_descriptors


	mess "ic_puts $fp_ext $string\n"

	if { ! [ info exists ic_file_descriptors($fp_ext) ] } {
		error "no such file open $fp_ext"
	}
	set fp $ic_file_descriptors($fp_ext)

	return [ puts $fp $string ]
}

proc ic_close { fp_ext } {
	global ic_file_descriptors

	if { ! [ info exists ic_file_descriptors($fp_ext) ] } {
                error "no such file open $fp_ext"
        }

	set fp $ic_file_descriptors($fp_ext)
	unset ic_file_descriptors($fp_ext)

	return [ close $fp ]
}
proc ic_rm { args } {
	if {$args != ""} {
		catch {eval file delete -force -- \
			[ glob -nocomplain $args] } res]
    	}
}
proc ic_rm_r { file } {
	return [ cmd_rm_r $file ]
}
proc ic_mv { from to } {
	return [ cmd_mv $from $to ]
}
proc ic_gzip { args } {
	return [ eval cmd_gzip $args ]
}
proc ic_rename { old new } {
	return [ cmd_rename $old $new ]
}
proc ic_cp { old new } {
	return [ cmd_cp $old $new ]
}
proc ic_cp_r { old new } {
	return [ cmd_cp_r $old $new ]
}
proc ic_mkdir { dir } {
	return [ cmd_mkdir $dir ]
}

## Removes duplicates from list of <i>names</i>.

proc ic_remove_duplicate {names} {
    catch {unset count}
    foreach c $names {
        if [info exists count($c)] {
            incr count($c)
        } else {
            set count($c) 1
        }
    }
    set new_names ""
    foreach cn [array names count] {
        if {$count($cn) == 1} {
            lappend new_names $cn
        }
    }
    return $new_names
}

proc undo_debug {s} {
    return
    mess "UNDO_DEBUG: $s" red
}

## Undo the previous action

proc ic_undo {} {
    global undo_redo uns_cur str_cur
	set nothing_done 0
    if [info exists undo_redo] {
	busy 1
	if [ic_uns_is_loaded] {
	    start_new_elems
	}
	set result [$undo_redo apply_undo]
	if {[string first "Nothing to be" $result] > 0} {
		set nothing_done 1
	}		
	set msg ""
	foreach {t n s p v} $result {
	    set res [undo_tmp_delete_graphics $t $n $s $p $v]
	    if {$res != ""} {
		append msg $res \n
	    }
	}
	update_bsp_consistency
	foreach {t n s p v} $result {
	    set res [undo_geom_update_graphics $t $n $s $p $v]
	    if {$res != ""} {
		append msg $res \n
	    }
	}
	if ![get_etm_undo_option 0] {
	    mess "$msg" blue
	} elseif {[lindex $msg 0] != "Nothing"} {
	    mess "$msg" blue
	}
	if [ic_uns_is_loaded] {
	    finish_new_elems
	    $uns_cur update_map_deletes
	    $uns_cur reset_extrude_hash
	}
	if [ic_str_is_loaded] {
	   if [get_etm_undo_option 1] {
	       # for undo operations after smoothing
	       $str_cur restore_previous_nodes
	       $str_cur glb_sm_init
	       mess "Structured operation undone.\n" blue
	   }
	}
	busy 0
    }
    if [ic_uns_is_loaded] {
    	update_uns_available
    }
    return $nothing_done
}

## Redo the previous undone action

proc ic_redo {} {
    global undo_redo uns_cur str_cur
	set nothing_done 0
    if [info exists undo_redo] {
	busy 1
	if [ic_uns_is_loaded] {
	    start_new_elems
	}
	set result [$undo_redo apply_redo]
	if {[string first "Nothing to be" $result] > 0} {
		set nothing_done 1
	}		
	set msg ""
	foreach {t n s p v} $result {
	    set res [undo_tmp_delete_graphics $t $n $s $p $v]
	    if {$res != ""} {
		append msg $res \n
	    }
	}
	update_bsp_consistency
	foreach {t n s p v} $result {
	    set res [undo_geom_update_graphics $t $n $s $p $v]
	    if {$res != ""} {
		append msg $res \n
	    }
	}	
	mess $msg blue	

	if [ic_uns_is_loaded] {
	    finish_new_elems
	    $uns_cur update_map_deletes
	    $uns_cur reset_extrude_hash
	}
	busy 0
    }
    update_uns_available
    return $nothing_done
}

## Set Undo group begin 

proc ic_undo_group_begin { {text "undo_group"} } {
    global undo_redo

    if [info exists undo_redo] {
        $undo_redo undo_group_begin $text
        undo_debug "ic_undo_group_begin \"$text\"\n"
    }
}

## Set Undo group end

proc ic_undo_group_end { {text "undo_group"} } {
    global undo_redo

    if [info exists undo_redo] {
        $undo_redo undo_group_end $text
        undo_debug "ic_undo_group_end \"$text\"\n"
    }
}

## Suspend undo logging

proc ic_undo_suspend {} {
    global undo_redo

    if [info exists undo_redo] {
        $undo_redo suspend_undo
        undo_debug "ic_undo_suspend\n"
    }
}
set dont_record_command(ic_undo_suspend) 1

## state of undo manager
proc ic_undo_suspended {} {
    global undo_redo
 
    set state 1
    if [info exists undo_redo] {
        set state [$undo_redo suspended]
    }
    return $state
}
set dont_record_command(ic_undo_suspended) 1

## resume undo logging
proc ic_undo_resume {} {
    global undo_redo
    
    if [info exists undo_redo] {
        $undo_redo resume_undo
        undo_debug "ic_undo_resume\n"
    }
}
set dont_record_command(ic_undo_resume) 1

proc ic_undo_enable_largeop {val} {
    global undo_redo
 
    if [info exists undo_redo] {
        $undo_redo enable_largeop $val
        undo_debug "ic_undo_enable_largeop $val\n"
    }
}
set dont_record_command(ic_undo_enable_largeop) 1

proc ic_undo_logging {on} {
    if $on {
        ic_undo_start
        undo_debug "ic_undo_logging on\n"
    } else {
        ic_undo_stop
        undo_debug "ic_undo_logging off\n"
    }
}
set dont_record_command(ic_undo_logging) 1

## start undo handler; started by default

proc ic_undo_start {} {
    global undo_redo

    if ![info exists undo_redo] {
        set undo_redo [undo_handler]
        $undo_redo configure -update_cmd undo_redo_update
        undo_redo_update 0 0
        undo_debug "ic_undo_start\n"
    }
    $undo_redo start_undo
}
set dont_record_command(ic_undo_start) 1

## stop undo handler; removes undolog

proc ic_undo_stop {} {
    global undo_redo

    if ![info exists undo_redo] {
        set undo_redo [undo_handler]
        undo_debug "ic_undo_stop\n"
    }
    $undo_redo stop_undo
}
set dont_record_command(ic_undo_stop) 1

## clear undo events and restart undolog

proc ic_undo_clear {} {
    global undo_redo

    if [info exists undo_redo] {
        $undo_redo clear_undo
        undo_debug "ic_undo_clear\n"
    }
}
set dont_record_command(ic_undo_clear) 1

proc ic_save_model_for_undo {} {
    global projlib debug

    if {[info exists projlib] && $projlib != ""} {
        undo_debug "ic_save_model_for_undo\n"
        $projlib save_model_for_undo
    }
}
set dont_record_command(ic_save_model_for_undo) 1

## Tar and gzip the directory <em>dir</em> as <em>archive</em>

proc ic_archive_dir {dir archive} {
    
    set suff [file tail $dir]
    set archive1 [file rootname $archive]    
    mess "Running tar...\n"
    set here [pwd]
    cd [file dirname $dir]
    if [catch {
	cmd_tar -cf $archive1 $suff
	mess "Compressing with gzip ...\n"
	cmd_rm $archive
	cmd_gzip $archive1
    } res] { mess "$res\n" red }
    cd $here
    catch {exec ls -l $archive} ls
    mess "Done: $ls\n"
}

## Untar and gunzip the archive <em>file</em> in directory <em>dest</em>

proc ic_unarchive_file {file dest} {
    
    busy 1
    set dir [file dirname $dest]
    set here [pwd]
    cd $dir
    if [catch {
	mess "Uncompressing ...\n"
	set tmpdir tmpdir.[pid]
	ic_rm_r $tmpdir
	ic_mkdir $tmpdir
	cd $tmpdir
	ic_gzip -d < $file > tmp.tar
	mess "Untarring ...\n"
	cmd_tar -xf tmp.tar
	ic_rm tmp.tar
	set got [glob -nocomplain *]
	if {[llength $got] != 1} {
	    mess "Error: tar gave these files: $got\n" red
	    cd $here; busy 0; return
	}
	ic_mv [lindex $got 0] $dest
    } res] { mess "$res\n" red }
    cd $here
    ic_rm_r $tmpdir
    mess "Done.\n"
    busy 0
}

## Start a stopwatch, in milliseconds.

proc ic_stopwatch_start {} {
    global ic_stopwatch_start_time
    if [info exists ic_stopwatch_start_time] {
	mess "ic_stopwatch_start called with watch already started...reseting\n" red
	ic_stopwatch_end
    }
    set ic_stopwatch_start_time [clock clicks -milliseconds]
}

## Get the elapsed time, in milliseconds, since start of the stopwatch.
## Optional arg <em>stop_the_watch</em> will also stop the watch.

proc ic_stopwatch_get_elapsed {{stop_the_watch 0}} {
    global ic_stopwatch_start_time
    if ![info exists ic_stopwatch_start_time] {
	mess "ic_stopwatch_get_elapsed: no watch started\n" red
	return "undefined"
    }
    set elapsed [expr [clock clicks -milliseconds] - $ic_stopwatch_start_time]
    if $stop_the_watch { ic_stopwatch_end }
    return $elapsed
}

## Stop the current stopwatch.

proc ic_stopwatch_end {} {
    global ic_stopwatch_start_time
    if [info exists ic_stopwatch_start_time] { unset ic_stopwatch_start_time }
}

## Uniquify given given TCL list <em>list</em>. Note that this function returns
## the list sorted.

proc ic_list_uniquify {list} {
    return [lsort -unique $list] 
}

proc ic_plural {number} {
    if {$number == 1} {
        return ""
    }
    return "s"
}

## For every non-unique element in given TCL list <em>list</em>,
## remove all instances. Note that this function returns the list sorted.

proc ic_list_remove_duplicated {list} {
    
    set sorted_list [lsort $list]
    
    # foreach element in the list see if it is followed by duplicates
    set i 0
    while {$i < [llength $sorted_list]} {
	
	set ref [lindex $sorted_list $i]
	set j $i
	set next [lindex $sorted_list [expr $j + 1]]
	
	while [string equal $ref $next] {
	    incr j
	    set next [lindex $sorted_list [expr $j + 1]]
	    if ![string equal $ref $next] { break }
	}
	
	if {$j > $i} {
	    set sorted_list [lreplace $sorted_list $i $j]
	} else { incr i }
    }
    
    return $sorted_list
}
set dont_record_command(ic_list_remove_duplicated) 1

## This returns the duplicated items in a list 

proc ic_list_get_duplicated {list} {
    set list2 [ic_list_remove_duplicated $list]
    set ret_list ""
    foreach l $list {
	if {[lsearch $list2 $l] == -1} {lappend ret_list $l}
    }
    return $ret_list
}
set dont_record_command(ic_list_get_duplicated) 1

## Takes a list of groups and an original list and returns items in orig that are not in groups

proc ic_list_remove_from_grouped {groups orig} {
    set grouped "" 
    foreach l $groups {
	set grouped [concat $grouped $l]    
    }
    set free ""
    foreach s $orig {
	if {[lsearch $grouped $s] == -1} {lappend free $s}	
    }

    return $free
}
set dont_record_command(ic_list_remove_from_grouped) 1

## gets the median in the list

proc ic_list_median {list} {
    set list_length [llength $list]
    if !$list_length {return ""}
    set median_place [expr $list_length / 2]
    return [lindex $list $median_place]
}

#
#  Turn on floating point traps.  
#
#  This is a testing function that will cause MED to abort on
#  various floating point errors, e.g. divide by zero, overflow,
#  underflow.  Used for testing.  Currently implemented on 
#  Linux only.
#

proc ic_trap_fpe {} {
	gk_trap_fpe
}

## Change working directory

proc ic_chdir {dir} {
    cd $dir
}

## Check to see if ai*env licensing is enabled

proc ic_check_licensing_aienv {} {
    return [check_licensing_aienv]
}
set dont_record_command(ic_check_licensing_aienv) 1

## redefine graphics for geometry 

proc ic_reinit_geom_objects {{all ""}} {
    if {$all == "all"} {
        reinit_geom_objects
    } else {
        update_bsp_consistency
    }
}

proc ic_get_compile_date {} {

    set ret [get_compile_date]
    return $ret
}

proc ic_get_tglib_info {} {

    set ret [get_tglib_info]
    return $ret
}

proc ic_aienv_license_exit {} {
    aie_license_i_exit
}

proc ic_include_file {file} {
    if {[file exists $file] && ![file isdirectory] && [file isfile $file]} {
        source $file
    }
}

## For testing

proc ic_error {} { error "got it" }

# return metric order for the "Quality Metrics" DEZ
# or
# return all existing metrics (not ordered)

proc ic_diagnostic_info {{ordered 1}} {

    set metrics {
        "Quality"
        "Aspect ratio"
        "Aspect Ratio (Fluent)"
        "Custom quality"
        "Determinant"
        "Distortion"
        "Element stretch"
        "Equiangle Skewness"
        "Ford"
        "Hex. Face Aspect Ratio"
        "Hex. Face Distortion"
        "Max angle"
        "Min angle"
        "Max dihedral angle"
        "Max length"
        "Max ortho"
        "Min ortho"
        "Max orthogls"
        "Max ratio"
        "Max sector volume"
        "Min sector volume"
        "Max side"
        "Min side"
        "Min side (Quad Optimized)"
        "Max warp"
        "Max warpgls"
        "Mesh Distribution"
        "Mesh expansion factor"
        "Mid node"
        "Mid node Angle"
        "Opp. Face Area Ratio"
        "Opp. Face Parallelism"
        "Orientation"
        "Orthogonal Quality"
        "Prism thickness"
        "Quadratic dev"
        "Skew"
        "TGrid Skew"
        "Surface area"
        "Surface dev"
        "Taper"
        "Tetra Special"
        "Volume"
        "Volume change"
        "Volume/Area/Length"
        "Workbench Shape"
        "X size"
        "Y size"
        "Z size"
    }
    if $ordered {
        return $metrics
    } else {
        return [diagnostic_info]
    }
}

proc ic_win_shortname {pathname} {
    global is_win
    if {$is_win && [string first " " $pathname] >= 0 && [file exists $pathname]} {
        set shortname [file attributes $pathname -shortname]
        if {[string first " " $shortname] >= 0} {
            return [list $pathname]
        } else {
            return $shortname
        }
    }
    return $pathname
}

proc ic_set_icemcfd_idle {} {
    global batch_mode
    
    if $batch_mode return
    aie_set_global icem_cfd_idle 1
    set_anslic_client_idle
    aie_unset_global icem_cfd_idle 
}

proc ic_tb_dir {} {
    global env
    set p $env(TB_WORKING_DIRECTORY)
    regsub -all {\\} $p {/} p
    return $p
}

proc ic_version {{dot 1}} {

    set Version [ic_get_global Version]
    if {$Version != "___NA___"} {
        if $dot {
            return $Version
        } else {
            regsub -all {\.} $Version "" Version
            return $Version
        }
    }
    return ""
}
