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

#
# $Log: not supported by cvs2svn $
# Revision 1.8  1998/09/04 15:02:54  borland
# Added a newline to avoid CVS warning message.
#
# Revision 1.7  1998/09/04 15:02:35  borland
# Per D. Blachowicz: Added exclude capability for searches.  Exclude may
# be used by itself to search the whole database for non-matches.
#
# Revision 1.6  1998/04/21 16:10:11  borland
# Fixed a Tcl 8.0-related bug in a set expression.
#
# Revision 1.5  1997/07/23 17:34:53  borland
# Added ability to launch probe for a PV by double-clicking.
#
# Revision 1.4  1997/07/23 14:01:48  borland
# Fixed append feature.
#
# Revision 1.3  1997/07/23 13:34:30  borland
# Added more features to file writing.  Now does appending and adds
# ControlType column for use with burtrb.
#
# Revision 1.2  1997/07/22 22:47:14  borland
# Added ability to write out the search results to an SDDS file.
#
# Revision 1.1  1996/10/07 14:31:36  saunders
# Moved pv name browser from epics/extensions to here.
#
#

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 origDir [pwd]

set CVSRevisionAuthor "\$Revision: 1.9 $ \$Author: borland $"

APSApplication . -name "Process Variable Browser" \
  -version $CVSRevisionAuthor -overview "Allows you to find process variable names and the IOCs in which they reside." \
  -contextHelp "This application allows you to find process variable names and the IOC's in which they reside."

# Set these paths to location of pv and ioc data directories
if {$apsUpgrade} {
    set pvdata_path "/C2/iocinfo/pvdata"
    if {[info exists "/C2/iocinfo/pvadata"]} {
        set pvadata_path "/C2/iocinfo/pvadata"
    } else {
        set pvadata_path "/net/ajax/iocinfo/pvadata"
    }
  set iocdata_path ""
} else {
  set pvdata_path "/home/helios/iocinfo/pvdata"
  set iocdata_path "/home/helios/iocinfo/iocdata"
  set pvadata_path ""
}

set pvsearch_debug 0
set cancelsearch 0
set iocname ""
set roomname ""
set rackname ""
set outputFile ""
set pvexclude ""


set status "Enter PV Name or Pattern"
APSLabeledOutput .status -parent .userFrame -label Status: \
  -textVariable status -width 40
APSLabeledEntry .entry -parent .userFrame -label "PV Name:" \
  -textVariable pvname -width 40 -contextHelp "Enter PV name or \
  patern to match."
APSLabeledEntry .exclude -parent .userFrame -label "Exclude:" \
  -textVariable pvexclude -width 40 -contextHelp "Enter PV name or \
  patern to exclude from the matching list. A list of PVs not matching \
  an exclusion string is going to be display if matching string is not present."

APSButton .invokesearch -parent .userFrame -text "Invoke Search" -packOption \
  "-side top -padx 1 -pady 1 -fill x" -command "pv_matchInvoke" \
  -contextHelp "Starting searching for an entered PV or patern."
APSButton .cancelsearch -parent .userFrame -text "Cancel Search" -packOption \
  "-side top -padx 1 -pady 1 -fill x" -command "set cancelsearch 1" \
  -contextHelp "Stops searching procedure."

APSFrame .output -parent .userFrame -label "Output to file"
set w .userFrame.output.frame
APSLabeledEntry .name -parent $w -label "Name: " \
  -textVariable outputFile -width 40 -contextHelp \
  "Give the name of a file to which to write search results."
APSButton .write -parent $w -text "Write" \
  -command {WriteOutSearch -fileName $outputFile -append 0} \
  -contextHelp "Write search results to the above-named file."
APSButton .append -parent $w -text "Append" \
  -command {WriteOutSearch -fileName $outputFile -append 1} \
  -contextHelp "Append search results to the above-named file.  If it doesn't exist, create it."

APSScrolledList .listbox -parent .userFrame -height 10 \
    -contextHelp "Single click to find the location of a PV.  Double click to launch a probe with the PV."

set listbox .userFrame.listbox.listbox
$listbox delete 0 end

