#!/bin/sh  
# \
exec oagwish "$0" "$@"


#
#
# pre-boot, post-boot, power cycle, general functions

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH) ]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]

set CVSRevisionAuthor "\$Revision: 1.10 $ \$Author: soliday $"
package require mysqltcl

APSApplication . -name "IOC Rebooter"  -version $CVSRevisionAuthor \
  -overview "Used to remotely reboot IOCs.\n\nLocate the IOC you wish to reboot.\n\nEnter the reason you wish to reboot it.\n\nClick Unlock and Reboot.\n\nIt attempts to use iocConsole to connect to the IOC."

APSSetVarAndUpdate status "Searching for information about IOCs..."
APSScrolledStatus .status \
  -parent .userFrame \
  -textVariable status \
  -width 60 \
  -height 6 \
  -packOption "-fill x"

APSScrolledText .expectstatus \
  -parent .userFrame \
  -width 96 \
  -height 20 \
  -packOption "-fill x" \
  -contextHelp "Output from iocConsole and telnet is displayed here."
.userFrame.expectstatus.text tag configure bold -foreground black -font {-adobe-courier-bold-r-normal-*-14-*-*-*-*-*-*-*}
.userFrame.expectstatus.text tag configure green -background green -foreground black -font {-adobe-courier-normal-r-normal-*-14-*-*-*-*-*-*-*}

proc SetText {args} {
    set text ""
    set tag ""
    APSStrictParseArguments {text tag}
    set text [join [split $text \r]]
    .userFrame.expectstatus.text insert end $text $tag
    .userFrame.expectstatus.text see end
}

APSLabeledEntry .reason \
  -parent .userFrame \
  -label "Reason for reboot:" \
  -packOption "-side top -fill x -expand true" \
  -textVariable rebootReason \
  -contextHelp "Used by the iocConsole in record the reason the IOC was rebooted."

if {[catch {package require Expect} results]} {
    APSAlertBox [APSUniqueName .] -errorMessage "$results"
    exit 1
}

proc SetupScreen {args} {
    global ioc

    pack [frame .userFrame.labelFrame] -fill x
    pack [label .userFrame.labelFrame.iocName -text "\t\t\tIOC Name"] -side left
    pack [label .userFrame.labelFrame.iocOwner -text "\tOwner"] -side left
    pack [label .userFrame.labelFrame.iocLocation -text "\t  Location"] -side left
    
    
    APSScroll .scrollWin \
      -parent .userFrame \
      -name "" \
      -packOption "-fill both -expand true" 
    .userFrame.scrollWin.frame.canvas config \
      -yscrollincrement 22 \
      -height 300 \
      -width 600
    pack configure .userFrame.scrollWin.frame.canvas \
      -fill both \
      -expand true
    
    global rows
    set w .userFrame.scrollWin.frame.canvas.frame
    set rows 0
    foreach name $ioc(name) {
        pack [frame ${w}.f$rows -bd 1 -relief raised] -fill x
        pack [button ${w}.f${rows}.pvs \
                -text "List PVs" -highlightthickness 0 \
                -padx 3 -pady 1 \
                -font "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*" \
                -command "ListPVs -iocname $name"] -side left
        pack [button ${w}.f${rows}.info \
                -text "IOC Info" -highlightthickness 0 \
                -padx 3 -pady 1 \
                -font "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*" \
                -command "IOCInfo -iocname $name"] -side left
        pack [button ${w}.f${rows}.reboot \
                -text "Reboot" -highlightthickness 0 \
                -padx 3 -pady 1 \
                -font "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*" \
                -command "Reboot -iocname $name" \
                -state disabled] -side left
        pack [button ${w}.f${rows}.unlock \
                -text "Unlock" -highlightthickness 0 \
                -padx 3 -pady 1 \
                -font "-adobe-courier-medium-r-normal-*-10-*-*-*-*-*-*-*" \
                -command "IOCInfo -iocname $name ; Unlock -iocname $name -button ${w}.f${rows}"] -side left
        pack [label ${w}.f${rows}.name -text [format %-16s $name]] -side left
        pack [label ${w}.f${rows}.owner -text [format %-15s [join $ioc(${name}.user)]]] -side left
        pack [label ${w}.f${rows}.location -text [format %-13s [join $ioc(${name}.location)]]] -side left
        lappend ioc(loadPVs) ${name}:load
        incr rows
    }
    global rebootOnly
    set rebootOnly 0
    if 0 {
    APSCheckButtonFrame .rebootOnly \
      -parent .userFrame \
      -label "" \
      -buttonList {"Reboot Only (Do not run any Pre-Boot procedures)"} \
      -variableList "rebootOnly" \
      -contextHelp "Do not run any Pre-Boot procedures" \
      -packOption "-side top -anchor nw"
    }
    APSButton .abort -parent .userFrame -text Abort -command AbortTclProcedures
    pack .userFrame.abort
}

