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

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 debug 0

puts "Running...this will take a long time to execute"

proc RemoveLineContinues {f} {
    set fid [open $f r]
    set data [read -nonewline $fid]
    close $fid
    set data [split $data \n]
    set output ""
    foreach line $data {
        set l [string trimright $line]
        if {[string compare [string index $l end] \\] == 0} {
            append output [string range $l 0 end-1]
        } else {
            append output "${line}\n"
        }
    }
    set fid [open /tmp/findPVs/[file tail $f] w]
    puts $fid $output
    close $fid
}

proc GetPVNames {args} {
    set names ""
    set options(number) 0
    set repeats 0
    foreach option $args {
        if {[string compare [string index $option 0] "-"] == 0} {
            set i [string first "=" $option]
            if {$i == -1} {
                set options($options(number)) [string range $option 1 end]
                set options($options(number),number) 0
            } else {
                set options($options(number)) [string range $option 1 [expr {$i - 1}]]
                set j 0
                set options($options(number),number) $j
                set option [string range $option [expr {$i + 1}] end]
                set i [string first "," $option]
                set ii [string first "=" $option]
                if {($i == -1) || (($ii > -1) && ($ii < $i))} {
                    set i $ii
                }
                while {$i != -1} {
                    set options($options(number),$j) [string range $option 0 [expr {$i - 1}]]
                    set option [string range $option [expr {$i + 1}] end]
                    incr j
                    set options($options(number),number) $j
                    set i [string first "," $option]
                    set ii [string first "=" $option]
                    if {($i == -1) || (($ii > -1) && ($ii < $i))} {
                        set i $ii
                    }
                }
                set options($options(number),$j) $option
                incr j
                set options($options(number),number) $j
            }
            incr options(number)
        } else {
            puts stderr "Warning: Unknown option: $option"
        }
    }
    set listOption(number) 0
    for {set i 0} {$i < $options(number)} {incr i} {
        if {[string compare -nocase -length [string length $options($i)] $options($i) "list"] == 0} {
            set n 0
            set listOption($listOption(number),number) $n
            for {set j 0} {$j < $options($i,number)} {incr j} {
                set listOption($listOption(number),$n) $options($i,$j)
                incr n
                set listOption($listOption(number),number) $n
            }
            incr listOption(number)
        } elseif {[string compare -nocase -length [string length $options($i)] $options($i) "range"] == 0} {
            set range(begin) ""
            set range(end) ""
            set range(format) ""
            set range(interval) "1"
            for {set j 0 ; set jj 1} {$j < $options($i,number)} {incr j 2 ; incr jj 2} {
                if {[string compare -nocase -length [string length $options($i,$j)] $options($i,$j) "begin"] == 0} {
                    set range(begin) $options($i,$jj)
                    if {![string is integer -strict $range(begin)]} {
                        set range(begin) 1
                    }
                } elseif {[string compare -nocase -length [string length $options($i,$j)] $options($i,$j) "end"] == 0} {
                    set range(end) $options($i,$jj)
                    if {![string is integer -strict $range(end)]} {
                        set range(end) 1
                    }
                } elseif {[string compare -nocase -length [string length $options($i,$j)] $options($i,$j) "format"] == 0} {
                    set range(format) $options($i,$jj)
                } elseif {[string compare -nocase -length [string length $options($i,$j)] $options($i,$j) "interval"] == 0} {
                    set range(interval) $options($i,$jj)
                    if {![string is integer -strict $range(interval)]} {
                        set range(interval) 1
                    }
                }
            }
            if {([string length $range(begin)]) && ([string length $range(end)])} {
                if {($range(interval) > 0) && ($range(begin) > $range(end))} {
                    return -code error "APScavget: invalid -range syntax"
                }
                if {($range(interval) < 0) && ($range(begin) < $range(end))} {
                    return -code error "APScavget: invalid -range syntax"
                }
                if {($range(interval) == 0) && ($range(begin) != $range(end))} {
                    return -code error "APScavget: invalid -range syntax"
                }
                set n 0
                set listOption($listOption(number),number) $n
                for {set j $range(begin)} {$j <= $range(end)} {incr j $range(interval)} {
                    if {[string length $range(format)]} {
                        set listOption($listOption(number),$n) [format $range(format) $j]
                    } else {
                        set listOption($listOption(number),$n) $j
                    }
                    incr n
                    set listOption($listOption(number),number) $n
                }
                incr listOption(number)
            }
        }
    }
    set num $listOption(0,number)
    for {set i 0} {$i < $listOption(0,number)} {incr i} {
        set listVar($i) $listOption(0,$i)
        set listVar($i,tmp) $listVar($i)
    }
    for {set n 1} {$n < $listOption(number)} {incr n} {
        for {set i 0 ; set k 0} {$i < $num} {incr i} {
            for {set j 0} {$j < $listOption($n,number)} {incr j ; incr k} {
                set listVar($k) "$listVar($i,tmp)$listOption($n,$j)"
            }
        }
        for {set i 0 ; set k 0} {$i < $num} {incr i} {
            for {set j 0} {$j < $listOption($n,number)} {incr j ; incr k} {
                set listVar($k,tmp) $listVar($k)
            }
        }
        set num [expr {$num * $listOption($n,number)}]        
    }
    for {set i 0} {$i < $num} {incr i} {
        append names "[file rootname $listVar($i)] "
    }
    return $names
}