proc pv_matchInvoke {} {
     global pvexclude pvname

     if {[string length $pvexclude] != 0 && [string length $pvname] != 0} {
         if [catch {pv_match -pvname $pvname -pvexclude $pvexclude} result] {
             APSAlertBox  [APSUniqueName .] -errorMessage "$result"
         }
     } 
     if {[string length $pvexclude] == 0 && [string length $pvname] != 0} {
         if [catch {pv_match -pvname $pvname} result] {
             APSAlertBox  [APSUniqueName .] -errorMessage "$result"
         }
     } 
     if {[string length $pvexclude] != 0 && [string length $pvname] == 0} {
         if [catch {pv_match -pvexclude $pvexclude} result] {
             APSAlertBox  [APSUniqueName .] -errorMessage "$result"
         }
     }
     if {[string length $pvexclude] == 0 && [string length $pvname] == 0} {
          APSAlertBox  [APSUniqueName .] -errorMessage "PV name or exclusion entry is required!"
     }
}

proc WriteOutSearch {args} {
    set fileName ""
    set append 0
    APSStrictParseArguments {fileName append}

    global matched_pvs_list origDir
    if ![string length $fileName] return
    cd $origDir

    if ![file exists $fileName] {
        set append 0
    }

    if {!$append && [file exists $fileName]} {
        set choice [APSMultipleChoice [APSUniqueName .] \
                      -question "$fileName exists.  What do you want to do?" \
                      -labelList {Overwrite Append Cancel} \
                      -returnList {Overwrite Append Cancel}]
        if [string compare $choice Cancel]==0 return
        if [string compare $choice Append]==0 {
            set append 1
        }
    }
    APSSetVarAndUpdate status "Writing to file..."

    if $append {
        catch {exec rm ${fileName}~}
        catch {exec cp ${fileName} ${fileName}~}
        set fileName0 $fileName
        set fileName /tmp/[APSTmpString]
    }

    if [catch {sdds open $fileName w} fd] {
        return -code error $fd
    }
    set rows [llength $matched_pvs_list]
    if [catch {sdds defineColumn $fd ControlName -type SDDS_STRING
        sdds defineColumn $fd ControlType -type SDDS_STRING
        sdds writeLayout $fd
        sdds startPage $fd $rows
        eval sdds setColumn $fd ControlName $matched_pvs_list
        eval sdds setColumn $fd ControlType [APSReplicateItem -item pv -number $rows]
        sdds writePage $fd
        sdds close $fd} result] {
        return -code error $result
    }
    if $append {
        if [catch {exec sddscombine $fileName0 $fileName -merge $fileName0.new -overwrite 
            exec mv $fileName0.new $fileName0} result] {
            catch {exec mv ${fileName0}~ $fileName0}
            return -code error $result
        }
    }
    APSSetVarAndUpdate status "Done writing."
}

#  When item selected: read and show info associated with process variable
bind $listbox <Button-1> {
    set index [$listbox nearest %y]
    if {$index != -1} {
	set iocname $associated_ioc($index)
	
	if {[file exists $associated_ioc($index)]} {
	    set iocfp [open $associated_ioc($index) r]
	    set line [gets $iocfp]
	    if {[llength $line] == 2} {
		set roomname [lindex $line 0]
		set rackname [lindex $line 1]
	    } else {
		set roomname "no info available"
		set rackname "no info available"
	    }
	    close $iocfp
	} else {
	    set roomname "no info available"
	    set rackname "no info available"
	}
    }
}

# on double-click, launch probe with the PV
bind $listbox <Double-Button-1> {
    set index [$listbox nearest %y]
    if {$index != -1} {
        APSSetVarAndUpdate status "Lauching probe..."
        exec probe $matched_pvs($index) >& /dev/null &
    }
}

APSFrame .number -parent .userFrame
set i 0
APSLabeledOutput .i -parent .userFrame.number.frame -label "Number of PVs found:" \
  -textVariable i -width 30 -contextHelp "Displays a number of PVs which where \
  found during the search process."

APSLabeledOutput .iocname -parent .userFrame -label "IOC Name:" \
  -textVariable iocname -width 40
