
# Stuff to deal with the filesystem representation of jobs and libraries.
#
# Copyright (c) 1993, 1994 Pacific Marketing and Consulting
# Author:  Wayne A. Christopher, wayne@pmac.com
#          Pacific Marketing and Consulting, Berkeley, California
#

proc job_unload {clear_post clear_form {force 0} {cancel_forms 1}} {
    global tdv_default
    global job_title job_notes job_existing_name job_name
    global type_visible object_type_list no_exit_job ff_value creation_count
    global advanced_mesher_ok_warned_once job_version solve_id
    global new_material_cache batch_mode already_warned_tol
    global named_point report_summary report_point is_iceboard
    global hardcopy_auto_dirname animate_auto_dirname
    
    if [info exists no_exit_job] {
	set mess "Warning: the $no_exit_job is currently running. \
		If you change projects now there will be trouble.  Do it anyway?"
	if ![tk_dialog .busy Busy $mess "" 0 No Yes] { return 0 }
    }
    
    if {!$force && [db_check_dirty model]} {
	set message "Current project has been modified --\
                             save before switching projects?"
	switch [tk_dialog .confirm Confirm $message "" 0 "Save" \
		    "Don't save" "Cancel switch"] {
			0 { file_save 1 "" }
			2 { return 0 }
		    }
    }
    
    model_set_current ""
    grid_clear full

    catch {unset advanced_mesher_ok_warned_once}

    set p [info commands app_job_unload]
    if {$p != ""} { $p $clear_post $clear_form }

    if !$batch_mode {
	$tdv_default delete_with_tag cad_line
	$tdv_default delete_with_tag cad_point
	tdv_clear_user_views
	tdv_changebg current black
    }

    db_reinit_model
    cad_clear 0
    tree_clear_subtree model
    tree_clear_subtree groups
    if !$is_iceboard {
	tree_clear_subtree named_point_container
    }
    tree_clear_clipboard
    foreach t "$object_type_list part" { set type_visible($t) 1 }

    undo_reset
    if $cancel_forms {
	form_cancel_all {.report_write .report_summary .report_overview* .report_summary* .solve_zoomin .report_point .html_report .optimization_output .monitor .pmonitor*}
    }
    set job_name ""
    set job_version ""
    set job_title ""
    set job_notes ""
    catch {unset creation_count}
    catch {unset new_material_cache}

    foreach i {
	params param_trials param_list param_choices cur_trials
	trial_restartid trial_name
    } {
	global expression_$i
	catch {unset expression_$i}
    }
    global expression_mode
    set expression_mode all
    catch { reset_uns_mon_vars }
    catch {unset already_warned_tol}
    
    foreach v {opt_function opt_design_var} {
	global $v
	catch {unset $v}
    }
    
    set hardcopy_auto_dirname ""
    set animate_auto_dirname ""
    
    return 1
}

proc job_switch_version {vers clear_post clear_form {force 0}} {
    global job_name job_version project_dir tdv_default
    global batch_mode report_summary report_point opt_design_var opt_function

    if {$job_version == $vers} {
	#mess "Version is already $vers -- not switching\n"
	return 1
    }

    set suff ""; if {$vers != ""} { set suff $vers. }
    if ![file exists [directory]/${suff}model] {
	mess "Can't switch to version $vers - ${suff}model file not found\n" red
	return 0
    }
    set old_sum [array get report_summary]
    set old_pt [array get report_point]
    set saved_opt [array get opt_design_var]
    set saved_optf [array get opt_function]
    
    set jn [directory]
    if ![job_unload $clear_post $clear_form $force 0] {
	mess "Cancelled switch version\n"
	return 0
    }
    set job_version $vers
    set job_name $jn
    if {!$batch_mode} {$tdv_default configure -active 0}

    db_dirty disable

    busy 1
    if ![job_load_files] { busy 0; return 0 }
    busy 0
    if {$vers != ""} {
	mess "Switched to version $vers\n"
    } else {
	mess "Switched to current version\n"
    }
    update_title
    model_set_current [lindex [db_list_objects domain] 0]
    if {!$batch_mode} {$tdv_default configure -active 1}
    if {!$batch_mode} {$tdv_default redraw}
    tdv_reset_user_views
    array set report_summary $old_sum
    array set report_point $old_pt
    array set opt_design_var $saved_opt
    array set opt_function $saved_optf
    
    global tool_name solve_solver
    if {$tool_name == "IcePak"} { set solve_solver uns }
    named_point_setup
    
    set project_dir $job_name ;# used by some code shared with med
    
    if {[info commands app_after_switch_version] != ""} { app_after_switch_version }
    
    db_dirty off

    return 1
}

