
# Stuff for replay.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com

proc replay_start_recording {} {
    global command_hook after_command_hook replay_count replay_current
    global replay_do_all replay_internal_editor 
       
    if ![info exists replay_count] { set replay_count 0 }
    if ![info exists replay_current] { set replay_current 0 }
    if ![info exists replay_do_all] { set replay_do_all 0 }
    
    set command_hook replay_record_command
    set after_command_hook replay_record_after_command
    mess "Started recording commands.\n"
    if {[info exists replay_internal_editor] && $replay_internal_editor} { replay_toggle_edit_mode 0 }
}

proc replay_stop_recording {} {
    global command_hook after_command_hook replay_internal_editor
    
    unset command_hook
    unset after_command_hook
    mess "Stopped recording commands.\n"
    if {[info exists replay_internal_editor] && $replay_internal_editor} { replay_toggle_edit_mode 1 }
}

proc replay_before_quit {} {
    global command_hook
    
    if ![info exists command_hook] return
    replay_save
}

proc replay_toggle_recording {} {
    global replay_recording
    if $replay_recording {
        replay_start_recording
    } else {
        replay_stop_recording
    }
}

proc replay_strip {line} {
    regexp {[0-9]+\.[ 	]+(.*)$} $line dummy line
    return $line
}

proc replay_linenumber_of {line} {
    if [regexp {(^[0-9]+)\.} $line dummy num] {
        return $num
    } else {
        return ""
    }
}

proc replay_record_command {com} {
    global replay_current replay_listbox replay_commands
    global replay_count command_hook replay_dont_record
    global replay_logfile_fp replay_handle_undo replay_file replay_do_all
    global logfile_dont_record
    
    regsub -all \n $com \\n com
    
    if {[info exists replay_logfile_fp] && ![info exists logfile_dont_record]} {
        puts $replay_logfile_fp $com
        flush $replay_logfile_fp
    }
    if {![info exists command_hook] || [info exists replay_dont_record]} return
    if {!$replay_do_all && ![replay_filter $com]} return

    if { [info exists replay_handle_undo] && $replay_handle_undo } {
        if {$replay_current == $replay_count} {
	        switch -- [string tolower $com] {
		        undo {
		            if [info exists replay_commands($replay_count)] {
			            incr replay_count -1
			            incr replay_current -1
			            replay_list_reset
		            }
		            return
		        }
		        redo {
		            set nc [expr $replay_count + 1]
		            if [info exists replay_commands($nc)] {
			            set replay_count $nc
			            set replay_current $nc
			            replay_list_reset
		            }
		            return
		        }
	        }
	    }
    }
    
    if {[lindex $com 0] == "replay_put"} {
	    set com [lrange $com 1 end]
    }
    if {$replay_current < $replay_count} {
	    incr replay_current
	    replay_insert_before
	    replay_renumber 1
    } else {
	    if {$replay_current > $replay_count} {
	        set replay_current $replay_count
	    }
        incr replay_count
	    incr replay_current
	
	    # Get rid of any undone commands that have been superceded.
	    for {set i [expr $replay_count + 1]} {[info exists replay_commands($i)]} {incr i} {
		    unset replay_commands($i)
	    }
    }
    set replay_commands($replay_current) $com
    replay_set_number $replay_current
    replay_list_setvals $replay_current
    replay_list_select
    replay_dirty
}

proc replay_record_after_command {com} {
    global replay_has_result_func 
    
    set cmd [lindex $com 0]
    if ![info exists replay_has_result_func($cmd)] return
    set res [${cmd}_replay_result]
    foreach r [split $res \n] {
	    set r [string trim $r]
	    if {$r != ""} {
	        replay_record_command [concat replay_put $r]
	    }
    }
}

proc replay_gui_is_running {} {
    foreach v "replay_standalone_mode replay_icem_mode replay_wb_mode" {
        if {[aie_get_global $v] != "___NA___"} {
            return $v
        }
    }
    return ""
}

