

proc APSUBtsDcpsAction {args} {
    global apsScriptHost apsPemStackPrefix
    set action ""
    set value 0
    set names ""
    set statusCallback ""
    set maxTries 10
    APSStrictParseArguments {action value names statusCallback}

    if {[llength $names] == 0} {
        return
    }
    
    if {![info exists apsPemStackPrefix]} {
        set apsPemStackPrefix APSUBtsDcpsAction
    }
    
    #Correctors are bipolar
    #Quads and Skew Quads are unipolar
    #We also have the Dipoles AB, BX, BB1 and CB1
    #Plus the Septum and Kicker supplies
    foreach type "bipolar unipolar dipole septum kicker" {
        set magnets($type) ""
    }
    foreach name $names {
        if {([string index $name end-1] == "H") || ([string index $name end-1] == "V")} {
            lappend magnets(bipolar) $name
        } elseif {([string index $name end] == "H") || ([string index $name end] == "V")} {
            lappend magnets(bipolar) $name
        } elseif {[string index $name end-1] == "Q"} {
            lappend magnets(unipolar) $name
        } elseif {($name == "BTS:AB") || ($name == "BTS:BX") || ($name == "BTS:BB1") || ($name == "BTS:CB1")} {
            lappend magnets(dipole) $name
        } elseif {([string range $name 2 3] == "ES") || ([string range $name 4 9] == "IES:IS")} {
            lappend magnets(septum) $name
        } elseif {([string range $name 4 9] == "IES:IK") || ([string range $name 4 9] == "IES:DK") || ([string range $name 2 3] == "EK")} {
            lappend magnets(kicker) $name
        } else {
            return -code error "APSUBtsDcpsAction: $name is an unknown power supply"
        }
    }

    if {[catch {APSGetMagnetPVNamesAndInfo -arrayName magnetPVs} results]} {
        puts "Error: $results"
        exit
    }
    
    if {($action == "on")} {
        if {[catch {APSUBtsDcpsTurnRawsOn} result]} {
            return -code error $result
        }
        if {([llength $magnets(kicker)] || [llength $magnets(septum)])} {
            foreach n "IK1 IK2 IK3 DK0 EK IS1 ES1 ES2" magnet "S39-IES:IK1 S39-IES:IK2 S39-IES:IK3 S38-IES:DK0 B:EK S39-IES:IS1 B:ES1 B:ES2" {
                set i [lsearch -exact $names $magnet]
                if {$i != -1} {
                    set $n 1
                    set names [lreplace $names $i $i]
                } else {
                    set $n 0
                }
            }
            if {[catch {APSMpSRTurnOnKickers -IK1 $IK1 -IK2 $IK2 -IK3 $IK3 -DK0 $DK0 -EK $EK -IS1 $IS1 -ES1 $ES1 -ES2 $ES2} results]} {
                return -code error "APSUBtsDcpsAction: $results"
            }
            if {[llength $names] == 0} {
                return
            }
        }
    }
    if {($action == "off") || ($action == "forcecondition")} {
        if {[catch {APSUBtsCheckForDipoleSwitching} result]} {
            return -code error $result
        }
    }
    if {($action == "off")} {
        if {([llength $magnets(kicker)] || [llength $magnets(septum)])} {
            foreach n "IK1 IK2 IK3 DK0 EK IS1 ES1 ES2" magnet "S39-IES:IK1 S39-IES:IK2 S39-IES:IK3 S38-IES:DK0 B:EK S39-IES:IS1 B:ES1 B:ES2" {
                set i [lsearch -exact $names $magnet]
                if {$i != -1} {
                    set $n 1
                    set names [lreplace $names $i $i]
                } else {
                    set $n 0
                }
            }
            if {[catch {APSMpSRTurnOffKickers -IK1 $IK1 -IK2 $IK2 -IK3 $IK3 -DK0 $DK0 -EK $EK -IS1 $IS1 -ES1 $ES1 -ES2 $ES2} results]} {
                return -code error "APSUBtsDcpsAction: $results"
            }
            if {[llength $names] == 0} {
                return
            }
        }
    }
    if {($action == "ccmode")} {
        set newNames [list ]
        foreach name $names {
            if {[string match BTS:?Q? $name] || [string match BTS:\[BC\]B1 $name] || [string match BTS:BSQ? $name]} {
                lappend newNames $name
            }
        }
        set names $newNames
        if ![llength $names] return
    }
    set try 1
    while {$try <= $maxTries} {
        if {($action == "on") || ($action == "off")} {
            set poweredOnList ""
            set poweredOffList ""
            foreach name $names {
                if [catch {eval APScavget -printError -num -pend=2 -list=$magnetPVs(${name}.statusPV)} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
                if {$result == $magnetPVs(${name}.statusOnValue)} {
                    lappend poweredOnList $name
                } else {
                    lappend poweredOffList $name
                }
            }
        }
        
        if {$action == "on"} {
            if {[llength $poweredOffList] == 0} {
                return
            } elseif {$try == $maxTries} {
                return -code error "APSUBtsDcpsAction: Unable to turn on: $poweredOffList"
            }
            if {$try == [expr $maxTries - 1]} {
                foreach name $poweredOffList {
                    if [catch {APScavput -pend=1 -blunder=silent -list=$magnetPVs(${name}.turnOnPV)=$magnetPVs(${name}.turnOnValue)} result] {
                        return -code error "APSUBtsDcpsAction: $result"
                    }
                    after 10
                }
            } else {
                if {$try == 1} {
                    set pvValueList ""
                    foreach name $poweredOffList {
                        if {[llength $magnetPVs(${name}.setCurrentPV)]} {
                            lappend pvValueList "$magnetPVs(${name}.setCurrentPV)=0"
                        }
                    }
                    if {[llength $pvValueList]} {
                        if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                            return -code error "APSUBtsDcpsAction: $result"
                        }
                        after 1000
                    }
                }
                set pvValueList ""
                foreach name $poweredOffList {
                    if {$magnetPVs(${name}.turnOnPV) != $magnetPVs(${name}.resetPV)} {
                        lappend pvValueList "$magnetPVs(${name}.resetPV)=$magnetPVs(${name}.resetValue)"
                    }
                }
                if {[llength $pvValueList]} {
                    foreach pvvl $pvValueList {
                        if {[catch {APScavput -pend=1 -blunder=silent -list=$pvvl -pend=1} result]} {
                            return -code error "APSUBtsDcpsAction: $result"
                        }
                    }
                    after 1000
                }
                set pvValueList ""
                foreach name $poweredOffList {
                    lappend pvValueList "$magnetPVs(${name}.turnOnPV)=$magnetPVs(${name}.turnOnValue)"
                }
                foreach pvvl $pvValueList {
                    if {[catch {APScavput -pend=1 -blunder=silent -list=$pvvl -pend=1} result]} {
                        return -code error "APSUBtsDcpsAction: $result"
                    }
                }
                after 7000
            }
            incr try
        } elseif {$action == "off"} {
            if {[llength $poweredOnList] == 0} {
                return
            } elseif {$try == $maxTries} {
                return -code error "APSUBtsDcpsAction: Unable to turn off: $poweredOnList"
            }
            if {$try == [expr $maxTries - 1]} {
                foreach name $poweredOnList {
                    if [catch {APScavput -pend=1 -blunder=silent -list=$magnetPVs(${name}.turnOffPV)=$magnetPVs(${name}.turnOffValue)} result] {
                        return -code error "APSUBtsDcpsAction: $result"
                    }
                    after 10
                }
            } else {
                if {$try == 1} {
                    #Ramp down the current on the supplies
                    set pvValueList ""
                    foreach name $poweredOnList {
                        if {[llength $magnetPVs(${name}.setCurrentPV)]} {
                            lappend pvValueList "$magnetPVs(${name}.setCurrentPV)=0"
                        }
                    }
                    if {[llength $pvValueList]} {
                        if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                            return -code error "APSUBtsDcpsAction: $result"
                        }
                    }
                    set pvList ""
                    foreach name $poweredOnList {
                        if {[llength $magnetPVs(${name}.readCurrentPV)]} {
                            lappend pvList "$magnetPVs(${name}.readCurrentPV)"
                        }
                    }
                    set powerDownTry 1
                    while {1} {
                        APSWaitWithUpdate -waitSeconds 1
                        set suppliesWithPower ""
                        if {[catch {APScavget -printError -num -pend=2 -list=[join $pvList ,]} result]} {
                            return -code error "APSUBtsDcpsAction: $result"
                        }
                        foreach pv $pvList val $result {
                            if {$val > 1} {
                                lappend suppliesWithPower $pv
                            }
                        }
                        if {[llength $suppliesWithPower] == 0} {
                            break
                        }
                        if {$powerDownTry > 20} {
                            return -code error "APSUBtsDcpsAction: $suppliesWithPower BTS power supplies are not going to 0 amps prior to shutdown"
                        }                   
                        incr powerDownTry
                    }
                }
                #Turn the supplies off
                set pvValueList ""
                foreach name $poweredOnList {
                    lappend pvValueList "$magnetPVs(${name}.turnOffPV)=$magnetPVs(${name}.turnOffValue)"
                }
                foreach pvvl $pvValueList {
                    if {[catch {APScavput -pend=1 -blunder=silent -list=$pvvl -pend=1} result]} {
                        return -code error "APSUBtsDcpsAction: $result"
                    }
                }
                after 2000
            }
            incr try
        } elseif {$action == "ccmode"} {
            set pvValueList1 [list ]
            set pvValueList2 [list ]
            set pvValueList3 [list ]
            foreach name $names {
                lappend pvValueList1 $name:PS:SetCurrentC=0
                lappend pvValueList2 $name:PS:CCModeC.PROC=1
                lappend pvValueList3 $name:PS:ConstantCurrentM
            }
            if {[llength $pvValueList1]} {
                if [catch {APScavput -pend=1 -list=[join $pvValueList1 ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
                after 1000
                if [catch {APScavput -pend=1 -list=[join $pvValueList2 ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
                after 5000
                if [catch {APScavget -pend=1 -label=1 -list=[join $pvValueList3 ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
                return "$result"
            }
            return
        } elseif {$action == "set"} {
            set pvValueList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.setCurrentPV)]} {
                    lappend pvValueList "$magnetPVs(${name}.setCurrentPV)=$value"
                } elseif {[llength $magnetPVs(${name}.setVoltagePV)]} {
                    lappend pvValueList "$magnetPVs(${name}.setVoltagePV)=$value"
                }
            }
            if {[llength $pvValueList]} {
                if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            return
        } elseif {$action == "read"} {
            set pvValueList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.readCurrentPV)]} {
                    lappend pvValueList "$magnetPVs(${name}.readCurrentPV)"
                } elseif {[llength $magnetPVs(${name}.readVoltagePV)]} {
                    lappend pvValueList "$magnetPVs(${name}.readVoltagePV)"
                }
            }
            if {[llength $pvValueList]} {
                if [catch {APScavget -pend=1 -label=1 -list=[join $pvValueList ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            return $result
        } elseif {$action == "setcycles"} {
            set pvValueList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.setConditioningCyclesPV)]} {
                    lappend pvValueList "$magnetPVs(${name}.setConditioningCyclesPV)=$value"
                }
            }
            if {[llength $pvValueList]} {
                if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            return
        } elseif {$action == "configure"} {
            set configFile1 [APSTmpDir]/[APSTmpString]

            set matchOption "-match=column,ControlName=[lindex $names 0]"
            foreach name [lrange $names 1 end] {
                append matchOption ",ControlName=${name},|"
            }

            #degauss
            set configFile "/home/helios/oagData/bts/magnetConditioning/degauss.config"
            if {[catch {exec sddsprocess $configFile $configFile1 $matchOption -nowarnings} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {[catch {exec sdds2stream -rows=bare $configFile1} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {$result > 0} {
                if {[catch {exec degauss -configure $configFile1} result]} {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            file delete $configFile1
            
            #triDegauss
            set configFile "/home/helios/oagData/bts/magnetConditioning/triDegauss.config"
            if {[catch {exec sddsprocess $configFile $configFile1 $matchOption -nowarnings} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {[catch {exec sdds2stream -rows=bare $configFile1} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {$result > 0} {
                if {[catch {exec degauss -configure $configFile1} result]} {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            file delete $configFile1
            
            #standardize
            if {0} {
            set configFile "/home/helios/oagData/bts/magnetConditioning/standardize.config"
            if {[catch {exec sddsprocess $configFile $configFile1 $matchOption -nowarnings} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {[catch {exec sdds2stream -rows=bare $configFile1} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {$result > 0} {
                if {[catch {exec standardize -configure $configFile1} result]} {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            file delete $configFile1
            }

            #standardize
            set configFile "/home/helios/oagData/bts/magnetConditioning/standardizeDwell.config"
            if {[catch {exec sddsprocess $configFile $configFile1 $matchOption -nowarnings} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {[catch {exec sdds2stream -rows=bare $configFile1} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            if {$result > 0} {
                if {[catch {exec standardize -configure $configFile1} result]} {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            file delete $configFile1
            return
        } elseif {$action == "forcecondition"} {
            if {[catch {APSUBtsDcpsPreCondition -arrayName magnets} result]} {
                return -code error "APSUBtsDcpsAction: $result"
            }
            set pvValueList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.startConditioningPV)]} {
                    lappend pvValueList "$magnetPVs(${name}.startConditioningPV)=1"
                }
            }
            if {[llength $pvValueList]} {
                if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            return
        } elseif {$action == "stopcond"} {
            set pvValueList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.startConditioningPV)]} {
                    lappend pvValueList "$magnetPVs(${name}.startConditioningPV)=0"
                }
            }
            if {[llength $pvValueList]} {
                if [catch {APScavput -pend=1 -blunder=silent -list=[join $pvValueList ,]} result] {
                    return -code error "APSUBtsDcpsAction: $result"
                }
            }
            return
        } elseif {$action == "listcond"} {
            set condnames ""
            set pvList ""
            foreach name $names {
                if {[llength $magnetPVs(${name}.startConditioningPV)]} {
                    lappend pvList $magnetPVs(${name}.startConditioningPV)
                }
            }
            if {[llength $pvList]} {
                if {[catch {APScavget -printError -pend=2 -list=[join $pvList ,]} result]} {
                    return -code error "APSUBtsDcpsAction: $result"
                }
                foreach name $names val $result {
                    if {$val != 0} {
                        lappend condnames $name
                    }
                }
            }
            return -code ok $condnames
        } else {
            return
        }
    }
    if {($action == "off")} {
        #FIX THIS, If all booster side was selected, then turn off BTS:RBO
        #          If all sr side was selected, then turn off BTS:RSR.
    }
}

proc APSUBtsDcpsPreCondition {args} {
    upvar names vn
    set arrayName magnets
    APSStrictParseArguments {arrayName}

    upvar 1 $arrayName magnets
    set options ""
    set removeList ""
    foreach ps $magnets(unipolar) {
        switch $ps {
            "BTS:CQ1" {
                lappend removeList BTS:CQ1H
                lappend options "BTS:CQ1:StandardizeC.OUTB=BTS:CQ1H:StandardizeC.PROC"
                lappend options "BTS:CQ1:StandardizeC.OUTC=BTS:CQ1H:PS:SetCurrentC"
                lappend options "BTS:CQ1:StandardizeC.OUTD=\"\""
            }
            "BTS:CQ2" {
                lappend removeList BTS:CQ2V
                lappend options "BTS:CQ2:StandardizeC.OUTB=BTS:CQ2V:StandardizeC.PROC"
                lappend options "BTS:CQ2:StandardizeC.OUTC=BTS:CQ2V:PS:SetCurrentC"
                lappend options "BTS:CQ2:StandardizeC.OUTD=\"\""
            }
            "BTS:CQ3" {
                lappend removeList BTS:CQ3H
                lappend options "BTS:CQ3:StandardizeC.OUTB=BTS:CQ3H:StandardizeC.PROC"
                lappend options "BTS:CQ3:StandardizeC.OUTC=BTS:CQ3H:PS:SetCurrentC"
                lappend options "BTS:CQ3:StandardizeC.OUTD=\"\""
            }
            "BTS:DQ1" {
                lappend removeList BTS:DQ1H
                lappend options "BTS:DQ1:StandardizeC.OUTB=BTS:DQ1H:StandardizeC.PROC"
                lappend options "BTS:DQ1:StandardizeC.OUTC=BTS:DQ1H:PS:SetCurrentC"
                lappend options "BTS:DQ1:StandardizeC.OUTD=\"\""
            }
            "BTS:DQ2" {
                lappend removeList BTS:DQ2V
                lappend options "BTS:DQ2:StandardizeC.OUTB=BTS:DQ2V:StandardizeC.PROC"
                lappend options "BTS:DQ2:StandardizeC.OUTC=BTS:DQ2V:PS:SetCurrentC"
                lappend options "BTS:DQ2:StandardizeC.OUTD=\"\""
            }
            "BTS:BSQ1" {
                lappend removeList BTS:BSQ1H
                lappend options "BTS:BSQ1:StandardizeC.OUTB=BTS:BSQ1H:StandardizeC.PROC"
                lappend options "BTS:BSQ1:StandardizeC.OUTC=BTS:BSQ1H:PS:SetCurrentC"
                lappend options "BTS:BSQ1:StandardizeC.OUTD=\"\""
            }
            "BTS:BSQ2" {
                lappend removeList BTS:BSQ2V
                lappend options "BTS:BSQ2:StandardizeC.OUTB=BTS:BSQ2V:StandardizeC.PROC"
                lappend options "BTS:BSQ2:StandardizeC.OUTC=BTS:BSQ2V:PS:SetCurrentC"
                lappend options "BTS:BSQ2:StandardizeC.OUTD=\"\""
            }
            "BTS:BSQ5" {
                lappend removeList BTS:BSQ5H
                lappend options "BTS:BSQ5:StandardizeC.OUTB=BTS:BSQ5H:StandardizeC.PROC"
                lappend options "BTS:BSQ5:StandardizeC.OUTC=BTS:BSQ5H:PS:SetCurrentC"
                lappend options "BTS:BSQ5:StandardizeC.OUTD=\"\""
            }
            "BTS:BSQ6" {
                lappend removeList BTS:BSQ6V
                lappend options "BTS:BSQ6:StandardizeC.OUTB=BTS:BSQ6V:StandardizeC.PROC"
                lappend options "BTS:BSQ6:StandardizeC.OUTC=BTS:BSQ6V:PS:SetCurrentC"
                lappend options "BTS:BSQ6:StandardizeC.OUTD=\"\""
            }
        }
    }
    foreach ps $removeList {
        set i [lsearch -exact $vn $ps]
        if {$i != -1} {
            set vn [lreplace $vn $i $i]
        }
    }
    if {[llength $options]} {
        catch {APScavput -list=[join $options ,]}
        after 1000
    }
}


proc APSUBtsDcpsTurnRawsOn {} {
    if {[catch {APSGetMagnetPVNamesAndInfo -arrayName magnetPVs -beamline BTS -type raw} magnets]} {
        return -code error "APSUBtsDcpsTurnRawsOn: $magnets"
        exit
    }

    foreach raw $magnets {
        if {[catch {APScavget -num -printErrors -pend=2 -list=$magnetPVs(${raw}.statusPV)} status]} {
            return -code error "APSUBtsDcpsTurnRawsOn: $status"
        }
        if {$status != $magnetPVs(${raw}.statusOnValue)} {
            if {[catch {APScavput -pend=2 -list=$magnetPVs(${raw}.setVoltagePV)=0.0} result]} {
                return -code error "APSUBtsDcpsTurnRawsOn: $result"
            }
            after 1000
            if {[catch {APScavput -pend=2 -list=$magnetPVs(${raw}.resetPV)=$magnetPVs(${raw}.resetValue)} result]} {
                return -code error "APSUBtsDcpsTurnRawsOn: $result"
            }
            after 1000
            if {[catch {APScavput -pend=2 -list=$magnetPVs(${raw}.setVoltagePV)=65.0} result]} {
                return -code error "APSUBtsDcpsTurnRawsOn: $result"
            }
        }
    }
}

proc APSUBtsCheckForDipoleSwitching {args} {
    if {[catch {APScavget -printErrors -pend=2 -num -list=BTS:DipoleSwitchingC} status]} {
        return -code error "APSUBtsCheckForDipoleSwitching: $status"
    }
    if {$status} {
        return -code error "APSUBtsCheckForDipoleSwitching: Dipole switching is still ongoing"
    }
}