proc job_load {jn version} {
    global tdv_default tar_delim
    global job_title job_notes job_name job_existing_name
    global solve_id global_pref_file global_def_file batch_mode job_version
    global autohex_root domain job_listsort type_name project_dir
    global tdv_home_direction job_home_direction job_precision
    global graph_fancy log_messages library_path
    global message_save_directory type_visible
    global server_host html_rept solve_zoomin
    global tdv_mouse_bindings_autohex_names

    if ![job_name_is_valid $jn] { return 0 }

    if {[string first $tar_delim $jn] > 0} {
        set tar [split $jn $tar_delim]
        if {[file exists [lindex $tar 0]] &&
            [tarfile_extract [lindex $tar 0] "[lindex $tar 1]/*"]} {
            set jn [file dirname [lindex $tar 0]]/[lindex $tar 1]
        }
    }

    # Use FORCE because we were already asked once
    if ![job_unload 1 1 1] {
	mess "Cancelled load project\n"
	return 0
    }

    # This has to get dealt with specially
    form_kill .html_report
    catch {unset html_rept}
    form_kill .solve_zoomin
    catch {unset solve_zoomin}

    set job_name $jn
    set job_version $version
    set project_dir $job_name ;# used by some code shared with med
    set message_save_directory [directory]

    set olibpath $library_path
    db_dirty disable

    if !$batch_mode { $tdv_default configure -active 0 }
    set jd [directory]
    if {[url_file_exists $jd/model] || [url_file_exists $jd/geometry]} {
	busy 1
	if ![job_load_files] { busy 0; return 0 }
	busy 0
	if {$domain == ""} {
	    # No luck
	    return 0
	}
    } else {
	mess "Creating new project\n"
	reset_default_param_values
	regsub -all \\\\ $global_pref_file / cfile_pref
	regsub -all \\\\ $global_def_file  / cfile_def

	if [file exists $global_pref_file] {
	    uplevel \#0 source \"$cfile_pref\"
	}

	if [file exists $global_def_file] {
	    uplevel \#0 source \"$cfile_def\"
	} else {
	    if [file isdirectory $cfile_def] {
		mess "$cfile is a directory!"
	    } else {               # Just create an empty placeholder.
		if [catch {open $cfile_def w} file_id] {
		    mess "Cannot open $cfile_def: $file_id"
		} else {
		    close $file_id
		}
	    }
	}

	catch {cmd_mkdir $jd}
	global gmax_in_def_units
	set gmax_in_def_units 1
	unit_update_shape_length_scale
	if {[info commands initialize_problem_data] != ""} {
	    initialize_problem_data
	}
	tdv_dynamics_bindings $tdv_default
	if [info exists tdv_mouse_bindings_autohex_names] {
	    tdv_selection_bindings $tdv_default
	}
	if {!$batch_mode && ($library_path != $olibpath)} {
	    tree_make_library_subtree ;# this may have changed above
	}
	if {[info commands app_after_new_project] != ""} {
	    app_after_new_project
	}
    }
    #puts "here1 [exec date]"
    if {$domain == ""} {
	set domain [edit_new domain $type_name(domain).1]
    }

    set job_precision 0

    update_title
#    update_mtype
    if !$batch_mode {
	graph_set_ctrlkey
	set tdv_home_direction($tdv_default) $job_home_direction
	tdv_home $tdv_default
	tdv_reset_user_views
	model_set_current [lindex [db_list_objects domain] 0]
	$tdv_default configure -active 1
	# in case non-standard lighting has been set
	tdv_lighting_params		
	$tdv_default redraw

	set log_messages 1
	message_log_close
	cmd_rm [directory]/messages.log
	message_log_reopen [directory]/messages.log 1
    }

    if {[info commands app_after_load] != ""} { app_after_load }

    db_dirty off
    if !$batch_mode {
	tree_single_click model
    }
    mess "Done loading.\n"
    #puts "here2 [exec date]"
    return 1
}