proc replay_form {extras {xscroll 0} {wb_mode 0}} {
    global options replay_listbox replay_recording wb_initProjName replay_internal_editor replay_main_box

    if {$wb_mode && [aie_wb2_is_running]} {
        set replay_header "Replay Control in Workbench 2.0 Framework"
        aie_set_global replay_wb_mode 1
    } else {
        set replay_header "Replay Control"
        if [aie_wb2_is_running] {
            aie_set_global replay_icem_mode 1
            mess "Note that it is recommended to use the \"Replay Control in Workbench 2.0 Framework\" in case that workbench input/output parameters exist\n" red
        } else {
            aie_set_global replay_standalone_mode 1
        }
    }
    
    set replay_internal_editor $options(replay_internal_editor)
    set d [form_init .replay_ops "$replay_header" "" {{Done replay_done}} "" 2]
    if {$d != ""} {
        set replay_main_box $d
        if $replay_internal_editor {
	        form_listbox $d.list "Record mode" "" "replay_list_set_select" "replay_doit" 15x15 {0 0 -cols -} "" 1 0 0 $xscroll
	    } else {
	        form_listbox $d.list "Operations in script" "" "replay_list_set_select" "replay_doit " 15x15 {0 0 -cols -} "" 1 0 0 $xscroll
	    }
	    set replay_listbox $d.list
	    form_checkbutton $d.recording "Record (after current)" replay_recording {1 0 -cols 2}
	    $d.recording configure -command replay_toggle_recording
	    form_checkbutton $d.all "All commands" replay_do_all {1 2 -cols 2} replay_recording
	
	    form_button $d.doit "Do one" "replay_doit_cur" {2 0 -fill x}
	    form_button $d.doall "Do all" "replay_doit_all" {2 1 -fill x}
	    form_button $d.dorange "Do range" "replay_doit_range" {2 2 -fill x}
	    form_button $d.skip "Skip" "replay_skip_cur" {2 3 -fill x}
	
	    if {[aie_wb2_is_running] && [aie_get_global replay_wb_mode] != "___NA___"} {
	        if [file exists $wb_initProjName.rpl] {
	            form_button $d.load "Load" "replay_load $wb_initProjName.rpl" {3 0 -fill x}
	        } else {
	            form_button $d.load "Load" "replay_load" {3 0 -fill x}
	        }
            form_button $d.save "Save" "replay_save $wb_initProjName.rpl" {3 1 -fill x}
	    } else {
	        form_button $d.load "Load" "replay_load" {3 0 -fill x}
	        form_button $d.save "Save" "replay_save" {3 1 -fill x}
	    }
	    
	    form_button $d.edit "Edit" "replay_edit" {3 2 -fill x}
	    form_button $d.ins "Insert" "replay_insert_before" {3 3 -fill x}

	    form_button $d.del "Delete one" "replay_delete" {4 0 -fill x}
	    form_button $d.clr "Delete all" "replay_clear" {4 1 -fill x}
	    form_button $d.delr "Delete range" "replay_delete_range" {4 2 -fill x }
	    form_button $d.renf "Renumber" "replay_renumber 1; replay_list_reset" {4 3 -fill x}

	    form_checkbutton $d.update "Always update" replay_always_update {5 0 -cols 1}
	    form_checkbutton $d.ignore "Ignore errors" replay_ignore_errors {5 1 -cols 1}
	    form_button $d.stop "Stop" "replay_stop" {5 2 -fill x }
	    form_button $d.clean "Clean" "replay_clean" {5 3 -fill x }
	
	    foreach e $extras {
	        form_[lindex $e 0] $d.[lindex $e 1] [lindex $e 2] [lindex $e 3] [lindex $e 4]
	    }
        if $replay_internal_editor {
            foreach item "file_replay file_tool_replay edit edit_tool" {
                form_text_editor_create_menu $replay_main_box.editor [winfo parent $replay_main_box] $item disabled
	        }
	    }
	    
	    foreach c {0 1 2 3} {
	        grid columnconfigure $d $c -weight 1000
	    }
	    form_finish bot
	    bind .replay_ops <Destroy> replay_done
    }
    
    set replay_recording 1
    replay_start_recording

    return $d
}

proc replay_toggle_edit_mode {mode} {
    global replay_listbox replay_editbox replay_main_box replay_grid_listbox
    global replay_count replay_commands replay_current replay_temp_file
    global form_text_editor_linenumber

    if {[info exists replay_temp_file] && [file exists $replay_temp_file]} {
        set file $replay_temp_file
    } else {
        set file [tmp_filename]
        set replay_temp_file $file
    }
    
    set main [winfo parent $replay_main_box]
    if $mode {
        set state1 disabled
        set state2 normal
        if ![info exists replay_editbox] {
            set replay_grid_listbox [grid info $replay_listbox]
            form_text_editor $replay_main_box.editor $main "Edit mode" "" "0 0 -cols -" "" 15x15 ""
            set replay_editbox $replay_main_box.editor
            form_text_editor_trace_linenumber create
        }
        grid forget $replay_listbox
        eval grid $replay_editbox $replay_grid_listbox
	    foreach c {0 1 2 3} {
	        grid columnconfigure $replay_main_box $c -weight 1000
	    }
		$replay_editbox.txt delete 1.0 end
		form_text_editor_trace_linenumber delete
        for {set i 1} {$i <= $replay_count} {incr i} {
		    $replay_editbox.txt insert end "[replay_strip $replay_commands($i)]\n"
		}
        set num ""
        if [info exists replay_commands($replay_current)] {
    	    set num [replay_linenumber_of $replay_commands($replay_current)]
        }
        if {$num == ""} { set num 0 } 
        $replay_editbox.txt yview moveto [lindex [$replay_listbox.list yview] 0]
	    $replay_editbox.txt mark set insert $num.0
	    $replay_editbox.txt edit reset
	    form_text_editor_set_linenumber
	    focus $replay_editbox.txt
    } else {
        set state1 normal
        set state2 disabled
        if [winfo exists .text_search] {
            destroy .text_search
        }
        if [winfo exists .text_replace] {
            destroy .text_replace
        }
        if ![info exists replay_editbox] return
        form_text_editor_trace_linenumber delete
        set num [expr [lindex [split [$replay_editbox.txt index insert] .] 0] - 1]
        if {$num > $replay_count} {
            set num $replay_count
        }
		set data [$replay_editbox.txt get 1.0 end]
		set fp [open $file w]
		puts $fp $data
		close $fp
        grid forget $replay_editbox
        eval grid $replay_listbox $replay_grid_listbox
        replay_load $file
	    replay_renumber 1
	    replay_list_reset
	    replay_list_set_select $num
	    replay_list_select
    }
    foreach e "0 1" {
        $main.mbar.file entryconfigure $e -state $state2
        $main.tool.bbox1 itemconfigure $e -state $state2
    }
    foreach e "0 1 3 4 5 7 8" {
        $main.mbar.edit entryconfigure $e -state $state2
    }
    foreach e "0 1 2 3 4" {
        $main.tool.bbox2 itemconfigure $e -state $state2
    }
# doit doall dorange skip update ignore
	foreach n "del clr delr renf stop clean load save edit ins" {
	    $replay_main_box.$n configure -state $state1
	}
}

