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

#Load the ca pacakge this way to avoid the dp_atexit error
set caLib [file join [lindex $tcl_pkgPath 0] ca libtclCa.so]
load $caLib

#set basic script variables
set apsScriptUser $env(USER)
set apsScriptHost [exec hostname]
set apsScriptDate [clock format [clock seconds] -format "%a %b %d %T %Z %Y"]
set rcPV S-INJ:TopLevelInjCheckSumsC
set permissivePV S-INJ:TopLevelInjPermissiveC
#set rcPV OAG181RC
set runControlTimeout 20



if {[pv linkw "perm(pid) perm(user) perm(host)" "${permissivePV}.PID ${permissivePV}.USER ${permissivePV}.HOST"]} {
    puts stderr "Unable to connect to $permissivePV"
    pv exit
    exit 1
}


proc CheckSumVerification {args} {
    global rcPV perm permissivePV apsScriptHost

    set checkSums(sddspermissive) cfc98581aedd3507d2edaf681361dedd140af0550ce0b19ef675054631611b34
    set checkSums(injswap-perm-test) 14f583cc9f16c1c00d05ac1f3e432d488fc86b607baaa378fd99c643b7b8dcbd
    set checkSums(sr-permissive.sdds) 50587cd8fae9f37672669d217e76b1699d1c91c32d47e466608ba4295bbb3f64 
    set checkSums(swapOutPermissiveLauncher) e4f9685f824fdaa8e5839c557332f4852d2d933deb2cf68606a2511a35875ed1 
    set fullPath(sddspermissive) /usr/local/oag/apps/bin/linux-x86_64/sddspermissive
    set fullPath(injswap-perm-test) /C2/etc/auxiliary-scripts/bin/injswap-perm-test
    set fullPath(sr-permissive.sdds) /home/helios/oagData/sr/permissive/sr-permissive.sdds
    set fullPath(swapOutPermissiveLauncher) /usr/local/oag/apps/bin/linux-x86_64/swapOutPermissiveLauncher
    
    ConnectToRunControl
    
    while {1} {
        set nExecProblems 0
        set nFileProblems 0
        set nChecksumProblems 0
        if {[pv getw "perm(pid) perm(user) perm(host)"]} {
            puts stderr "Unable to read $permissivePV"
            incr nExecProblems
        } else {
            if {($perm(user) != "") && ($perm(user) != "asdops")} {
                puts stderr "sddspermissive is being run by $perm(user) instead of asdops"
                incr nExecProblems
            }
            if {($perm(host) != "") && ($perm(host) != $apsScriptHost)} {
                puts stderr "sddspermissive is running on $perm(host) instead of $apsScriptHost"
                incr nExecProblems
            } elseif {($perm(pid) != "")} {
                if {[catch {exec /bin/ps -p $perm(pid) -o cmd} cmdline]} {
                    puts stderr "Unable find PID $perm(pid)"
                    incr nExecProblems
                } else {
                    set index [lsearch -exact $cmdline $fullPath(sr-permissive.sdds)]
                    if {$index == -1} {
                        puts stderr "sddspermissive using the wrong input file"
                        incr nExecProblems
                    }
                }
            }
        }
        foreach item [array names checkSums] {
            if {[catch {exec sha256sum $fullPath($item)} result]} {
                puts stderr "Unable to run sha256sum on $fullPath($item)"
                incr nFileProblems
            } else {
                set result [lindex [split $result] 0]
                if {($checkSums($item) != [string trim $result])} {
                    puts stderr "Checksum is wrong for $fullPath($item)"
                    incr nChecksumProblems
                }
            }
        }
        if {($nFileProblems>0 || $nChecksumProblems>0)} {
            if {[catch {RunControlLogMessage "Errs:$nFileProblems files, $nChecksumProblems checksums" 2} result]} {
                puts stderr "Unable to set the runcontrol log message for ${rcPV}: $result"
            }
        } elseif {$nExecProblems>0} {
            if {[catch {RunControlLogMessage "Errs:$nExecProblems cmdline problems" 2} result]} {
                puts stderr "Unable to set the runcontrol log message for ${rcPV}: $result"
            }
        }
        
        #Ping runcontrol 12 times in 60 seconds
        for {set i 1} {$i <= 12} {incr i} {
            if {[catch {RunControlPing} result]} {
                if {($result == "RUNCONTROL_TIMEOUT") || ($result == "RUNCONTROL_ERROR")} {
                    puts stderr "Unable to ping ${rcPV}: $result"
                    pv exit
                    exit 1
                } else {
                    #Abort was clicked
                    pv exit
                    exit
                }
            }
            after 5000
        }
    }
}

