#########################################################
#                  Tk LaTeX Editor
#        Distributed under GNU Public License
# Author: Sergey Kalinin (BanZaj) banzaj@lrn.ru
# Copyright (c) "CONERO lab", 2002, http://conero.lrn.ru
#########################################################
#              Spell Checking procedure
#              required Ispell, Msgcat
# Author: Victor Wagner (Vitus) http://www.ice.ru/~vitus
#
# Usage: "SpellCheck text_widget"
#########################################################


proc SpellCheck {text} {
    global ispell_lib ispell_language ispell_startindex nb color font
    set node [$nb raise]
    if {[winfo exists .spell]} {
        return
    }
    
    if {$node == "newproj" || $node == "settings" || $node == "about" || $node == ""} {
        return
    }
    # Build dictionary list
    foreach dict [glob [file join $ispell_lib *.hash]] {
        file stat $dict foo
        set lang [file rootname [file tail $dict]]
        if {$lang == "default"} {
            set default_inode $foo(ino)
        } else {
            lappend langs $lang
            set lang_nodes($foo(ino)) $lang;
        }  
    }  
    if {![info exists ispell_language]} {
        if {[info exists default_inode ]&&[info exists lang_nodes($default_inode)]} {
            set ispell_language $lang_nodes($default_inode)
        } else {
            set ispell_language [lindex $langs 0]
        }
    }
    toplevel .spell -class Notepad
    wm title .spell [::msgcat::mc "Spell check"]
    wm transient .spell .
    wm resizable .spell 0 0
    
    frame .spell.lang -relief raised -borderwidth 1 -background $color(bg)
    label .spell.lang.l -text [::msgcat::mc "Language"] -background $color(bg) -font $font(normal)
    eval tk_optionMenu .spell.lang.m ispell_language $langs -background $color(bg) -font $font(normal)
    pack .spell.lang.l .spell.lang.m -side left -padx 5 
    pack .spell.lang.m -side left -padx 5 -fill x -expand 1
    frame .spell.start -relief raised -borderwidth 1 -background $color(bg)
    radiobutton .spell.start.all -text [::msgcat::mc "Entire file"] -background $color(bg)\
    -variable ispell_startindex -value "1.0" -anchor w -font $font(normal)
    radiobutton .spell.start.ins -text [::msgcat::mc "From cursor"] -background $color(bg)\
    -variable ispell_startindex -value insert -anchor w -font $font(normal)
    pack .spell.start.all .spell.start.ins -side top -pady 1 -expand y -fill x        
    frame .spell.b -relief raised -borderwidth 1 -background $color(bg)
    button .spell.b.ok -text [::msgcat::mc "Start"] -relief groove -background $color(bg)\
    -command "DoSpellCheck $text"  -font $font(normal)
    button .spell.b.cancel -text [::msgcat::mc "Cancel"] -relief groove -background $color(bg)\
    -command "destroy .spell" -font $font(normal)
    pack .spell.b.ok .spell.b.cancel -side left -padx 10
    pack .spell.lang -side top -fill x
    pack .spell.start -side top -fill both -expand 1
    pack .spell.b -side top -fill x
    bind .spell <Escape> "destroy .spell"
}