proc replay_update_editbox {} {
    global replay_listbox replay_editbox replay_commands replay_count
        
    if {![info exists replay_editbox] || ![winfo exists $replay_editbox]} return
    
    $replay_editbox.txt delete 1.0 end
    for {set i 1} {$i <= $replay_count} {incr i} {
		$replay_editbox.txt insert end "[replay_strip $replay_commands($i)]\n"
    }
}

proc replay_start_editor {file num} {
    global env AppName Version replay_editor

    if {[info exists replay_editor] && [winfo exists $replay_editor]} {
        ::AIEnv::GUIManagement::Widgets::TextEditor::Open replayEditor "$file" 1
	    if {$num > 1} {
	        $replay_editor.sw.txt yview scroll [expr $num - 1] units
	    }
	    raise $replay_editor
        return
    }
    set Editor [::AIEnv::GUIManagement::Widgets::TextEditor::TextEditor replayEditor]
    $Editor create "editable" "$AppName $Version Replay Control Editor"
    ::AIEnv::GUIManagement::Widgets::TextEditor::Open $Editor "$file" 1
	set replay_editor .${Editor}-txted
	if {$num > 1} {
	    $replay_editor.sw.txt yview scroll [expr $num - 1] units
	}
	wm geometry $replay_editor -0+0
}

proc replay_stop {} {
	global replay_interupt
	set replay_interupt 1
}

proc replay_done {} {
    global replay_dirty form_done replay_recording wb_initProjName replay_editor replay_temp_file
 
    if [info exists replay_dirty] {
        if {[aie_wb2_is_running] && [aie_get_global replay_wb_mode] != "___NA___"} {
	        if {[tk_dialog .quest_saveing "Query" "Saving replay file $wb_initProjName.rpl?" ""  0 "Yes" "No" ] == 0} {
		        replay_save $wb_initProjName.rpl
	        }
        } else {
            replay_save
        }
    }
    catch { unset replay_dirty }
    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_unset_global replay_wb_mode
            if [ic_wb2_input_parameter_mode] {
                aie_unset_global wb_input_parameter_mode
            }
        }
        if {[aie_get_global replay_icem_mode] != "___NA___"} {
            aie_unset_global replay_icem_mode
        }
    } else {
        if {[aie_get_global replay_standalone_mode] != "___NA___"} {
            aie_unset_global replay_standalone_mode
        }
    }
    if ![winfo exists .replay_ops] return
    
    form_done .replay_ops
    set form_done_flag(.replay_ops) 1
    if $replay_recording {
        set replay_recording 0
        replay_stop_recording
    }
    if {[info exists replay_editor] && [winfo exists $replay_editor]} {
        destroy $replay_editor
        unset replay_editor
    }
    if [info exists replay_temp_file] {
        unset replay_temp_file
    }
    if [winfo exists .text_search] {
        destroy .text_search
    }
    if [winfo exists .text_replace] {
        destroy .text_replace
    }
}

proc replay_dirty {} {
    global replay_dirty
    set replay_dirty 1
}

proc replay_batch {file} {
    global replay_current
    
    replay_load $file
    set replay_current 1
    replay_doit_all
}

# returns 0 if it couldn't execute the command
# returns 1 for okay
proc replay_doit {args} {
    global replay_commands replay_count replay_listbox replay_current
    global replay_dont_record replay_always_update replay_mess_prefix
    global replay_editbox replay_internal_editor

    if {![info exists replay_commands($replay_current)] || [info exists replay_dont_record]} { 
	    if ![info exists replay_commands($replay_current)] {
		    mess "replay_commands($replay_current) doesn't exist\n"
	    } else {
		    mess "replay_dont_record exists\n"
	    }
	    return 0 
    }
     
    set replay_dont_record 1
    set replay_mess_prefix [replay_linenumber_of $replay_commands($replay_current)]
    set cmd [replay_strip $replay_commands($replay_current)]
    if {$replay_internal_editor && [info exists replay_editbox] && [winfo exists $replay_editbox]} {
        $replay_editbox.txt tag delete yellow
        set cmd [$replay_editbox.txt get $replay_current.0 $replay_current.end]
    }
    set stat 1
    if [ info exists replay_always_update ] { 
    	set replay_update $replay_always_update
    } else {
        set replay_update 0
    }
    if {($cmd != "") && (([string index $cmd 0] != "#") || ([string index $cmd 1] == "!"))} {
	    if [replay_execute_command $cmd $replay_update] {
		    set stat 0
	    }
    }
    unset replay_mess_prefix
    unset replay_dont_record
    
    incr replay_current
    if [info exists replay_always_update] {
        replay_list_select
    }
    if {$replay_internal_editor && [info exists replay_editbox] && [winfo exists $replay_editbox]} {
        $replay_editbox.txt mark set insert $replay_current.0
        $replay_editbox.txt tag add yellow $replay_current.0 $replay_current.end
        $replay_editbox.txt tag configure yellow -background yellow
        if {[info exists replay_listbox] && [winfo exists $replay_listbox.list]} {
            $replay_editbox.txt yview moveto [lindex [$replay_listbox.list yview] 0]
        }
        form_text_editor_set_linenumber
    }
    return $stat
}

proc replay_doit_cur {} {
    global replay_always_update replay_dont_record
    global replay_count replay_current

    if ![info exists replay_always_update] {
        set replay_always_update 1
        set unsetit 1
    }
    if ![replay_doit] {
        mess "No current command to replay.\n" red
    }
    if [info exists unsetit] {
        unset replay_always_update
    }
    
    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_set_global wb_input_parameter_mode 1
        }
    }
    
    if {$replay_count && ($replay_current - 1) == $replay_count} {
        if {![info exists replay_always_update] || !$replay_always_update} { 
            set replay_dont_record 1
            replay_after_commands_done
            unset replay_dont_record
        }
    }
    
    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_unset_global wb_input_parameter_mode
        }
    }
}