proc ScrollAdjust {} {
    global rows
    .userFrame.scrollWin.frame.canvas config -scrollregion "0 0 1000 [expr 22 * ($rows)]"
}

set lockout 0
proc Unlock {args} {
    set iocname ""
    set button ""
    set auto 0
    global rows lockout
    set w .userFrame.scrollWin.frame.canvas.frame
    APSStrictParseArguments {iocname button auto}
    if {([${button}.unlock cget -text] == "Unlock") && ($auto == 0)} {
        if {$lockout} {
            APSSetVarAndUpdate status "Locked out while rebooting IOC"
            return
        }
        APSSetVarAndUpdate status "Unlocking $iocname"
        ${button}.unlock configure -text " Lock "
        ${button}.reboot configure -state normal
        for {set i 0} {$i < $rows} {incr i} {
            if {"${w}.f${i}" != "$button"} {
                ${w}.f${i}.unlock configure -state disabled
            }
        }
        after 20000 Unlock -iocname $iocname -button $button -auto 1
    } else {
        if {[${button}.unlock cget -text] == "Unlock"} {
            return
        }
        APSSetVarAndUpdate status "Locking $iocname"
        ${button}.unlock configure -text Unlock
        ${button}.reboot configure -state disabled
        for {set i 0} {$i < $rows} {incr i} {
            if {"${w}.f${i}" != "$button"} {
                ${w}.f${i}.unlock configure -state normal
            }
        }
    }
}