proc DoSpellCheck {text} {
    global ispell_file ispell_startindex ispell_language spellAddWords color font
    eval destroy [winfo children .spell]
    wm transient .spell .
    entry .spell.word -exportselection false
    listbox .spell.misses -yscrollcommand ".spell.y set" -exportselection false -background $color(bg)
    scrollbar .spell.y -command ".spell.misses yview" -background $color(bg)
    button .spell.ok -text [::msgcat::mc "Accept"] -command "SpellOk $text" -background $color(bg) \
    -font $font(normal)
    button .spell.accept -text [::msgcat::mc "Next"] -command "SpellAccept @" -background $color(bg) \
    -font $font(normal)
    button .spell.adddict -text [::msgcat::mc "Add to dict"] -command "SpellAccept *" -background $color(bg) \
    -font $font(normal)
    button .spell.adddict2 -text [::msgcat::mc "Add lowercase"] -command "SpellAccept &" -background $color(bg) \
    -font $font(normal)
    button .spell.stop -text [::msgcat::mc "Stop checking"] -command "SpellStop $text" -background $color(bg) \
    -font $font(normal)
    grid .spell.word - - -sticky news -padx 5 -pady 5
    grid .spell.misses .spell.y .spell.ok -sticky news  
    grid x x .spell.accept  -sticky news 
    grid x x .spell.adddict -sticky news
    grid x x .spell.adddict2 -sticky news
    grid x x .spell.stop -sticky news
    grid configure .spell.ok .spell.accept .spell.adddict .spell.adddict2 .spell.stop -padx 5 -pady 3
    grid configure .spell.misses .spell.y -rowspan 5 
    focus .spell.word
    wm protocol .spell WM_DELETE_WINDOW "SpellStop $text"
    
    set ispell_file [open "|ispell -a -d $ispell_language" w+]
    fconfigure $ispell_file -buffering none -blocking yes
    gets $ispell_file
    puts $ispell_file "!"
    set spellAddWords {}
    
    $text mark set insert $ispell_startindex 
    while {[SpellNextLine $text]} {
        while {[gets $ispell_file responce]>0} {
            switch -exact -- [string range $responce 0 0] {
                "*" -
                "+" -
                "-" {continue}
                "&" -
                "?" {regexp {^. +([^ ]+) +[0-9]+ +([0-9]+):(.*)$} $responce foo \
                orig offset guesses
                SpellInteract $orig $offset $guesses $text
            }
            "#" {regexp {^. +([^ ]+) +([0-9]+)} $responce foo orig offset
            SpellInteract $orig $offset {} $text
        }
    }
}
$text mark set insert "spellstart linestart + 1 lines"
}
close $ispell_file
eval destroy  [winfo children .spell]
label .spell.l -text [::msgcat::mc "Checking complete"] -background $color(bg)
button .spell.ok -text [::msgcat::mc "Ok"] -command {destroy .spell} -background $color(bg)
wm protocol .spell WM_DELETE_WINDOW {destroy .spell}
pack .spell.l .spell.ok -side top -padx 5 -pady 10
}


proc SpellNextLine {text} {
    global spellOffset ispell_file spellAddWords
    set spellOffset -1 
    $text see insert
    $text mark set spellstart insert
    set line [$text get insert "insert lineend"]
    if [$text compare insert >= "end-1char"] {
        return 0 
    }
    foreach word $spellAddWords {
        puts "Adding to dictionary $word"
        puts $ispell_file $word
    }   
    set spellAddWords {}
    puts $ispell_file "^$line"
    return 1
}

proc SpellInteract {word offset guesses text} {
    .spell.word delete 0 end
    .spell.word insert 0 $word
    $text tag remove sel 0.0 end
    global spellOffset
    incr offset $spellOffset
    $text tag add sel "spellstart+$offset chars" "spellstart+[expr $offset+\
    [string length $word]] chars"
    global spellHighlight
    set spellHighlight [$text tag ranges sel]
    $text see sel.first
    $text mark set insert sel.first
    .spell.misses delete 0 end
    if [string length $guesses] {
        foreach miss [split $guesses ","] {
            .spell.misses insert end [string trim $miss]
        }
    }
    global spellInteractResult
    vwait spellInteractResult
    return -code $spellInteractResult
}

proc SpellOk {text} {
    # заменить на содержимое .spell.word или .spell.misses
    global spellInteractResult spellHighlight
    if [llength [.spell.misses curselection]] {
        set word [.spell.misses get [.spell.misses curselection]]
    } else {
        set word [.spell.word get]
    }
    if {![llength [$text tag ranges sel]]} {
        global spellHighilight
        eval $text tag add sel $spellHighlight
    }  
    set oldword [$text get sel.first sel.last]
    if {[string compare $oldword $word]} {
        $text delete sel.first sel.last
        $text insert insert $word sel
        global changed spellOffset
        set changed 1
        incr spellOffset [expr [string length $word]-[string length $oldword]]
    }    
    set spellInteractResult ok
}

proc SpellAccept {cmd} {
    global spellAddWords spellInteractResult
    lappend  spellAddWords "$cmd[.spell.word get]"
    set spellInteractResult ok
}

proc SpellStop {text} {
    global ispell_file
    $text mark unset spellstart
    catch {close $ispell_file}
    destroy .spell
    set spellInteractResult return
} 