proc replay_doit_all {} {
    global replay_count replay_current replay_always_update
    global replay_interupt replay_dont_record med_no_interactions
    global replay_internal_editor replay_editbox replay_listbox
    
    catch { unset replay_interupt }
    set nrep 0
    set error 0
    mess "Starting at command $replay_current, going to end\n"
    set med_no_interactions 1
    
    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_set_global wb_input_parameter_mode 1
        }
    }
    
    while {$replay_count && ($replay_current <= $replay_count)} {
        # break if the users interupts
	    if [info exists replay_interupt] {
		    mess "replay_interupt exists\n"
		    break
	    }
        # break if there was an error executing the commnad
	    if {[replay_doit] == 0}  {
		    set error 1
		    break
	    }
	    incr nrep
    }
    
    # This tells the GUI not to talk to the user at all
    set med_no_interactions 0
    catch { unset replay_interupt }
    replay_list_select
    if {![info exists replay_always_update] || !$replay_always_update} { 
	    set replay_dont_record 1
	    replay_after_commands_done
	    unset replay_dont_record
    }
    if $error {
	    mess "Error in replay script.\n" red
    } else {
	    if { $nrep <= 1 } {
	        mess "$nrep command line replayed.\n"
	    } else {
	        mess "$nrep command lines replayed.\n"
	    }
	    mess "Replay complete.\n"
    }

    if {$replay_internal_editor && [info exists replay_editbox] && [winfo exists $replay_editbox]} {
        $replay_editbox.txt mark set insert $replay_current.0
        if {[info exists replay_listbox] && [winfo exists $replay_listbox.list]} {
            $replay_editbox.txt yview moveto [lindex [$replay_listbox.list yview] 0]
        }
        form_text_editor_set_linenumber
    }

    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_unset_global wb_input_parameter_mode
        }
    }
}

proc replay_doit_range {} {
    global replay_range_min replay_range_max replay_count replay_current
    global replay_commands replay_always_update replay_interupt replay_dont_record
    global replay_internal_editor replay_editbox replay_listbox
    
    if {![info exists replay_range_min] || ($replay_range_min == "")} {
        replay_doit_range_reset
    }
    set d [form_init .replay_range "Replay range" "" [list accept "Reset replay_doit_range_reset" cancel]]
    if {$d != ""} {
	    form_label $d.minv "Start line" {0 0}
	    form_label $d.maxv "End line" {1 0}
	    form_entry $d.min replay_range_min string {0 1}
	    form_entry $d.max replay_range_max string {1 1}
	    form_finish bot
    }
    if {![form_wait .replay_range] || ($replay_range_min == "") || ($replay_range_max == "")} return
    if { ($replay_range_min > $replay_range_max) } return
    
    if [ info exists replay_always_update ] {
	    set replay_always_update_back $replay_always_update
	    unset replay_always_update
    }
    catch { unset replay_interupt }
    set nrep 0
    set error 0
    
    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_set_global wb_input_parameter_mode 1
        }
    }
    
    for {set i 1} {$i <= $replay_count} {incr i} {
        # break if there was a user interupt
	    if [ info exists replay_interupt ] break
	    set num [replay_linenumber_of $replay_commands($i)]
	    if {$num == ""} continue
	    if {($num < $replay_range_min) || ($num > $replay_range_max)} continue
	    set replay_current $i
	    if { [ replay_doit ] == 0 } {
		    set error 1
		    break
	    }
	    incr nrep
    }
    catch { unset replay_interupt }
    if [info exists replay_always_update_back] { 
	    set replay_always_update $replay_always_update_back
    }
    replay_list_select
    set replay_dont_record 1
    replay_after_commands_done
    unset replay_dont_record
    if $error {
	    mess "Error in replay script.\n" red
    } else {
	    if { $nrep <= 1 } {
	        mess "$nrep command line replayed.\n"
	    } else {
	        mess "$nrep command lines replayed.\n"
	    }
    }

    if {$replay_internal_editor && [info exists replay_editbox] && [winfo exists $replay_editbox]} {
        $replay_editbox.txt mark set insert $replay_current.0
        if {[info exists replay_listbox] && [winfo exists $replay_listbox.list]} {
            $replay_editbox.txt yview moveto [lindex [$replay_listbox.list yview] 0]
        }
        form_text_editor_set_linenumber
    }

    if [aie_wb2_is_running] {
        if {[aie_get_global replay_wb_mode] != "___NA___"} {
            aie_unset_global wb_input_parameter_mode
        }
    }
    
}

proc replay_doit_range_reset {} {
    global replay_range_min replay_range_max replay_count replay_current
    global replay_commands
    
    set replay_range_min ""; set replay_range_max ""
    
    for {set i 1} {$i <= $replay_count} {incr i} {
        set num [replay_linenumber_of $replay_commands($i)]
        if {$num == ""} continue
        if {($replay_range_min == "") || ($num < $replay_range_min)} {
            set replay_range_min $num
        }
        if {($replay_range_max == "") || ($num > $replay_range_max)} {
            set replay_range_max $num
        }
    }
}

proc replay_skip_cur {} {
    global replay_current
    global replay_internal_editor replay_editbox replay_listbox
    
    incr replay_current
    replay_list_select
    
    if {$replay_internal_editor && [info exists replay_editbox] && [winfo exists $replay_editbox]} {
        $replay_editbox.txt mark set insert $replay_current.0
        if {[info exists replay_listbox] && [winfo exists $replay_listbox.list]} {
            $replay_editbox.txt yview moveto [lindex [$replay_listbox.list yview] 0]
        }
        form_text_editor_set_linenumber
    }
}