proc Reboot {args} {
    set iocname ""
    APSStrictParseArguments {iocname}
    
    global rebootReason lockout rebootOnly
    set lockout 1
    
    if {[string range $iocname 0 0] == "s"} {
        APSSetVarAndUpdate status "Soft IOCs cannot currently be rebooted with this program"
        bell
        set lockout 0
        return        
    }

    if {$rebootReason == ""} {
        APSSetVarAndUpdate status "Invalid reboot reason"
        bell
        set lockout 0
        return
    }
    set answer [tk_messageBox -default no -icon question -message "Have you read the Pre-Boot instructions for ${iocname}?" -parent . -type yesno]
    if {$answer == "no"} {
        APSSetVarAndUpdate status "Please read the Pre-Boot instructions for $iocname"
        set lockout 0
        return
    }
    if {$rebootOnly == 0} {
        if {[catch {PreBootProcedure -iocname $iocname} result]} {
            APSSetVarAndUpdate status "Error running Pre-Boot procedure: $result"
            bell
            set lockout 0
            return
        }
    }

    APSSetVarAndUpdate status "Attempting to reboot $iocname"

    global timeout expect_out apsScriptUser

    set timeout 60

    set prompt 0
    SetText -text "\n"
    spawn -noecho iocConsole $iocname
    match_max -i $spawn_id 10000
    log_user 0
    expect {
        "screen session." {
            SetText -text $expect_out(buffer)
            exp_continue
        } "NOT reachable." {
            SetText -text $expect_out(buffer)
            bell
            catch {exp_close}
        } "Are you sure you want to continue connecting(yes/no)?" {
            SetText -text $expect_out(buffer)
            APSSetVarAndUpdate status "This account (${apsScriptUser}) does not have access privileges to reboot $iocname"
            bell
            catch {exp_close}
        } "password:" {
            SetText -text $expect_out(buffer)
            APSSetVarAndUpdate status "This account (${apsScriptUser}) does not have access privileges to reboot $iocname"
            catch {exp_close}
        } "Password:" {
            SetText -text $expect_out(buffer)
            APSSetVarAndUpdate status "This account (${apsScriptUser}) does not have access privileges to reboot $iocname"
            catch {exp_close}
        } "${iocname}>" {
            SetText -text $expect_out(buffer)
            incr prompt
            if {$prompt == 20} {
                APSSetVarAndUpdate status "Sending reboot command"
#This is Control-x, Control-y, Control-z
                exp_send "\030\031\032"
#                exp_send "reboot\r"
                exp_continue
            } elseif {$prompt < 20} {
                exp_send "\r"
                exp_continue
            } else {
                exp_continue                
            }
        } "booting..." {
            SetText -text $expect_out(buffer)
            exp_continue
        } "NOTICE TO USERS" {
            SetText -text $expect_out(buffer)
            exp_continue
        } "=" {
            SetText -text $expect_out(buffer)
            exp_continue
        } "," {
            SetText -text $expect_out(buffer)
            exp_continue
        } "reason of reboot >>>>>" {
            SetText -text $expect_out(buffer)
            if {$prompt >= 20} {
                exp_send "\r"
            }
            exp_continue
        } "User Name :" {
            SetText -text $expect_out(buffer)
            if {$prompt >= 20} {
                APSSetVarAndUpdate status "Sending username of rebooter"
                exp_send "${apsScriptUser}\r"
            }
            exp_continue
        } "reason to reboot :" {
            SetText -text $expect_out(buffer)
            if {$prompt >= 20} {
                APSSetVarAndUpdate status "Sending reason for reboot"
                exp_send "${rebootReason}\r"
            }
            exp_continue
        } "Reboot time is recorded." {
            SetText -text $expect_out(buffer)
            if {$prompt >= 20} {
                APSSetVarAndUpdate status "Reboot time has been recorded"
                APSSetVarAndUpdate status "$iocname rebooted successfully"
                catch {exp_close}
            } else {
                exp_continue
            }
        } timeout {
            catch {SetText -text $expect_out(buffer)}
            APSSetVarAndUpdate status "Connection to $iocname timed out"
            catch {exp_close}
        } eof {
           APSSetVarAndUpdate expectStatus $expect_out(buffer)
        }
    }
    SetText -text "\n"

    APSSetVarAndUpdate status "Done"
    set lockout 0
}

proc IOCInfo {args} {
    set iocname ""
    APSStrictParseArguments {iocname}
    global ioc
    SetText -text "--------- ${iocname} ---------\n\n" -tag bold
    SetText -text "General Functions\n" -tag bold
    SetText -text "[join $ioc(${iocname}.generalFunctions)]\n"
    SetText -text "Pre-Boot Instructions\n" -tag bold
    SetText -text "[join $ioc(${iocname}.preboot)]\n"
    SetText -text "Post-Boot Instructions\n" -tag bold
    SetText -text "[join $ioc(${iocname}.postboot)]\n"
    SetText -text "Power Cycle Caution\n" -tag bold
    SetText -text "[join $ioc(${iocname}.powercycle)]\n"
}

proc GetIOCInfo {args} {
    global ioc

    if {[catch {::mysql::connect -host ctlrdbprod -user public-read -password aps-irmis} handle]} {
        APSSetVarAndUpdate status "Unable to get IOC information: $handle"
        return
    }

    if {[catch {::mysql::use $handle irmis} result]} {
        APSSetVarAndUpdate status "Unable to get IOC information: $result"
        return
    }
    
    if {[catch {::mysql::sel $handle "select ioc_nm, general_functions, pre_boot_instr, post_boot_instr, power_cycle_caution, location, first_nm, last_nm from ioc, aps_ioc, person where ioc.ioc_id = aps_ioc.ioc_id and aps_ioc.cog_technician_id = person.person_id" -flatlist} results]} {
        APSSetVarAndUpdate status "Unable to get IOC information: $results"
        return
    }
    
    foreach "name general pre post power location firstname lastname" $results {
        set v ""
        lappend v $name
        lappend v $general
        lappend v $pre
        lappend v $post
        lappend v $power
        lappend v $location
        lappend v "$firstname $lastname"
        lappend info $v
    }
    set info [lsort -dictionary -index 0 $info]
    foreach line $info {
        foreach "name general preboot postboot powercycle location tech" $line {
            lappend ioc(name) $name
            lappend ioc(${name}.user) $tech
            lappend ioc(${name}.generalFunctions) $general
            lappend ioc(${name}.preboot) $preboot
            lappend ioc(${name}.postboot) $postboot
            lappend ioc(${name}.powercycle) $powercycle
            lappend ioc(${name}.location) $location
        }
    }
    ::mysql::close $handle
}

