#
# Module for performing searches in Misc widgets
#


# Performs a search on w, informing user of success or failure. If direction
# and type are not specified, they are determined from the search label.
# Direction is forward or backward, and type indicates the search type, one of
# 'string' or 'regexp'. If next is 0, stays on the same find, otherwise moves
# to the next one.
proc th_Misc_find {w string {next 1} {direction ""} {type ""} {wrap ""}} {
  set label "[th_frame $w].search.l"
  set text [$label cget -text]
  if {$direction == ""} {set direction [lindex $text 0]}
  if {$type == ""} {set type [lindex $text 1]}

  global TH
  if {[catch "set TH(Search,Case,Implicit)"]} {set TH(Search,Case,Implicit) 0}
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}

  if $TH(Search,Case,Implicit) {
    if {(![winfo exists "[th_frame $w].replace"]
	 || ![winfo ismapped "[th_frame $w].replace"])
	&& ![regexp -- {[A-Z]+} $string]} {
      set TH(Search,Case,$w) 1} else {set TH(Search,Case,$w) 0}}

  if $TH(Search,Case,$w) {set string [string tolower $string]}

  if {[th_[winfo class $w]_find $w $string $next $direction $type]} {
    $label configure -text "$direction $type search:"
    return 1
  } else {
    $label configure -text "$direction $type search failed:"
    bell
    return 0
}}


# Finds all future occurrences of string 'n highlights 'em.
proc th_Misc_highlight_searches {w string} {
  set label "[th_frame $w].search.l"
  set text [$label cget -text]
  set direction [lindex $text 0]
  set type [lindex $text 1]
  global TH
  if {![catch "set TH(Search,Case,$w)" result] && $result} {
	set string [string tolower $string]}
  while {[th_[winfo class $w]_find $w $string 1 $direction $type]} {}
}


# Turns on 'incremental' search, or turns it off if it was on.
proc th_toggle_incremental_search {w} {
  global TH
  th_checkbutton_variable Search,Incremental,$w
  if {[winfo exists [set e "[th_frame $w].search.e"]]} {
    if $TH(Search,Incremental,$w) {
      if {[lsearch [bindtags $e] "is$e"] < 0} {
        bindtags $e [concat [bindtags $e] "is$e"]}
      bind "is$e" <Key> [subst {if {\[regexp . %A\]} {th_Misc_find $w \[$e get\] 0}}]
      th_bind "is$e" Search_Forward "continue"
      th_bind "is$e" Search_Backward "continue"
    } else {
      bind "is$e" <Key> {}
}}}

# Called the first time a search is requested. $f is the widget's frame.
proc th_Misc_search_setup {w f} {
  global TH

  lappend TH(Completions,$f.e) "th_word_replace $w {}"

# Make sure all cancels get out of search mode.
  th_bind $f.e Cancel "th_Misc_search_exit $w ; [th_bind $f.e Cancel]"
  if {[catch "set TH(Cancel,Code,$w)"]} {set TH(Cancel,Code,$w) ""}
  append TH(Cancel,Code,$w) "th_Misc_search_exit $w ; "

# Add all keybindings to the search entry
  set binding_list {Search_Forward Search_Backward Toggle_Case_Sensitivity Toggle_Incremental_Search}
  if {[lsearch "Text Listbox" [winfo class $w]] >= 0} {
    lappend binding_list Highlight_Searches
    th_bind $f.e Highlight_Searches "th_Misc_highlight_searches $w \[$f.e get\] ; break"
    if {[winfo class $w] == "Text"} {
      lappend binding_list Mark_Text Unmark_Text
      set tag $TH(Search,Select,Text)
      th_bind $f.e Mark_Text "$w tag add mark $tag.first $tag.last ; if {![catch {set TH(Mark,Tag)}]} {eval $w tag configure mark \$TH(Mark,Tag)} ; break"
      th_bind $f.e Unmark_Text "$w tag remove mark $tag.first $tag.last ; break"
  }}
  if {![catch "set TH(Binding,Replace_One)"] && ([lsearch "Text Entry Canvas" [winfo class $w]] >= 0)} {
    lappend binding_list Replace_One Replace_All
    th_bind $f.e Replace_One "th_Misc_replace $w 1 \{$binding_list\} ; break"
    th_bind $f.e Replace_All "th_Misc_replace $w 0 \{$binding_list\} ; break"
  }
  th_bind $f.e OK "th_Misc_find $w \[$f.e get\] ; th_Misc_search_exit $w ; break"
  th_bind $f.e Search_Forward "th_Misc_find $w \[$f.e get\] 1 forward ; break"
  th_bind $f.e Search_Backward "th_Misc_find $w \[$f.e get\] 1 backward ; break"
  th_bind $f.e Toggle_Case_Sensitivity "th_checkbutton_variable Search,Case,$w ; break"
  th_bind $f.e Toggle_Incremental_Search "th_toggle_incremental_search $w ; break"

# Change the search label to a menubutton, add menubutton entries.
  destroy $f.l
  menubutton $f.l -menu $f.l.m
  pack $f.l -side left -before $f.e
  menu $f.l.m
  foreach binding $binding_list {
    $f.l.m add command -label [lindex $TH(Menuentry,$binding) 0] \
	-accel [lindex $TH(Binding,$binding) 0] \
	-underline [lindex $TH(Menuentry,$binding) 1] \
	-command [th_bind $f.e $binding]
  }

# Turn on incremental search if necessary.
  if $TH(Search,Incremental,$w) {
    set TH(Search,Incremental,$w,aux) 0
    th_toggle_incremental_search $w
}}


# Starts up the search routines
proc th_Misc_search {w {direction "forward"} {type "string"}} {
  global TH
  if {[catch "set TH(Search,Incremental,$w)"]} {set TH(Search,Incremental,$w) 0}
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}
  if {![winfo exists "[th_frame $w].search.e"]} {set setup 1} else {set setup 0}
  if {[set f [th_show_entry $w search]] == ""} {bell ; return}
  if $setup {th_Misc_search_setup $w $f}
  $f.l configure -text "$direction $type search:"

  if {$TH(Search,Incremental,$w) && ($type != "string")} {
    th_toggle_incremental_search $w
  }
  if $TH(Search,Incremental,$w) {$f.e delete 0 end}
  set TH(Search,Failed,$w) 0
  return ""
}


# Closes down the search routines.
proc th_Misc_search_exit {w} {
  global auto_index
  set exit_proc th_[winfo class $w]_search_exit
  if {([info procs $exit_proc] != "") || \
     ([lsearch [array names auto_index] $exit_proc] >= 0)} {$exit_proc $w}
  th_hide_entry $w search

  set f [th_frame $w]
  if {![catch {winfo ismapped "$f.replace.e"} result]} {
    if $result {th_Misc_replace_exit $w}}
}