proc job_name_is_valid {jn} {
    global is_win
    if {!$is_win && [string match *\\\\* $jn]} {
	user_error "On UNIX job names can't have \\ in them."
	return 0
    }
    if {($jn == ".") || ($jn == "..")} {
	user_error "The job name can't be \"$jn\""
	return 0
    }
    return 1
}

proc job_load_files {} {
    global tdv_default meshing_units unit_default
    global job_title job_notes job_name job_existing_name
    global solve_id global_def_file global_pref_file batch_mode job_version
    global autohex_root domain job_listsort type_name
    global tdv_home_direction job_home_direction problem_units
    global old_fan_curves old_heat_tr_coeffs gmax_in_def_units
    global graph_fancy graph_color env open_job_override_prefs
    global job_ttol job_ttol_units opt_design_var
    
    catch {unset old_fan_curves}
    catch {unset old_heat_tr_coeffs}
    catch {unset gmax_in_def_units}
    
    if {$job_version == ""} {
	set pref ""
	set saved_opt ""
    } else {
	set pref $job_version.
	set saved_opt [array get opt_design_var]
    }

    reset_default_param_values

    set jd [directory]
    if !$batch_mode { $tdv_default configure -active 0 }

    url_source $jd/job 0
    #if ![url_source $jd/job 0] { return 0 }

    # Set any defaults that might be required.  Most of these will be
    # overwritten by what's in the problem file but it can't hurt to load them
    if [file exists $global_def_file] {
	regsub -all \\\\ $global_def_file / cfile
	uplevel \#0 source \"$cfile\"
    }

    array set save_pu [array get problem_units]
    catch {unset problem_units}

    unset meshing_units  ;# catch the 3.2 unit behavior
    if [url_source $jd/${pref}problem 0] {
	fix_problem_units
	if ![info exists gmax_in_def_units] {
	    set un [unit_get_default_choice length]
	    foreach n {gmax_i gmax_j gmax_k gmin_i gmin_j gmin_k} {
		global grid_$n
		set grid_$n [unit_convert [set grid_$n] $un 1]
	    }
	    set gmax_in_def_units 1
	}
	unit_update_shape_length_scale
	set make_libsubtree 1
    } else {
	array set problem_units [array get save_pu]
	set make_libsubtree 0
    }
    if ![info exists meshing_units] {
	set meshing_units $unit_default(length)
    }
    
    if {$saved_opt != ""} {
	# If we're reloading different versions during optimization we don't want to trash
	# the intermediate values
	array set opt_design_var $saved_opt
    }
    
    if !$open_job_override_prefs {
	# We want values in the "all jobs" category to overwrite anything
	# that was for "this job" only.  This applies only to preferences
	# not defaults.
	if [file exists $global_pref_file] {
	    regsub -all \\\\ $global_pref_file / cfile
	    uplevel \#0 source \"$cfile\"
	}
    }

    if $make_libsubtree {
	# This has to get done before the model file is read but after
	# the correct library path is determined
	tree_make_library_subtree
    }
    
    # This is to correct a bug that got into .icepak_config_files
    foreach t {heatsink enclosure} {
	if [info exists graph_fancy($t)] { set graph_fancy($t) "" }
    }

    if 0 {
	# this is not good
	if [file exists $jd/${pref}tetin] {
	    # Should do this before loading the model file so that cad objects
	    # can get their geometry
	    auto_load_projlib $jd/${pref}tetin 0 1
	}
    }

    if {![model_read $jd/${pref}model 1 1] && ![model_read $jd/geometry 1 1]} {
	#user_error "No model or geometry file with version $job_version"
	$tdv_default configure -active 1
	$tdv_default redraw
	return 0
    }

    cad_reload_unused
    update_all_decorations
    
    set anno $jd/${pref}annotations
    if [file exists $anno] {
	if [catch {uplevel \#0 source $anno} mess] {
	    mess $mess\n red
	}
    }
    
    if !$batch_mode {
	$tdv_default configure -active 1
	$tdv_default redraw
        tdv_dynamics_bindings $tdv_default
        tdv_selection_bindings $tdv_default
    }

    if {$job_listsort == "prec"} { set job_listsort creation_order }
    
    if [info exists job_ttol] {
	foreach i {x y z} {
	    global grid_sep_$i grid_sep_${i}_units
	    set grid_sep_$i $job_ttol
	    set grid_sep_${i}_units $job_ttol_units
	}
	unset job_ttol
	unset job_ttol_units
    }
    
    return 1
    
    #puts "tree1 [exec date]"

    #puts "after:load [exec date]"
}

proc save_default_param_values {} {
    global saved_default_param_values

    foreach {ptype pref} {
	problem problem_ solve solve_ uns uns_
	config job_ grid grid_ other ""
    } {
	global ${ptype}_params
	if [info exists ${ptype}_params] {
	    foreach l [set ${ptype}_params] {
		set n ${pref}$l
		global $n
		if ![info exists $n] continue
		if {[array names $n] != ""} {
		    foreach v [array names $n] {
			set nv ${n}($v)
			if ![info exists saved_default_param_values($nv)] {
			    set saved_default_param_values($nv) [set $nv]
			}
		    }
		} else {
		    if ![info exists saved_default_param_values($n)] {
			set saved_default_param_values($n) [set $n]
		    }
		}
	    }
	}
    }
}

proc reset_default_param_values {} {
    global saved_default_param_values
    foreach n [array names saved_default_param_values] {
	uplevel \#0 set $n \{$saved_default_param_values($n)\}
    }
}

proc update_title {} {
    global whoami version job_name job_title job_version job_title_string

    if {$job_title != ""} { set jt " ($job_title)" } else { set jt "" }
    if {$job_version != ""} { set jv "; version $job_version" } else { set jv "" }
    set job_title_string "[file tail $job_name]$jt$jv"
    set_title "$whoami $version : $job_title_string"
}

proc job_save {dir version {part ""}} {
    global job_params problem_params job_name server_host

    # This is an annoying hack.
    if {[directory] != $job_name} {
	set dir $dir/autohex
    }

    # Don't actually remove these files until you save a dirty job
    if {($version == "") && [db_check_dirty mesh]} {
	foreach f {grid_output grid_mapping mesh_timestamp} {
	    if [file exists [directory]/$f] {
		cmd_rm [directory]/$f
	    }
	}
    }

    if {$version != ""} { set version $version. }
    #set jobf $dir/${version}job
    set jobf $dir/job
    set probf $dir/${version}problem
    set modf $dir/${version}model
    set tetinf $dir/${version}tetin
    set bocof $dir/${version}boco
    if ![file exists $bocof] { set bocof "" }

    catch {cmd_mkdir $dir}

    if ![write_job_file $jobf] {
	lpopup "Project not saved"
	return
    }
    if [info exists problem_params] {
	if ![write_problem_file $probf] {
	    lpopup "Project not saved"
	    return
	}
    }
    
    if [catch {open $modf w} fp] {
	user_error $fp
	lpopup "Project not saved"
	return
    }
    set objects ""
    if {$part != ""} {
	set need_domain 1
	foreach obj [$part list_contents creation_order int] {
	    lappend objects $obj
	    if {[$obj getval obtype] == "domain"} { set need_domain 0 }
	}
	if $need_domain { set objects "domain $objects" }

	# We also want to save the custom materials.
	foreach mat [db_list_objects material] {
	    if {[$mat getval mat_lib_path ""] == ""} {
		lappend objects $mat
	    }
	}
    }
    
    model_write $fp $objects
    close $fp
    
    annotation_save $dir/${version}annotations
    
    cad_save_unused

    if [file exists $dir/geometry] {
	mess "Moved geometry file to geometry.old (data is now stored in model)\n"
	cmd_rename $dir/geometry $dir/geometry.old
    }

    set gprev 0
    set gtfile $dir/${version}mesh_timestamp
    if [file exists $gtfile] {
	set fp [open $gtfile r]
	set gprev [gets $fp]
	close $fp
    }

    set mtfile $dir/${version}model_timestamp
    set fp [open $mtfile w]
    puts $fp [abs_time_string]
    close $fp

    if {$gprev && ($gprev > [db_check_dirty mesh])} {
	set fp [open $gtfile w]
	puts $fp [expr {[abs_time_string] + 1}]
	close $fp
    }
    if {$server_host != ""} {
	server_write_job $dir [directory] current "" \
	    "model job problem tetin_unused"
    }
}

proc write_job_file {file} {
    global job_params
    
    if [catch {open $file w} fp] {
	user_error $fp
	return 0
    }
    foreach p $job_params {
	global job_$p
	puts $fp [list set job_$p [set job_$p]]
    }
    close $fp
    return 1
}

proc write_problem_file {file} {
    global problem_params solve_params grid_params grid_mesher_params
    global config_params config_default_params
    global graph_params other_params uns_params uns_mon_units
    global library_path is_airpak env batch_mode
    
    if {[info exists is_airpak] && $is_airpak} {
	set root $env(AIRPAK_ROOT)
	set var AIRPAK_ROOT
    } elseif {[info exists env(ICEPAK_ROOT)]} {
	set root $env(ICEPAK_ROOT)
	set var ICEPAK_ROOT
    } else {
	set root $env(AUTOHEX_ROOT)
	set var AUTOHEX_ROOT
    }
    regsub -all \\\\  $root / root
    if ![string match */ $root] { append root / }
    set olib $library_path
    set library_path ""
    foreach lib $olib {
	if [string match $root* $lib] {
	    set lib \$$var/[string range $lib [string length $root] end]
	}
	if ![info exists got($lib)] {
	    lappend library_path $lib
	}
	set got($lib) 1
    }

    if [catch {open $file w} fp] {
	user_error $fp
	return 0
    }
    foreach p [concat $config_params $config_default_params] {
	write_problem_param $fp job_$p
    }
    foreach p $problem_params { write_problem_param $fp problem_$p }
    foreach p $grid_params    { write_problem_param $fp grid_$p }
    foreach p $solve_params   { write_problem_param $fp solve_$p }
    foreach p $uns_params     { write_problem_param $fp uns_$p }
    foreach p $graph_params   { write_problem_param $fp graph_$p }
    foreach p $other_params   { write_problem_param $fp $p }
    
    # This should not be here -- it should be in icepak somewhere
    for {set i 1} {$i <= 8} {incr i} {
	global uns_mon_pt$i uns_mon_loc$i uns_mon_var$i
	if {[info exists uns_mon_pt$i] && [set uns_mon_pt$i]} {
	    puts $fp [list set uns_mon_pt$i 1]
	    puts $fp [list set uns_mon_loc$i [set uns_mon_loc$i]]
	    puts $fp [list set uns_mon_var$i [set uns_mon_var$i]]
	}
    }
    if [info exists uns_mon_units] {
	puts $fp [list set uns_mon_units $uns_mon_units]
    }
    if {!$batch_mode} {
	puts $fp "catch \{tdv_changebg current \{[tdv_getbg current]\}\}"
    }
    close $fp
    
    set library_path $olib
    return 1
}

proc write_problem_param {fp what} {
    global $what

    if ![info exists $what] return
    
    if [array exists $what] {
	puts $fp "array set $what {"
	foreach n [array names $what] {
	    puts $fp "    [list $n [set ${what}($n)]]"
	}
	puts $fp "}"
    } else {
	puts $fp [list set $what [set $what]]
    }
}

proc fix_problem_units {} {
    global problem_units library_path
    global unit_choices unit_data
    global preset_unit_choices preset_unit_data
    global unit_default_si unit_default_english unit_default
    
    set was_eng 0
    if [info exists problem_units] {
	switch $problem_units {
	    metric - SI {
		array set unit_default [array get unit_default_si]
		mess "Problem units in 2.2 project were set to SI\n"
	    }
	    english - English {
		array set unit_default [array get unit_default_english]
		mess "Problem units in 2.2 project were set to English\n"
		set was_eng 1
	    }
	}
	unset problem_units
    }
    
    foreach t [array names preset_unit_choices] {
	if ![info exists unit_choices($t)] {
	    set unit_choices($t) $preset_unit_choices($t)
	} else {
	    foreach c $preset_unit_choices($t) {
		if ![lmember $unit_choices($t) $c] {
		    lappend unit_choices($t) $c
		}
	    }
	}
    }
    foreach t [array names preset_unit_data] {
	set unit_data($t) $preset_unit_data($t)
    }
    if {[info commands app_fix_problem_units] != ""} {
	app_fix_problem_units $was_eng
    }
}

proc process_exists {pid} {
    set ps [get_path ps 1]
    if {$ps == ""} { return 1 }
    return [expr ![catch {exec $ps -p $pid}]]
}

proc read_array_from_problem_file {file array} {
    if [file exists $file] {
	source $file
    }
    return [array get $array]
}
	    
proc read_variable_from_problem_file {file var} {
    if [file exists $file] {
	source $file
    }
    if [info exists $var] {
	return [set $var]
    } else {
	return ""
    }
}