APSLabeledOutput .iocroom -parent .userFrame -label "Room:" \
  -textVariable roomname -width 40
APSLabeledOutput .iocrack -parent .userFrame -label "Rack:" \
  -textVariable rackname -width 40

proc pv_match {args} {
    set pvname ""
    set pvexclude ""
    if [APSStrictParseArguments {pvname pvexclude}] {
        return -code error "openFile: bad arguments"
    }
    global pvsearch_debug 
    global pvdata_path pvadata_path
    global iocdata_path
    global matched_pvs matched_pvs_list
    global associated_ioc
    global cancelsearch
    global status
    global listbox
    global iocname roomname rackname i
    
    if {[file isdirectory $pvdata_path] != 1} {
	APSAlertBox .alert -errorMessage \
	  "Cannot open or locate directory $pvdata_path"
	exit
    }
    if {[llength $pvadata_path]} {
        if {[file isdirectory $pvadata_path] != 1} {
	    APSAlertBox .alert -errorMessage \
	      "Cannot open or locate directory $pvadata_path"
	    exit
       }
    }
    if {[llength $iocdata_path]} {
        if {[file isdirectory $iocdata_path] != 1} {
	    APSAlertBox .alert -errorMessage \
	      "Cannot open or locate directory $iocdata_path"
            exit
        }
        cd $iocdata_path
        set iocdata_file_list [glob -nocomplain *]
        set iocdata_nofiles [llength $iocdata_file_list]
        if {$pvsearch_debug} {
            puts "found $iocdata_nofiles files in iocdata directory"
        }
    }
    
    cd $pvdata_path
    set pvdata_file_list [glob -nocomplain *]
    set pvdata_nofiles [llength $pvdata_file_list]
    if {$pvsearch_debug} {
	puts "found $pvdata_nofiles files in pvdata directory"
    }
    if {[llength $pvadata_path]} {
        append pvdata_file_list " [glob -directory $pvadata_path -nocomplain *]"
    }

    #  Clear leading and trailing spaces in pv search string
    set pvname [string trim $pvname]
    set pvexclude [string trim $pvexclude]
    
    #  Check to make sure search string isn't just "*"
    set pvnameOrig $pvname
    set pvexcludeOrig $pvexclude
    if {![string compare $pvname "*"] || ![string compare $pvexclude "*"]} {
	APSAlertBox .alert -errorMessage \
	  "Please be more specific. This will match everything."
	set i 0
    } else {
	# Convert a glob style wildcard string to a regular expression
	if {[string length $pvexclude] != 0 && [string length $pvname] != 0} {
	     set pvname [ConvertGlobStyleWildcardString $pvname]
        } 
	if {[string length $pvexclude] == 0 && [string length $pvname] != 0} {
	     set pvname [ConvertGlobStyleWildcardString $pvname]
        } 

	if {[string length $pvexclude] != 0 && [string length $pvname] == 0} {
	     set pvexclude [ConvertGlobStyleWildcardString $pvexclude]
        }   
 
	#     Execute a grep on pvdata directory and put results in listbox
	set status "Searching..."
	update
	if {[string length $pvexclude] != 0 && [string length $pvname] != 0} {
	     set cmd "grep \"$pvname\" $pvdata_file_list /dev/null"
        } 
	if {[string length $pvexclude] == 0 && [string length $pvname] != 0} {
	     set cmd "grep \"$pvname\" $pvdata_file_list /dev/null"
        } 

	if {[string length $pvexclude] != 0 && [string length $pvname] == 0} {
	     set cmd "grep -v \"$pvexclude\" $pvdata_file_list /dev/null" 
        }   

	set catchlist [list open |$cmd r]
	catch $catchlist fp
	$listbox delete 0 end
	set i 0
        set matched_pvs_list ""
	while {[gets $fp line] >= 1} {
	    if {$cancelsearch} {break}
	    set breakpoint [string first : $line]
            set ematch [string range $line [expr $breakpoint+1] end]
            if {[string length $pvexclude] != 0 && [string length $pvname] != 0} {
                 if {[string match "[set pvexclude]" $ematch] == 0} { 
	              set matched_pvs($i) $ematch
                      lappend matched_pvs_list $matched_pvs($i)
	              set associated_ioc($i) [string range $line 0 [expr $breakpoint-1]]
	              $listbox insert end $matched_pvs($i)
	              incr i
                 }
	    } else {
	              set matched_pvs($i) $ematch
                      lappend matched_pvs_list $matched_pvs($i)
	              set associated_ioc($i) [string range $line 0 [expr $breakpoint-1]]
	              $listbox insert end $matched_pvs($i)
	              incr i
            }
	    if {($i%360) == 0} {
		set status "Searching...\\"
		update
	    } elseif {($i%360) == 90} {
		set status "Searching...|"
		update
	    } elseif {($i%360) == 180} {
		set status "Searching.../"
		update
	    } elseif {($i%360) == 270} {
		set status "Searching...-"
		update
	    }
	}
	catch {close $fp}
        
        if {[file exists /home/helios/oagData/pvdata/iocRecNamesOAG.sdds]} {
            if {[llength $pvnameOrig] && [llength $pvexcludeOrig]} {
                set option \"-match=column,rec_name=$pvnameOrig,rec_name=$pvexcludeOrig,\!,\&\"
            } elseif {[llength $pvnameOrig]} {
                set option \"-match=column,rec_name=$pvnameOrig\"
            } elseif {[llength $pvexcludeOrig]} {
                set option \"-match=column,rec_name=$pvexcludeOrig,\!\"
            } else {
                return -code error "No selection info given"
            }
            if {[catch {eval exec sddsprocess /home/helios/oagData/pvdata/iocRecNamesOAG.sdds -pipe=out $option | sdds2stream -pipe=in -col=rec_name,ioc_name} results]} {
                
            } else {
                foreach "rec ioc" $results {
                    set j [lsearch -exact $matched_pvs_list $rec]
                    if {$j == -1} {
                        set matched_pvs($i) $rec
                        lappend matched_pvs_list $matched_pvs($i)
                        set associated_ioc($i) $ioc
                        $listbox insert end $matched_pvs($i)
                        incr i
                    }
                }
            }
        }

	set cancelsearch 0
	set status "Enter PV Name or Pattern"
    }
    
    #  If we have at least one match, select the first one automatically
    if {![llength $iocdata_path]} {
	$listbox select anchor 0
	$listbox select set 0
	set index 0
	set iocname ""
	set roomname "no info available"
	set rackname "no info available"
        return
    }
    if {$i > 0} {
	cd $iocdata_path
	$listbox select anchor 0
	$listbox select set 0
	set index 0
	set iocname $associated_ioc($index)
	
	if {$pvsearch_debug} {
	    puts "currently in [pwd] directory"
	}
	if {[file exists $associated_ioc($index)]} {
	    set iocfp [open $associated_ioc($index) r]
	    set line [gets $iocfp]
	    if {[llength $line] == 2} {
		set roomname [lindex $line 0]
		set rackname [lindex $line 1]
	    } else {
		set roomname "no info available"
		set rackname "no info available"
	    }
	    close $iocfp
	} else {
	    set roomname "no info available"
	    set rackname "no info available"
	}
    } else {
	set iocname ""
	set roomname ""
	set rackname ""
	
    }
}

proc ConvertGlobStyleWildcardString {pvVariable} {
     global pvsearch_debug

     set sstring ^$pvVariable
     set pvVariable ""

     while {[set breakpoint [string first "*" $sstring]] != -1} {
	 set firstpart [string range $sstring 0 [expr $breakpoint-1]]
	 set lastpart [string range $sstring $breakpoint end]
	 set pvVariable $pvVariable$firstpart.*
	 set sstring [string range $lastpart 1 end]
     }      
     set pvVariable $pvVariable$sstring
     while {[set transpose_index [string first "?" $pvVariable]] != -1} {
	    set pvVariable "[string range $pvVariable 0 [expr $transpose_index-1]].[string range $pvVariable [expr $transpose_index+1] end]"
     }
     set pvVariable $pvVariable$
     if {$pvsearch_debug} {
	 puts "reg exp search string is: $pvVariable"
     }
     return $pvVariable
}