proc replay_load {{file ""}} {
    global replay_file replay_dir replay_commands replay_count replay_current
    global replay_dirty ai_environment file_name
    
    replay_warn_dirs
    if {$file == ""} {
        if [info exists replay_file] {
            set def $replay_file
            if ![string match */* $def] {
                set def $replay_dir/$def
            }
        } else {
            set def [pwd]
        }
        if {[info exists ai_environment] && $ai_environment} {
            if [file exists $file_name(settings)] {
                set init_replay_file_name [file rootname [file tail $file_name(settings)]].rpl
            } else {
                set init_replay_file_name ""
            }
            set file [tk_getOpenFile \
			  -filetypes {{{Replay Files} {.rpl .jrf .tcl}} {{All Files} *}} \
			  -title "Open Script File" -parent . \
			  -initialfile $init_replay_file_name \
			  -initialdir [pwd] -defaultextension ".rpl"]
        } else {
            # Used by the old hexa
            set file [file_select_rel "File to load the script from?" $def]
        }
        if {$file == ""} { return 0 }
        mess "Loading replay file $file\n"
        set replay_file $file
    } else {
        if {[aie_wb2_is_running] && [aie_get_global replay_wb_mode] != "___NA___"} {
            mess "Loading replay file $file\n"
        }
    }
    
    catch {unset replay_commands}
    set replay_count 0
    set fp [open $file r]
    while {![eof $fp]} {
	set line [string trim [gets $fp]]
	while { [ string index $line end ] == "\\"} {
		set line [ string range $line  0 end-1 ] 
		set new_line [ string trim [gets $fp]]
		set line "$line $new_line"
	}
	if {$line != ""} {
	    incr replay_count
	    set replay_commands($replay_count) $line
	}
    }
    close $fp
    set replay_current 1
    replay_renumber 0
    replay_list_reset
    catch { unset replay_dirty }
    return 1
}

proc replay_save {{file ""} {skip_usenum 0}} {
    global replay_file replay_dir replay_commands replay_count replay_dirty
    global file_name ai_environment replay_internal_editor replay_editor

    replay_warn_dirs
    set usenum 1
    if {$file == ""} {
        if {[info exists ai_environment] && $ai_environment} {
            if {([info exists replay_file] && ($replay_file == "" || $replay_file == "replay_file")) && ([info exists file_name(settings)] && $file_name(settings) != "")} {
                set def [file rootname $file_name(settings)].rpl
            } else {
                if [info exists replay_file] {
                    set def $replay_file
                 } else {
                    set def [pwd]
                 }
            }
            set file [tk_getSaveFile -filetypes {{{Replay Files} {.rpl .jrf .tcl}} {{All Files} *}} \
			  -title "Save Script File" -parent . -initialfile $def -initialdir [pwd] -defaultextension ".rpl"]
            if {$file == ""} return
        } else {
            # For the old hexa GUI
            if [info exists replay_file] {
                set def $replay_file
                if ![string match */* $def] {
                    set def $replay_dir/$def
                }
            } else {
                set def [pwd]
            }
            set file [file_select_rel "File to save the replay script to?" $def "File selection" 0 1]
            if [file exists $file] {
                if [tk_dialog .overwrite Overwrite "Overwrite existing replay file $file?" "" -1 Yes No] return
            }
        }
        set replay_file $file
        set usenum 0
    }
    if {$file != ""} {
        if {[aie_wb2_is_running] && [aie_get_global replay_wb_mode] != "___NA___"} {
            ic_socket_send_to_wb2 "wb_status 0"
            set usenum 0
        }
        if $skip_usenum { set usenum 0 }
        replay_save_to_file $file $usenum
        if {[info exists replay_internal_editor] && $replay_internal_editor} {
            if {[info exists replay_editor] && ![winfo exists $replay_editor]} {
                mess "Saved replay log to $file\n"
            }
        } else {
            mess "Saved replay log to $file\n"
        }
    } else {
        mess "No file specified\n"
    }
    catch {unset replay_dirty}
}