proc ListPVs {args} {
    set iocname ""
    APSStrictParseArguments {iocname}
    APSSetVarAndUpdate status "Searching for PVs on $iocname"
    APSExecLog .pvs -unixCommand "sddsprocess /home/helios/oagData/pvdata/iocRecNamesOAG.sdds -match=column,ioc_name=$iocname -pipe=out -nowarn | sdds2stream -pipe=in -column=rec_name -rows" \
      -callback "ListPVsDone -iocname $iocname"    
}

proc ListPVsDone {args} {
    set iocname ""
    APSStrictParseArguments {iocname}
    APSSetVarAndUpdate status "Done searching for PVs on $iocname"
}

package require comm

proc APSMpStep {stepName args} {
    global apsNetworkDomain apsScriptUser apsScriptHost

    if {(![string compare $apsNetworkDomain "accel.ntw0rk"]) || (![string compare $apsNetworkDomain "aps4.anl.gov"])} {
	set procName [lindex [info level [expr [info level] - 1]] 0]	
	set logCmd "logMessage -sourceId=scriptAction -tag=User $apsScriptUser -tag=Host \"$apsScriptHost\" -tag=Procedure $procName -tag=Action Start -tag=Parameters ? -tag=Status ? -tag=Script ? -tag=Stack ?"
	catch {eval exec $logCmd}
    }
    SetText -text "$stepName\n" -tag green
    return
}

proc PreBootProcedure {args} {
    set iocname ""
    APSStrictParseArguments {iocname}

    global apsPemStackPrefix cwd abortRequest procID
    set apsPemStackPrefix IOCRebooter
    set cwd [pwd]
    set abortRequest ""
    unset -nocomplain procID


    switch -exact $iocname {
        iocbramp {
            set tclprocedure(1,1) "APSMpBoosterPSSetNoPower -BM 1 -QF 1 -QD 1 -SF 1 -SD 1"
#            set tclprocedure(1,2) "APSMpBRFStandbyFromFullPower"
            set message(1,1) "Running APSMpBoosterPSSetNoPower to bring BM, QF, QD, SF, and SD down."
#            set message(1,2) "Running APSMpBRFStandbyFromFullPower to bring the booster rf system in to standby mode if at full power."
	} default {
            return
        }
    }
    if {[info exists tclprocedure]} {
        APSSetVarAndUpdate status "Running Tcl procedures as part of the Pre-Boot procedures."
	global mpInterface
	set mpInterface 1
        for {set i 1} {$i <= 10} {incr i} {
            for {set j 1} {$j <= 10} {incr j} {
                if {[info exists tclprocedure(${i},${j})]} {
                    APSSetVarAndUpdate status $message(${i},${j})
                    set procID(${i},${j}) [APSMpParallel -procedure $tclprocedure(${i},${j}) -mode Automatic]
                }
            }
            for {set j 1} {$j <= 10} {incr j} {
                if {[info exists tclprocedure(${i},${j})]} {
                    if {[catch {APSMpJoin $procID(${i},${j})} result]} {
                        if {[APSPEMTKDialog .warningDialog -text "Error running [lindex $tclprocedure(${i},${j}) 0]\n$result"] == 1} {
                            return -code error $result
                        }
                    }
                }
            }
        }
        unset -nocomplain procID
    }
    return
}

proc AbortTclProcedures {args} {
    global procID
    for {set i 1} {$i <= 10} {incr i} {
        for {set j 1} {$j <= 10} {incr j} {
            if {[info exists procID(${i},${j})]} {
                if {[catch {APSMpAbort $procID(${i},${j})} result]} {
                    APSSetVarAndUpdate "Error: $result"
                }
            }
        }
    }
}


update
GetIOCInfo
SetupScreen
ScrollAdjust
APSSetVarAndUpdate status Ready