proc CheckoutAndBuildOAG {args} {
    global env

    exec rm -rf /tmp/oagsoftware
    exec mkdir /tmp/oagsoftware
    cd /tmp/oagsoftware
    
    if {[catch {exec svn -q checkout https://svn.aps.anl.gov/AOP/oag/trunk/apps/src/tcltkapp/oagapp oag/apps/src/tcltkapp/oagapp} results]} {
        puts stderr "error: $results"
        exit
    }
    if {[catch {exec svn -q checkout https://svn.aps.anl.gov/AOP/oag/trunk/apps/src/tcltklib oag/apps/src/tcltklib} results]} {
        puts stderr "error: $results"
        exit
    }
    if {[catch {exec svn -q checkout https://svn.aps.anl.gov/AOP/oag/trunk/apps/src/mplib oag/apps/src/mplib} results]} {
        puts stderr "error: $results"
        exit
    }
}

proc PrepairFiles {args} {
    CheckoutAndBuildOAG
    set files [glob -nocomplain -type f /tmp/oagsoftware/oag/apps/src/tcltkapp/oagapp/* /tmp/oagsoftware/oag/apps/src/tcltklib/* /tmp/oagsoftware/oag/apps/src/mplib/*/*]
    exec rm -rf /tmp/findPVs
    if {![file exists /tmp/findPVs]} {
        exec mkdir /tmp/findPVs
    }
    foreach f $files {
        RemoveLineContinues $f
    }
}

proc CheckCavget {args} {
    set files [glob -nocomplain -type f /tmp/findPVs/*]

    set data [eval exec fgrep {" cavget "} $files]\n[eval exec fgrep {"APScavget "} $files]
    
    set data [split $data \n]
    
    set names ""
    set filenames ""
    foreach line $data {
        set line [split $line]
        set filename [file tail [lindex $line 0]]
        set i [string first ":" $filename]
        incr i -1
        set filename [string range $filename 0 $i]
        set ignore 0
        set output ""
        set count 0
        foreach element $line {
            if {[string range $element 0 5] == "-list="} {
                if {([string first \[ $element] != -1) || \
                      ([string first \{ $element] != -1) || \
                      ([string first \$ $element] != -1)} {
                    set ignore 1
                    break
                }
                while {([string compare [string index $element end] \}] == 0) || \
                         ([string compare [string index $element end] \]] == 0) || \
                         ([string compare [string index $element end] \"] == 0)} {
                    set element [string range $element 0 end-1]
                }
                append output "$element "
            } elseif {[string range $element 0 6] == "-range="} {
                if {([string first \[ $element] != -1) || \
                      ([string first \{ $element] != -1) || \
                      ([string first \$ $element] != -1)} {
                    set ignore 1
                    break
                }
                while {([string compare [string index $element end] \}] == 0) || \
                         ([string compare [string index $element end] \]] == 0) || \
                         ([string compare [string index $element end] \"] == 0)} {
                    set element [string range $element 0 end-1]
                }
                append output "$element "
            } elseif {[string range $element 0 3] == "-dry"} {
                set ignore 1
                break
            } elseif {([string first "cavget" $element] != -1) || ([string first "cavput" $element] != -1)} {
                incr count
                if {$count > 1} {
                    if {(!$ignore) && ([string length $output] != 0)} {
                        set tmp [eval GetPVNames $output]
                        append names "$tmp "
                        for {set i 0} {$i < [llength $tmp]} {incr i} {
                            append filenames "$filename "
                        }
                    }
                    set ignore 0
                    set output ""
                }
            } elseif {[string range $element 0 0] != "-"} {
                if {[string first \$ $element] != -1} {
                    set ignore 1
                    break
                }
            }
            
        }
        if {(!$ignore) && ([string length $output] != 0)} {
            set tmp [eval GetPVNames $output]
            append names "$tmp "
            for {set i 0} {$i < [llength $tmp]} {incr i} {
                append filenames "$filename "
            }
        }
    }
    return [list $names $filenames]
#    return [lsort -dictionary -unique $names]
}

proc CheckCavput {args} {
    set files [glob -nocomplain -type f /tmp/findPVs/*]
    
    set data [eval exec fgrep {" cavput "} $files]\n[eval exec fgrep {"APScavput "} $files]

    set data [split $data \n]

    set names ""
    set filenames ""
    foreach line $data {
        set line [split $line]
        set filename [file tail [lindex $line 0]]
        set i [string first ":" $filename]
        incr i -1
        set filename [string range $filename 0 $i]
        set ignore 0
        set output ""
        set count 0
        set string 0
        set compoundElement ""
        foreach element $line {
            if {[string compare [string index $element 0] \"] == 0} {
                if {$string == 0} {
                    if {[string compare [string index $element end] \"] == 0} {
                        set element [string range $element 1 end-1]
                    } else {
                        append compoundElement [string range $element 1 end]
                        set string 1
                        continue
                    }
                }
            } elseif {[string compare [string index $element end] \"] == 0} {
                if {$string == 1} {
                    append compoundElement " [string range $element 0 end-1]"
                    set element $compoundElement
                    set string 0
                    set compoundElement ""
                }
            } elseif {$string == 1} {
                append compoundElement " $element"
            }
            
            if {[string range $element 0 5] == "-list="} {
                if {([string first \[ $element] != -1) || \
                      ([string first \{ $element] != -1)} {
                    set ignore 1
                    break
                }
                while {([string compare [string index $element end] \}] == 0) || \
                         ([string compare [string index $element end] \]] == 0) || \
                         ([string compare [string index $element end] \"] == 0)} {
                    set element [string range $element 0 end-1]
                }
                set i [string first = [string range $element 6 end]]
                if {$i != -1} {
                    incr i 5
                    set element [string range $element 0 $i]
                }
                if {[string first \$ $element] != -1} {
                    set ignore 1
                    break
                }
                append output "$element "
            } elseif {[string range $element 0 6] == "-range="} {
                if {([string first \[ $element] != -1) || \
                      ([string first \{ $element] != -1) || \
                      ([string first \$ $element] != -1)} {
                    set ignore 1
                    break
                }
                while {([string compare [string index $element end] \}] == 0) || \
                         ([string compare [string index $element end] \]] == 0) || \
                         ([string compare [string index $element end] \"] == 0)} {
                    set element [string range $element 0 end-1]
                }
                append output "$element "
            } elseif {[string range $element 0 3] == "-dry"} {
                set ignore 1
                break
            } elseif {([string first "cavput" $element] != -1) || ([string first "cavget" $element] != -1)} {
                incr count
                if {$count > 1} {
                    if {(!$ignore) && ([string length $output] != 0)} {
                        set tmp [eval GetPVNames $output]
                        append names "$tmp "
                        for {set i 0} {$i < [llength $tmp]} {incr i} {
                            append filenames "$filename "
                        }
                    }
                    set ignore 0
                    set output ""
                }
            } elseif {[string range $element 0 0] != "-"} {
                if {[string first \$ $element] != -1} {
                    set ignore 1
                    break
                }
            }
            
        }
        if {(!$ignore) && ([string length $output] != 0)} {
            set tmp [eval GetPVNames $output]
            append names "$tmp "
            for {set i 0} {$i < [llength $tmp]} {incr i} {
                append filenames "$filename "
            }
        }
    }
    return [list $names $filenames]
}

proc CheckTclScripts {} {
    global debug
    set files [glob -nocomplain -type f /tmp/findPVs/*]

    file delete -force /tmp/findPVs/HugeFile
    foreach f $files {
        set fid [open $f r]
        set data [read $fid]
        close $fid
        set output ""
        foreach line [split $data \n] {
            append output "$f $line\n"
        }
        set fid [open /tmp/findPVs/HugeFile a]
        puts $fid $output
        close $fid
    }

    if {[catch {exec sdds2stream /home/helios/oagData/pvdata/iocRecNamesOAG.sdds -col=rec_name} pvNames]} {
        puts stderr "Error: $pvNames"
        exit
    }
    
    set tmpName /tmp/[APSTmpString]
    set num 100000
    while {$num >=10} {
        set subPVNames ""
        set count [llength $pvNames]
        set i 0
        set j 0
        set output ""
        foreach pvName $pvNames {
            incr i
            incr j
            if {$i == 1} {
                file delete $tmpName
                set fid [open $tmpName "w"]
                set pvlist ""
            }
            if {($i == $num) || ($j == $count)} {
                puts -nonewline $fid $pvName
                append pvlist "$pvName "
                close $fid
                set i 0;
                if {$debug} {
                    puts "Searching $num PVs at a time ($j of $count)"
                }
                if {[catch {eval exec fgrep -f $tmpName /tmp/findPVs/HugeFile} results]} {
                    if {$results == "child process exited abnormally"} {
                    } else {
                        puts "$results"
                    }
                } else {
                    if {$num == 100000} {
                        append output "${results}\n"
                    }
                    append subPVNames "$pvlist "
                }
            } else {
                puts $fid $pvName
                append pvlist "$pvName "
            }
        }
        if {$num == 100000} {
            set fid [open /tmp/findPVs/HugeFile w]
            puts $fid $output
            close $fid
        }
        set num [expr {$num / 10}]
        set pvNames $subPVNames
    }
    file delete -force $tmpName

    set names ""
    set filenames ""
    set count [llength $pvNames]
    set j 0
    foreach pvName $pvNames {
        incr j
        if {$debug} {
            puts "Searching 1 PVs at a time ($j of $count)"
        }
	if {[string first \; $pvName] >= 0} { continue }
        if {[catch {eval exec fgrep $pvName /tmp/findPVs/HugeFile} results]} {
            if {$results == "child process exited abnormally"} {
            } else {
                puts "$results"
            }
        } else {
            foreach f [split $results \n] {
                append names "$pvName "
                set i [string first " " $f]
                incr i -1                
                append filenames "[file tail [string range $f 0 $i]] "
            }
        }
    }
    file delete -force /tmp/findPVs/HugeFile

    return [list $names $filenames]
}

proc CleanUpFiles {args} {
    cd /tmp
    exec rm -rf /tmp/oagsoftware
    exec rm -rf /tmp/findPVs
}

APSStandardSetup

PrepairFiles

set tmp [CheckTclScripts]
set tclPVnames [lindex $tmp 0]
set tclPVfiles [lindex $tmp 1]

set tmp [CheckCavget]
set cavgetPVnames [lindex $tmp 0]
set cavgetPVfiles [lindex $tmp 1]

set tmp [CheckCavput]
set cavputPVnames [lindex $tmp 0]
set cavputPVfiles [lindex $tmp 1]

CleanUpFiles

set allPVs "$cavgetPVnames $cavputPVnames $tclPVnames"
set allFiles "$cavgetPVfiles $cavputPVfiles $tclPVfiles"

set allPVsData(ColumnNames) "ControlName Filename"
set allPVsData(Column.ControlName) [list $allPVs]
set allPVsData(Column.Filename) [list $allFiles]

sdds save /tmp/allPVs allPVsData

set outputDir /home/helios/oagData/dataLoggerConfig
if {$env(USER) != "oag"} {
    puts "Changing output directory because you are not logged in as oag"
    set outputDir /tmp
}

if {[catch {exec sddsselect /tmp/allPVs /home/helios/oagData/pvdata/iocRecNamesOAG.sdds \
              -pipe=out -match=ControlName=rec_name -nowarning -reuse | \
              sddssort -pipe=in ${outputDir}/oagTclPVs.sdds -col=ControlName -col=Filename -unique -num} results]} {
    puts stderr "Error: $results"
    exit
}

if {$debug} {
    if {[catch {exec sddsselect /tmp/allPVs /home/helios/oagData/pvdata/iocRecNamesOAG.sdds \
                  -pipe=out -match=ControlName=rec_name -nowarning -reuse -invert | \
                  sddssort -pipe=in /tmp/allBadPVs -col=ControlName -col=Filename -unique -num} results]} {
        puts stderr "Error: $results"
        exit
    }
}

file delete /tmp/allPVs

puts "Data written to ${outputDir}/oagTclPVs.sdds"