proc replay_write_to_journal {cmd after} {
    global replay_journal_fp dont_record_command replay_has_result_func
    global journal_dont_record
    
    if {![info exists replay_journal_fp] || [info exists journal_dont_record]} return

    set cmd1 [lindex $cmd 0]
    set has_res [info exists replay_has_result_func($cmd1)]
    if $after {
	    if $has_res {
	        set res [batch_interp eval ${cmd1}_replay_result]
	        foreach r [split $res \n] {
		        set r [string trim $r]
		        if {$r != ""} {
		            regsub -all \n $r \\n r
		            if [catch {puts $replay_journal_fp $r; flush $replay_journal_fp} res] {
			            mess "Error writing to journal: $res\n" red
			            catch {close $replay_journal_fp}
			            unset replay_journal_fp
		            }
		        }
	        }
	    }
	    return
    } else {
	    if $has_res return
    }
    
    if [batch_interp eval uplevel \#0 info exists dont_record_command([lindex $cmd 0])] return
    regsub -all \n $cmd \\n cmd

    if [catch {puts $replay_journal_fp $cmd; flush $replay_journal_fp} res] {
	    mess "Error writing to journal: $res\n" red
	    catch {close $replay_journal_fp}
	    unset replay_journal_fp
    }
}

proc replay_save_to_file {file usenum} {
    global replay_commands replay_count

    set fp [open $file w]
    for {set i 1} {$i <= $replay_count} {incr i} {
	    if $usenum {
	        puts $fp $replay_commands($i)
	    } else {
	        puts $fp [replay_strip $replay_commands($i)]
	    }
    }
    close $fp
}

proc replay_warn_dirs {} {
    return
}

proc replay_renumber {full} {
    global replay_commands replay_count
    
    if $full {
	    for {set i 1} {$i <= $replay_count} {incr i} {
	        set replay_commands($i) "$i. [replay_strip $replay_commands($i)]"
	    }
    } else {
	    for {set i 1} {$i <= $replay_count} {incr i} {
	        if {[replay_linenumber_of $replay_commands($i)] == ""} {
		        replay_set_number $i
	        }
	    }
    }
    replay_dirty
}

proc replay_set_number {num} {
    global replay_commands replay_count
    
    if {$num == 1} {
	    set lno "1. "
    } elseif {$num == $replay_count} {
	    set lno1 [replay_linenumber_of $replay_commands([expr $num - 1])]
	    set lno "[expr $lno1 + 1]. "
    } else {
	    set lno1 [replay_linenumber_of $replay_commands([expr $num - 1])]
	    set lno2 [replay_linenumber_of $replay_commands([expr $num + 1])]
	    if {$lno1 == ""} {
	        set lno ""
	    } elseif {$lno2 == ""} {
	        set lno "[expr $lno1 + 1]. "
	    } elseif {$lno1 == $lno2 - 1} {
	        set lno "$lno1. "
	    } else {
	        set lno "[expr $lno1 + 1]. "
	    }
    }
    set replay_commands($num) "$lno[replay_strip $replay_commands($num)]"
    replay_dirty
}

proc replay_get_current_line {} {
    global replay_commands replay_current
    
    set num ""
    if [info exists replay_commands($replay_current)] {
    	set num [replay_linenumber_of $replay_commands($replay_current)]
    }
    return $num
}

proc replay_edit {} {
    global replay_commands replay_count replay_current options replay_file replay_internal_editor replay_temp_file 
    global replay_recording replay_main_box command_hook after_command_hook
    
    set num ""
    if [info exists replay_commands($replay_current)] {
    	set num [replay_linenumber_of $replay_commands($replay_current)]
    }
    if {[info exists replay_internal_editor] && $replay_internal_editor == "1" && [info exists replay_temp_file] && [file exists $replay_temp_file]} {
        set file $replay_temp_file
    } else {
        set file [tmp_filename]
    }
    if {[info exists replay_internal_editor] && $replay_internal_editor == "1"} {
        replay_renumber 1
        replay_list_reset
        if $replay_recording {
            set replay_recording 0
            unset command_hook
            unset after_command_hook
        }
        $replay_main_box.recording configure -state disabled
    }
    replay_save $file
    if {[info exists replay_internal_editor] && $replay_internal_editor == "1"} {
        set replay_temp_file $file
        replay_start_editor $file $num
    } else {
        edit_file $file 0  
        replay_load $file
        cmd_rm $file
    }
    if {$num != ""} {
	    set num1 0
	    set rc $replay_count
	    for {set i 1} {$i <= $replay_count} {incr i} {
	        set num2 [replay_linenumber_of $replay_commands($i)]
	        if {$num2 == $num} {
		        set rc $i
		        break
	        } elseif {($num2 != "") && ($num2 > $num)} {
		        if {($num1 == 0) || ($num2 < $num1)} {
		            set num1 $num2
		            set rc $i
		        }
	        }		
	    }
	    set replay_current $rc
	    replay_list_reset
    }
    replay_dirty
}

proc replay_clear {} {
    global replay_commands replay_count replay_current
    
    if !$replay_count {
	    mess "There are no commands to clear.\n"
	    return
    }
    set ok [tk_dialog .replay_ops.renum_clear Clear "Remove all commands from the replay log?" "" -1 Yes No]
    switch -- $ok {
        -1 { if [winfo exists .replay_ops.renum_clear] { top_destroy .replay_ops.renum_clear; return } }
        1 { return }
    }
    
    catch { unset replay_commands }
    set replay_count 0
    set replay_current 0
    replay_list_reset
    replay_dirty
}

proc replay_delete {} {
    global replay_commands replay_count replay_current
    
    if {!$replay_current || ($replay_current > $replay_count)} {
	    mess "No current command to delete.\n" red
	    return
    }
    for {set i $replay_current} {$i < $replay_count} {incr i} {
	    set replay_commands($i) $replay_commands([expr $i + 1])
    }
    unset replay_commands($replay_count)
    incr replay_count -1
    if { $replay_current > $replay_count } {
	    incr replay_current -1
    }
    replay_list_reset
    replay_dirty
}

proc replay_delete_range {} {
    global replay_range_min replay_range_max replay_count replay_current
    global replay_commands
    
    if {![info exists replay_range_min] || ($replay_range_min == "")} {
	    set num ""
	    catch {set num [replay_linenumber_of $replay_commands($replay_current)]}
	    if {$num == ""} {
	        replay_doit_range_reset
	    } else {
	        set replay_range_min $num
	        set replay_range_max $num
	    }
    }
    set d [form_init .delete_range "Delete range" "" [list accept "Reset replay_doit_range_reset" cancel]]
    if {$d != ""} {
	    form_label $d.minv "Start line" {0 0}
	    form_label $d.maxv "End line" {1 0}
	    form_entry $d.min replay_range_min string {0 1}
	    form_entry $d.max replay_range_max string {1 1}
	    form_finish bot
    }
    if {![form_wait .delete_range] || ($replay_range_min == "") || ($replay_range_max == "")} return
    if { ($replay_range_min > $replay_range_max) } return
 
    set ndel 0
    for {set i 1} {$i <= $replay_count} {incr i} {
	    set num [replay_linenumber_of $replay_commands($i)]
	    if {$num == ""} continue
	    if {($num < $replay_range_min) || ($num > $replay_range_max)} continue
 	    for {set j $i} {$j < $replay_count} {incr j} {
	        set replay_commands($j) $replay_commands([expr $j + 1])
	    }
	    unset replay_commands($replay_count)
	    incr replay_count -1
	    if {($replay_current > $i) || ($replay_current > $replay_count)} {
	        incr replay_current -1
	    }
	    incr i -1
	    incr ndel
    }
    if { $ndel <= 1 } {
	    mess "$ndel command line deleted.\n"
    } else {
	    mess "$ndel command lines deleted.\n"	
    }
    replay_list_reset
    replay_dirty
}

proc replay_insert_before {} {
    global replay_commands replay_count replay_current
    
    if {!$replay_current || ($replay_current > $replay_count)} {
	    mess "No current location for insert.\n" red
	    return
    }
    for {set i $replay_count} {$i >= $replay_current} {incr i -1} {
	    set replay_commands([expr $i + 1]) $replay_commands($i)
    }
    set replay_commands($replay_current) ""
    incr replay_count
    replay_list_reset
    replay_dirty
}

proc replay_list_reset {} {
    global replay_commands replay_count replay_listbox replay_internal_editor replay_editor
    
    if ![info exists replay_listbox] return
    
    set items ""
    for {set i 1} {$i <= $replay_count} {incr i} {
        lappend items $replay_commands($i)
    }
    form_listbox_set $replay_listbox $items
    replay_list_select
    if {[info exists replay_internal_editor] && $replay_internal_editor} {
        if {[info exists replay_editor] && [winfo exists $replay_editor]} {
            replay_update_editbox
        }
    }
}

proc replay_list_setvals {nums} {
    global replay_commands replay_count replay_listbox
    
    if ![info exists replay_listbox] return
    
    foreach n $nums {
	    form_listbox_set_index $replay_listbox [expr $n - 1] $replay_commands($n)
    }
    replay_list_select
}

proc replay_list_select {} {
    global replay_listbox replay_current
    
    if ![info exists replay_listbox] return
    form_listbox_select_index $replay_listbox [expr $replay_current - 1]
}

proc replay_list_set_select {num} {
    global replay_current

    set replay_current [expr $num + 1]
}

proc replay_remove_undo { last_func } {
	global replay_commands replay_current replay_count
	global replay_listbox replay_recording
	
	if {[info exists replay_recording] && $replay_recording} {
		set cur_command [ lindex $replay_commands($replay_current) 1 ]
		if { $cur_command != "undo" } {
			mess "Expecting current command to be undo\n" red
			mess "it was $cur_command\n" red
			return
		}
	}
	if { ! [ info exists replay_current ] } {
		return
	}
	
    # look for last func
	set i $replay_current
	incr i -1
	set com ""
	while {$i > 0} {
		if {[info exists replay_commands($i)]} {
			set line $replay_commands($i)
			set com  [ lindex $line 1 ]
			if {$com == $last_func} {
				break
			}
			if {$com == "undo_major_start"  && [lindex $line 2] == $last_func} {
			    set com [lindex $line 2]
				break
			}
		}
		incr i -1
	}
	if {$com != $last_func} {
		mess "Could not find command \"$last_func\" to delete to\n" red
		return
	}
	if {$replay_recording == 0} {
        # simply move back to that line
		set replay_current $i
		replay_list_select
		return
	}
    # highlight the lines to delete
	$replay_listbox.list see $i
	$replay_listbox.list selection clear 0 end
	$replay_listbox.list selection set [expr $i - 1] [expr $replay_current - 1]

	if [tk_dialog .quest "Query" "remove highlighted lines from the replay file ?" ""  0 "Yes" "No" ] {
		replay_list_select
		return
	}
    # delete all the commands from i to replay_current
	for { set j $i; set k [ expr $replay_current + 1 ] }  { $k <= $replay_count } { incr j; incr k } {
		set replay_commands($j) $replay_commands($k)
		unset replay_commands($k)
	}
	set replay_count [ expr $j - 1 ]
	set replay_current [ expr $i - 1 ]
	
	replay_list_reset
	replay_dirty
}

# =============== replay clean procs ===============
proc replay_popup_menu {{wfrom ""} {x 20} {y 20} {menus ""}} {
	global vid_options
	if {$wfrom == ""} {
		set wfrom $::replay_listbox.list
	}
	set w .vid_top_pop
	if [winfo exists $w] {destroy $w}
	set w [menu $w -tearoff 0]
	$w add command -label "Undo Clean" -command "replay_undo_clean $wfrom"		
	$w add checkbutton -label "Edit filter" -variable vid_options(edit_replay_filter) -command "replay_edit_filter $wfrom"		
	tk_popup $w $x $y
}

proc replay_undo_clean {w} {
	global replay_commands_saved replay_commands replay_current replay_count
	if ![array exists replay_commands_saved] return
	if [array exists replay_commands] {unset replay_commands}
	array set replay_commands [array get replay_commands_saved]
	set replay_count [llength [array names replay_commands]]
	set replay_current $replay_count
    replay_list_reset
    replay_dirty
}

proc replay_edit_filter {w {maybe_edit 1}} {
	global vid_options replay_exclude_cmd replay_listbox
	# Use option if call from replay window.
	# Set option "off" if called
	if $maybe_edit {
		set do_edit $vid_options(edit_replay_filter)
	} else {
		set do_edit 0
	}
	if !$do_edit {
		#save filter
		if [winfo exists $w.text] {
			set replay_exclude_cmd [$w.text get 1.0 end]
			pack forget $w.text
		}
		set vid_options(edit_replay_filter) 0
		return
	}
	if ![winfo exists $w.text] { 
		text $w.text
	}
	$w.text delete 1.0 end
	$w.text insert 1.0 $replay_exclude_cmd
	pack $w.text -fill both
	bind $w.text <Button-3> "replay_edit_filter $w 0"	
}

proc replay_clean {} {
# testing new version for 11.0. See replay_clean_old
    global replay_commands replay_current replay_count
    global replay_listbox replay_recording replay_exclude_cmd
	global replay_commands_saved replay_exclude_cmd2
	if ![info exists replay_current] return
	bind $replay_listbox.list <Button-3> "replay_popup_menu $replay_listbox.list %X %Y"	

# Currently default filters defined here; may be moved to globals.tcl
#----------------------------------------
if ![info exists replay_exclude_cmd] {
# 
# type each command name on separate line from first position:
#	
set replay_exclude_cmd {	
ic_undo 
ic_redo
ic_undo_group_begin
ic_undo_group_end
ic_undo_start
ic_undo_end
ic_undo_suspend
ic_undo_resume
ic_hex_undo_major_start
ic_hex_undo_major_end
}
}
if ![info exists replay_exclude_cmd2] {
#
# check for the same commands with the same arguments in two lines successively
#
set replay_exclude_cmd2 {
ic_uns_update_family_type
ic_delete_empty_parts
ic_uns_diag_reset_degen_min_max
}
}

    catch { array unset replay_commands_saved }
# make copy, clean with current filter, renumber
	if ![array exists replay_commands] return 
	array set replay_commands_saved [array get replay_commands]
	unset replay_commands	
	set nums [lsort -integer [array names replay_commands_saved]]
	set replay_count 0
	set last_command ""
	set last_args ""
	foreach n $nums {
		# strange format: ${num}. $the_cmd $args
		set the_cmd [lindex $replay_commands_saved($n) 1]
		set the_args [lrange $replay_commands_saved($n) 2 end]
		if {[lsearch $replay_exclude_cmd $the_cmd] >= 0} continue
		# remove a duplicate command in the next line also
		if {[lsearch $replay_exclude_cmd2 $the_cmd] >= 0} {
		    if {([string match "$the_cmd" "$last_command"]) && ([string match "$the_args" "$last_args"])} continue
		}
		incr replay_count
		set replay_commands($replay_count) $replay_commands_saved($n)
		set last_command $the_cmd
		set last_args $the_args
	}
    set replay_current $replay_count
    replay_list_reset
    replay_dirty
}    
#====== end replay clean procs =================
# Copy the current list to clean_list; scan the current_list and
# remove/add the statements correspoinding to undo/redo.
# finally remove all undo_group_begin and undo_group_end
proc replay_clean_old {} {
    global replay_commands replay_current replay_count
    global replay_listbox replay_recording

    if { ! [ info exists replay_current ] } {
	return
    }
    
    set cline 1
    set redo_valid 0
    for {set i 1} {$i <= $replay_current} {incr i} {
	if ![ info exists replay_commands($i) ]  {
	    continue
	}

	set line $replay_commands($i)
	set com  [ lindex $line 1 ]	
	if { $com == "ic_undo" && $cline > 0} {
	    incr cline -1
	    set com  [ lindex $clean_list($cline) 0 ]
	    if {$com == "ic_undo_group_end"} {
		while {$cline > 0} {
		    incr cline -1
		    set com  [ lindex $clean_list($cline) 0 ]
		    if {$com == "ic_undo_group_begin"} {
			incr cline -1
			break
		    }
		}
	    }
	    set redo_valid 1
	} elseif { $com == "ic_redo" && $cline > 0 } {
	    if !$redo_valid {
		continue
	    }
	    if ![info exists clean_list($cline)] {
		continue
	    }
	    set com  [ lindex $clean_list($cline) 0 ]
	    if {$com == "ic_undo_group_begin"} {
		while {$cline > 0} {
		    incr cline 1
		    set com  [ lindex $clean_list($cline) 0 ]
		    if {$com == "ic_undo_group_end"} {
			break
		    }
		}
	    }
	} elseif {$cline > 0} {
	    set clean_list($cline) [lrange $line 1 end]
	}
	incr cline
    }
    incr cline -1
    
    catch {unset replay_commands}
    set exclude_commands {
	ic_undo_group_begin
	ic_undo_group_end
	ic_undo_suspend
	ic_undo_resume
	ic_undo_start
	ic_undo_stop
    }

    set lnum 0
    for {set i 1} { $i <= $cline } {incr i} {
	set com [lindex $clean_list($i) 0]
	if {[lsearch $exclude_commands $com] < 0} {
	    incr lnum
	    set replay_commands($lnum) [linsert $clean_list($i) 0 $lnum.]
	}
    }

    set replay_count $lnum
    set replay_current $lnum
    
    replay_list_reset
    replay_dirty
}

# every use of suspend_all_recording should be paired up with a later call to resume_all_recording
proc suspend_all_recording {} {
    global journal_dont_record logfile_dont_record replay_dont_record
    upvar ::record_status([array size ::record_status]) data

    set data {}
    foreach var [list journal_dont_record logfile_dont_record replay_dont_record] {
	lappend data [info exists $var]
	set $var 1
    }
}

proc resume_all_recording {} {
    global journal_dont_record logfile_dont_record replay_dont_record
    if {[set i [array size ::record_status]] == 0} return
    upvar ::record_status([expr {$i-1}]) data

    foreach val $data var [list journal_dont_record logfile_dont_record replay_dont_record] {
	if $val {set $var 1} \
	else {catch {unset $var}}
    }
    unset data
}

