#
# Module for performing searches in Text widgets
#


# Finds next occurrence of string in w.
proc th_Text_find {w string {next 1} {direction "forward"} {type "string"}} {
  global TH
  set search $TH(Search,Select,[winfo class $w])

  if {($search != "sel") && ([lsearch [$w tag names] $search] == -1)} {
    eval $w tag configure $search $TH(Search,Text,Tag)
  }
  if {[lsearch [$w tag names] was_search] == -1} {
    eval $w tag configure was_search $TH(Search,Text,Oldtag)
  }
  $w tag raise $search
  $w tag lower was_search $search
  set was_search_area [$w tag nextrange $search 1.0 end]
  if {([llength $was_search_area] == 2) &&
      [$w compare [lindex $was_search_area 0] <= insert] &&
      [$w compare insert <= [lindex $was_search_area 1]]} {
    eval $w tag remove $search $was_search_area
    eval $w tag add was_search $was_search_area

    if $next {
      set border(forward) "[lindex $was_search_area 0] +1c"
      set border(backward) "[lindex $was_search_area 0] -1c"
    } else {
      set border(forward) "[lindex $was_search_area 0] -1c"
      set border(backward) "[lindex $was_search_area 0] +1c"
  }} else {
    set border(forward) [$w index insert-1c]
    set border(backward) [$w index insert+1c]
  }
  if {[catch "set TH(Search,Failed,$w)"]} {set TH(Search,Failed,$w) 0}
  if $TH(Search,Failed,$w) {
    set border(forward) 1.0
    set border(backward) end-2c
  }

  set length [string length $string]
  if {($length == 0)} {return 0}

  set slist [th_Text_[set type]_[set direction] $w $border($direction) $string]
  if {($slist != "")} {
    th_Text_goto $w [lindex $slist 0] 0
    if {$search == "sel"} { eval th_Text_select_range $w $slist
    } else {eval $w tag add $search $slist}
    set TH(Search,Failed,$w) 0
    return 1
  } else {
    set TH(Search,Failed,$w) 1
    return 0
}}


# Finds first occurrence of string after point in widget w
# Returns start and end of occurance or "" if unsuccessful.
proc th_Text_string_forward {w point string} {
  global TH
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}
  if $TH(Search,Case,$w) {set case "-nocase"} else {set case ""}
  if {[set answer [eval $w search -forward -exact $case -- \
	[list "$string"] [list $point] end]] == ""} {return ""} else {
    return [list $answer "$answer + [string length $string] chars"]
}}

# Finds last occurrence of string starting before point in widget w
# Returns start and end of occurance or "" if unsuccessful.
proc th_Text_string_backward {w point string} {
  global TH
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}
  if $TH(Search,Case,$w) {set case "-nocase"} else {set case ""}
  if {[set answer [eval $w search -backward -exact $case -- \
	[list "$string"] [list "$point+1c"] 1.0]] == ""} {return ""} else {
    return [list $answer "$answer + [string length $string] chars"]
}}


# Finds first occurrence of string after point in widget w using regexp.
# Returns start and end of occurance or "" if unsuccessful.
proc th_Text_regexp_forward {w point string} {
  global TH
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}
  if $TH(Search,Case,$w) {set case "-nocase"} else {set case ""}
  if {[catch "$w search -forward -regexp $case -count distance -- \
	[list "$string"] [list $point] end" answer]} {bell ; return ""}
  if {$answer == ""} {return ""} else {
      return [list $answer "$answer + $distance chars"]
}}

# Like regexp_forward, but searches from beginning to point.
proc th_Text_regexp_backward {w point string} {
  global TH
  if {[catch "set TH(Search,Case,$w)"]} {set TH(Search,Case,$w) 0}
  if $TH(Search,Case,$w) {set case "-nocase"} else {set case ""}
  if {[catch "$w search -backward -regexp $case -count distance -- \
	[list "$string"] [list "$point +1c"] 1.0" answer]} {bell ; return ""}
  if {$answer == ""} {return ""} else {
    return [list $answer "$answer + $distance chars"]
}}


# Cleans up widget from searching.
proc th_Text_search_exit {w} {
  global TH
  if {[set search $TH(Search,Select,[winfo class $w])] != "sel"} {
    if {[lsearch [$w tag names] $search] >= 0} {
      $w tag remove $search 1.0 end
  }}
  if {[lsearch [$w tag names] was_search] >= 0} {
    $w tag remove was_search 1.0 end
}}