proc RunControlInit {pv description timeout} {
    global apsRunControlInitialized apsScriptUser apsScriptHost apsScriptDate
    global apsScriptCommand

    set pvnameVAL ${pv}.VAL
    set pvnameHBT ${pv}.HBT
    set pvnameUSER ${pv}.USER
    set pvnameHOST ${pv}.HOST
    set pvnamePID ${pv}.PID
    set pvnameSEM ${pv}.SEM
    set pvnameDESC ${pv}.DESC
    set pvnameSTRT ${pv}.STRT
    set pvnameABRT ${pv}.ABRT
    set pvnameSUSP ${pv}.SUSP
    set pvnameHBTO ${pv}.HBTO
    set pvnameMSG ${pv}.MSG
    set pvnameALRM ${pv}.ALRM
    set pvnameCLR ${pv}.CLR

    # Connect up PVs
    set varList {pvVAL pvHBT pvUSER pvHOST pvPID pvSEM pvDESC pvSTRT pvABRT \
                   pvSUSP pvHBTO pvMSG pvALRM pvCLR}
    set nameList [list $pvnameVAL $pvnameHBT $pvnameUSER $pvnameHOST \
                    $pvnamePID $pvnameSEM $pvnameDESC $pvnameSTRT $pvnameABRT \
                    $pvnameSUSP $pvnameHBTO $pvnameMSG $pvnameALRM $pvnameCLR]
    if {[pv linkw $varList $nameList]} {
        return -code error "RUNCONTROL_ERROR"
    }

    eval global $varList

    #check the permissions
    if {[catch {pv info pvHBT access} access]} {
        return -code error "RUNCONTROL_ERROR"
    }
    if {[lindex [lindex $access 0] 1] != "RW"} {
        return -code error "RUNCONTROL_ERROR"
    }

    #Clear any timeouts
    set pvCLR 1
    if {[pv putw pvCLR]} {
        return -code error "RUNCONTROL_ERROR"
    }
    
    # Set heartbeat timeout
    set pvHBT $timeout
    if {[pv putw pvHBT]} {
        return -code error "RUNCONTROL_ERROR"
    }

    # Try to take semaphore by putting a 0. Generates error if unavailable.
    set pvSEM 0
    if {[pv putw pvSEM 5]} {
        return -code error "RUNCONTROL_DENIED"
    }

    # Load record with user, host, pid, start time, and description
    set pvUSER $apsScriptUser
    set pvHOST $apsScriptHost
    set pvSTRT $apsScriptDate
    set pvDESC $description
    set pvPID [pid]
    if {[pv putw {pvUSER pvHOST pvSTRT pvDESC pvPID}]} {
        return -code error "RUNCONTROL_ERROR"
    }
    set apsRunControlInitialized 1
    return -code ok "RUNCONTROL_OK"
}

proc RunControlLogMessage {message severity} {
    global apsRunControlInitialized pvMSG pvALRM

    if {!$apsRunControlInitialized} {
        return -code error "RUNCONTROL_ERROR"
    }

    set pvMSG $message
    set pvALRM $severity

    if {[pv putw {pvMSG pvALRM}]} {
        return -code error "RUNCONTROL_ERROR"
    }
    return -code ok "RUNCONTROL_OK"
}

proc RunControlPing {} {
    global apsRunControlInitialized

    if {!$apsRunControlInitialized} {
        return -code error "RUNCONTROL_ERROR"
    }

    set varList {pvVAL pvABRT pvSUSP pvHBTO pvPID}

    eval global $varList

    if {[pv getw $varList]} {
        return -code error "RUNCONTROL_ERROR"
    }
    if {![string compare $pvABRT Abort]} {
        return -code error "RUNCONTROL_ABORT"
    } elseif {![string compare $pvHBTO Timeout]} {
        return -code error "RUNCONTROL_TIMEOUT"
    } elseif {![string compare $pvSUSP Suspend]} {
        while {![string compare $pvSUSP Suspend]} {
            after 1000
            update
            if {[pv getw {pvABRT pvSUSP pvPID}]} {
                return -code error "RUNCONTROL_ERROR"
            }
            if {![string compare $pvABRT Abort]} {
                return -code error "RUNCONTROL_ABORT"
            } elseif {[string compare $pvPID [pid]]} {
                return -code error "RUNCONTROL_ERROR"
            }
        }
    } elseif {[string compare $pvPID [pid]]} {
        return -code error "RUNCONTROL_ERROR"
    }
    
    # No suspend, abort, or timeout. So ping the record
    set pvVAL 1
    if {[pv putw pvVAL]} {
        return -code error "RUNCONTROL_ERROR"
    }
    return -code ok "RUNCONTROL_OK"
}

proc RunControlExit {} {
    global apsRunControlInitialized

    if {!$apsRunControlInitialized} {
        return -code error "RUNCONTROL_ERROR"
    }
    set varList {pvVAL pvHBT pvUSER pvHOST pvPID pvSEM pvDESC pvSTRT pvABRT \
                   pvSUSP pvHBTO pvMSG pvALRM}
    eval global $varList
    set pvSEM 1
    if {[pv putw pvSEM]} {
        return -code error "RUNCONTROL_ERROR"
    }
    if {[pv unlink $varList]} {
        return -code error "RUNCONTROL_ERROR"
    }
    set apsRunControlInitialized 0
    return -code ok "RUNCONTROL_OK"
}

##############
# Initialize the run control and set the timeout value.
# If another version is already running then we will get 
# the RUNCONTROL_DENIED response and we exit without 
# printing any error messages.
##############
proc ConnectToRunControl {args} {
    global rcPV runControlTimeout
    
    if {[catch {RunControlInit $rcPV "CheckSumVerification" [expr $runControlTimeout * 1000]} result]} {
        if {$result == "RUNCONTROL_DENIED"} {
            #It is ether already running or in the process of aborting
            pv exit
            exit
        } else {
            puts stderr "Unable to initialize runcontrol ${rcPV}: $result"
            pv exit
            exit 1
        }
    }
    if {[catch {RunControlLogMessage "Running" 0} result]} {
        puts stderr "Unable to set the runcontrol log message for ${rcPV}: $result"
        pv exit
        exit 1
    }
    if {[catch {RunControlPing} result]} {
        if {($result == "RUNCONTROL_TIMEOUT") || ($result == "RUNCONTROL_ERROR")} {
            puts stderr "Unable to ping ${rcPV}: $result"
            pv exit
            exit 1
        } else {
            #Abort was pressed. Probably never happen this close after starting.
            pv exit
            exit
        }
    }
}

CheckSumVerification
