#! /usr/bin/wish8.0jp
#
# Copyright (C) 1997, 1998, 1999  Motoyuki Kasahara
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# This line makes the next one a comment in Tcl \
	exec /usr/bin/wish8.0jp "$0" ${1+"$@"}

#
# If the system is UNIX, set internal kanji code to EUC.
# Otherwise set it to SJIS.
#
if {$tcl_platform(platform) == "unix"} {
    kanji internalCode EUC
} else {
    kanji internalCode SJIS
}

#
# Include sources.
#
source "/usr/lib/bookview/finder.tcl"
source "/usr/lib/bookview/ndtp.tcl"
source "/usr/lib/bookview/setup.tcl"
source "/usr/lib/bookview/help.tcl"

######################################################################
## BookView
######################################################################
# History table.
set history_book(-1) {}
set history_position(-1) {}
set history_fraction(-1) {}
set history_cursor(-1) {}

# History size.
set history_size 16
set history_current -1
set history_top -1
set history_bottom -1

# Help Filenames.
set help_filename "/usr/lib/bookview/help.txt"
set ja_help_filename "/usr/lib/bookview/help-ja.txt"

# Setup Filename.
if {$tcl_platform(platform) == "unix"} {
    set system_setup_file "/usr/etc/bookview.conf"
    set user_setup_file "$env(HOME)/.bookview"
} else {
    set system_setup_file "/usr/lib/bookview/setup"
    set user_setup_file "/usr/lib/bookview/setup"
}

# Server list and the maximum number of servers.
set server_names {localhost}
set server_ports {ndtp}
set server_starts {nodict}
set max_servers 3

# Whether connect to server1 at start of BookView.
set start_server1 0

# Word input by an user.
set input_word {}

# Positions of hitting words.
global hit_positions {}

# Current position in hit entries.
global current_hit

# Selections of radio and check buttons.
set server_radiobutton {}
set book_radiobutton "nodict"
set go_radiobutton {}
set bitmap_checkbutton 1

# Bitmap size preferences.
set prefer_sizes {\
	{16} \
	{24} \
	{30} \
	{48} \
	{16 24} \
	{24 16} \
	{24 30} \
	{30 24} \
	{30 48} \
	{48 30} \
	{16 24 30} \
	{24 16 30} \
	{24 30 16} \
	{24 30 48} \
	{30 24 16} \
	{30 24 48} \
	{30 48 24} \
	{48 30 24} \
	{16 24 30 48} \
	{48 30 24 16}}

# Current preference of Bitmap sizes.
set prefer_index 0

# Widget focused in previous.
set saved_focus "."

# Window configurations.
set toolbar_checkbutton 1
set hits_height 4
set text_spacing 0

#
# Startup
#
proc startup {} {
    global argc
    global argv
    global argv0
    global server_names
    global server_ports
    global start_server1
    global prefer_index
    global server_radiobutton

    #
    # Set default fonts.
    #
    set font ""
    set kanjifont ""
    set deffont [option get . tkDefaultFont *]
    if {$deffont != ""} {
	set c ""
	catch {set c [font conf $deffont -compound]}
	if {$c == ""} {
	    option add *font $deffont
	}
	set font [lindex $c 0]
	set kanjifont [lindex $c 1]
    }

    #
    # Parse command line options.
    #
    set iconic 0
    set title ""
    for {set i 0} {$i < $argc} {incr i} {
	set argi [lindex $argv $i]
	switch -regexp -- $argi {
	    {^-(bg|background)$} {
		incr i
		if {$argc <= $i} {
		    puts stderr "$argv0: option \`$argi\' requires an argument"
		}
		option add "*background" [lindex $argv $i]
		option add "*hilightColor" [lindex $argv $i]
	    }
	    {^-(fg|foreground)$} {
		incr i
		if {$argc <= $i} {
		    puts stderr "$argv0: option \`$argi\' requires an argument"
		}
		set fg [lindex $argv $i]
		option add "*foreground" [lindex $argv $i]
	    }
	    {^-(fn|font)$} {
		incr i
		if {$argc <= $i} {
		    puts stderr "$argv0: option \`$argi\' requires an argument"
		}
		set font [lindex $argv $i]
		if {$kanjifont == ""} {
		    set kanjifont "Mincho"
		}
	    }
	    {^-(fk|kanjifont)$} {
		incr i
		if {$argc <= $i} {
		    puts stderr "$argv0: option \`$argi\' requires an argument"
		}
		set kanjifont [lindex $argv $i]
		if {$font == ""} {
		    set font "Helvetica-12"
		}
	    }
	    {^-iconic$} {
		set iconic 1
	    }
	    {^-title$} {
		incr i
		if {$argc <= $i} {
		    puts stderr "$argv0: option \`$argi\' requires an argument"
		}
		set title [lindex $argv $i]
	    }
	    {^-version$} {
		puts stderr "BookView version 2.4.6"
		puts stderr "Copyright (c) 1997, 1998, 1999  Motoyuki Kasahara\n"
		puts stderr "This is free software; you can redistribute it and/or modify"
		puts stderr "it under the terms of the GNU General Public License as published
 by"
		puts stderr "the Free Software Foundation; either version 2, or (at your option)"
		puts stderr "any later version.\n"
		puts stderr "This program is distributed in the hope that it will be useful,";
		puts stderr "but WITHOUT ANY WARRANTY; without even the implied warranty"
		puts stderr "of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the";
		puts stderr "GNU General Public License for more details."
		exit
	    }
	    {^-} {
		puts stderr "Unknown option \`$argi\'"
		exit 1
	    }
	    default {
		break
	    }
	}
    }
    if {$i < $argc} {
	puts stderr "Too many arguments"
	exit 1
    }

    #
    # Set fonts.
    #
    if {$font != "" && $kanjifont != ""} {
	catch {font delete default}
	catch {font create default -compound "$font $kanjifont"}
	option add "*font" default
    }

    #
    # Make a main window.
    #
    make_main_window

    if {$title != ""} {
	wm title . $title
    }
    if {$iconic} {
	wm iconify .
    }
    wm iconname . [wm title .]

    #
    # Load a setup file.  If failed, pop the Setup window up.
    #
    if {![setup_load_file]} {
	setup
    }
    set_server_menu
    if {$start_server1 == 1} {
	select_server 1
    }
    reconfigure_main_window
}

#
# Make a main window.
#
proc make_main_window {} {
    global history_size
    global history_book
    global history_current
    global input_word
    global help_filename
    global ja_help_filename
    global book_radiobutton
    global bitmap_checkbutton
    global toolbar_checkbutton
    global hits_height
    global text_spacing

    #
    # Toplevel
    #
    bind . <Destroy> quit
    bind . <Alt-q> quit
    bind . <M-q> quit

    set script {
	.server.menubutton.menu post [winfo rootx .server.menubutton] \
		[expr [winfo rooty .server.menubutton] \
		+ [winfo height .book.menubutton]]
	set saved_focus [focus]
	focus .server.menubutton.menu
	grab .book.menubutton.menu
	update
	.server.menubutton.menu activate 0
    }
    bind . <Alt-s> $script
    bind . <M-s> $script

    set script {
	if {[.book.menubutton.menu entrycget 0 -label] != ""} {
	    .book.menubutton.menu post [winfo rootx .book.menubutton] \
		    [expr [winfo rooty .book.menubutton] \
		    + [winfo height .book.menubutton]]
 	    set saved_focus [focus]
	    focus .book.menubutton.menu
	    grab .book.menubutton.menu
	    update
	    .book.menubutton.menu activate 0
	}
    }
    bind . <Alt-b> $script
    bind . <M-b> $script

    bind . <Alt-slash> finder_make_window
    bind . <M-slash> finder_make_window

    set script {
	if {[.toolbar.back cget -state] != "disabled"} {
	    go_history [expr ($history_current - 1) %% $history_size]
	}
    }
    bind . <Alt-Left> $script
    bind . <M-Left> $script
    bind . <Alt-p> $script
    bind . <M-p> $script

    set script {
	if {[.toolbar.next cget -state] != "disabled"} {
	    go_history [expr ($history_current + 1) %% $history_size]
	}
    }
    bind . <Alt-Right> $script
    bind . <M-Right> $script
    bind . <Alt-n> $script
    bind . <M-n> $script

    set script {
	if {[.word.toolbar.query cget -state] != "disabled"} {
	    focus .word.entry
	}
    }
    bind . <Alt-w> $script
    bind . <M-w> $script

    set script {
	if {[.word.toolbar.query cget -state] != "disabled"} {
	    query_selection
	}
    }
    bind . <Alt-Return> $script
    bind . <M-Return> $script

    #
    # Menu bar
    #
    frame .menubar -relief raised -borderwidth 2
    pack .menubar -side top -fill x

    menubutton .menubar.file -text "File" -menu .menubar.file.menu \
	-underline 0
    pack .menubar.file -side left

    menubutton .menubar.view -text "View" -menu .menubar.view.menu \
	-underline 0
    pack .menubar.view -side left

    menubutton .menubar.go -text "Go" -menu .menubar.go.menu \
	-underline 0
    pack .menubar.go -side left

    menubutton .menubar.help -text "Help" -menu .menubar.help.menu \
	-underline 0
    pack .menubar.help -side right

    #
    # Menu `File'
    #
    menu .menubar.file.menu -tearoff 0
    .menubar.file.menu add command -label "Setup..." -command setup \
	-underline 0
    .menubar.file.menu add separator
    .menubar.file.menu add command -label "Quit" -command quit -underline 0 \
	-accelerator "Alt+Q"

    #
    # Menu `View'
    #
    menu .menubar.view.menu -tearoff 0
    .menubar.view.menu add command -label "Book List" -state disabled \
	    -command {put_new_text nodict "booklist"} -underline 5
    .menubar.view.menu add command -label "Menu" -state disabled \
	    -command {put_new_text $book_radiobutton "menu"} -underline 0
    .menubar.view.menu add command -label "Copyright" -state disabled \
	    -command {put_new_text $book_radiobutton "copyright"} -underline 0
    .menubar.view.menu add command -label "Query Selection" -state disabled \
	    -command query_selection -accelerator "Alt+Return"
    .menubar.view.menu add separator
    .menubar.view.menu add command -label "Find in Text..." -underline 0 \
	    -accelerator "Alt+/" -command finder_make_window
    .menubar.view.menu add separator
    .menubar.view.menu add checkbutton -label "Display Toolbar" \
	    -underline 8 -variable toolbar_checkbutton \
	    -command {reconfigure_main_window}
    .menubar.view.menu add checkbutton -label "Display Bitmaps" \
	    -variable bitmap_checkbutton -onvalue 1 -offvalue 0 -underline 8 \
	    -command {if {0 <= $history_current} {go_history $history_current}}
    .menubar.view.menu add cascade -label "Text Spacing" \
	    -menu .menubar.view.menu.spacing -underline 5

    #
    # Cascade menu for `View -> Text Spacing'.
    #
    set script {
	.text.text configure -spacing1 $text_spacing -spacing2 $text_spacing
    }
    menu .menubar.view.menu.spacing -tearoff 0
    .menubar.view.menu.spacing add radiobutton -label "0 pixel" -value 0 \
	    -variable text_spacing -underline 0 -command $script
    .menubar.view.menu.spacing add radiobutton -label "2 pixels" -value 2 \
	    -variable text_spacing -underline 0 -command $script
    .menubar.view.menu.spacing add radiobutton -label "4 pixels" -value 4 \
	    -variable text_spacing -underline 0 -command $script
    .menubar.view.menu.spacing add radiobutton -label "6 pixels" -value 6 \
	    -variable text_spacing -underline 0 -command $script
    .menubar.view.menu.spacing add radiobutton -label "8 pixels" -value 8 \
	    -variable text_spacing -underline 0 -command $script

    #
    # Menu `Go'
    #
    menu .menubar.go.menu -tearoff 0
    .menubar.go.menu add command -label "Previous" -state disabled \
	    -underline 0 -accelerator "Alt+P" \
	    -command {go_history [expr ($history_current - 1) % $history_size]}
    .menubar.go.menu add command -label "Next" -state disabled \
	    -underline 0 -accelerator "Alt+N" \
	    -command {go_history [expr ($history_current + 1) % $history_size]}
    .menubar.go.menu add separator


    #
    # Menu `Help'
    #
    menu .menubar.help.menu -tearoff 0
    .menubar.help.menu add command -label "Help (English)..." \
	    -command "help_make_window \"$help_filename\"" -underline 6
    .menubar.help.menu add command -label "Help (Japanese)..." \
	    -command "help_make_window \"$ja_help_filename\"" -underline 6

    #
    # Create Images.
    #
    image create photo bitmap_prev -file "/usr/lib/bookview/prev.gif"
    image create photo bitmap_next -file "/usr/lib/bookview/next.gif"
    image create photo bitmap_find -file "/usr/lib/bookview/find.gif"
    image create photo bitmap_menu -file "/usr/lib/bookview/menu.gif"
    image create photo bitmap_copyright -file "/usr/lib/bookview/copyright.gif"
    image create bitmap bitmap_arrow -file "/usr/lib/bookview/arrow.xbm"
    image create bitmap bitmap_space -file "/usr/lib/bookview/space.xbm"

    #
    # Toolbar.
    # 
    frame .toolbar
    pack .toolbar -side top -anchor w -pady 2 -fill x
    button .toolbar.back -image bitmap_prev -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 \
	    -command {go_history [expr ($history_current - 1) % $history_size]}
    pack .toolbar.back -side left

    button .toolbar.next -image bitmap_next -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 \
	    -command {go_history [expr ($history_current + 1) % $history_size]}
    pack .toolbar.next -side left

    button .toolbar.menu -image bitmap_menu -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 \
	    -command {put_new_text $book_radiobutton "menu"}
    pack .toolbar.menu -side left

    button .toolbar.copyright -image bitmap_copyright -relief raised \
	    -borderwidth 2 -state disabled -takefocus 0 \
	    -command {put_new_text $book_radiobutton "copyright"}
    pack .toolbar.copyright -side left

    button .toolbar.find -image bitmap_find -relief raised -borderwidth 2 \
	    -state normal -takefocus 0 -command finder_make_window
    pack .toolbar.find -side left

    #
    # Server name
    #
    frame .server -relief flat
    pack .server -side top -fill x

    label .server.label -text "Server:" -relief flat -underline 0
    pack .server.label -side left

    menubutton .server.menubutton -text "(not selected)" -relief raised \
	    -bd 2 -menu .server.menubutton.menu -width 45
    pack .server.menubutton -side left -pady 2 -expand 1 -anchor w
    menu .server.menubutton.menu -tearoff 0
    bind .server.menubutton.menu <Escape> {
	.server.menubutton.menu unpost
	focus $saved_focus
    }

    #
    # Book title
    #
    frame .book -relief flat
    pack .book -side top -fill x

    label .book.label -text "Book:  " -relief flat -underline 0
    pack .book.label -side left

    menubutton .book.menubutton -text [ndtp_title 0] -relief raised \
	    -bd 2 -menu .book.menubutton.menu -width 45
    pack .book.menubutton -side left -pady 2 -expand 1 -anchor w
    menu .book.menubutton.menu -tearoff 0
    bind .book.menubutton.menu <Escape> {
	.book.menubutton.menu unpost
	focus $saved_focus
    }

    #
    # Word
    #
    frame .word -relief flat
    pack .word -side top -fill x

    label .word.label -text "Word:" -relief flat -underline 0
    pack .word.label -side left

    frame .word.toolbar -relief flat
    pack .word.toolbar -side right -expand 1 -fill x -padx 4 -pady 2
    button .word.toolbar.query -text "Query" -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 -command query_word
    pack .word.toolbar.query -side left -anchor w
    button .word.toolbar.qsel -text "Q Sel" -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 -command query_selection
    pack .word.toolbar.qsel -side left -anchor w
    button .word.toolbar.clear -text "Clear" -relief raised -borderwidth 2 \
	    -state disabled -takefocus 0 -command clear_word
    pack .word.toolbar.clear -side left -anchor w

    entry .word.entry -width 36 -relief sunken -borderwidth 2 \
	    -textvariable input_word -takefocus 0
    pack .word.entry -side left -pady 2
    bind .word.entry <Return> query_word
    bind .word.entry <Control-m> query_word

    #
    # Information
    #
    frame .information -relief flat
    pack .information -side bottom -anchor w -fill x
    label .information.information
    pack .information.information -side left -anchor w

    #
    # Hits
    #
    frame .hits -relief flat
    pack .hits -side top -fill both

    scrollbar .hits.scroll -command ".hits.text yview" -takefocus 0
    pack .hits.scroll -side right -fill y
    text .hits.text -relief sunken -borderwidth 2 -height $hits_height \
	    -yscrollcommand ".hits.scroll set"
    pack .hits.text -side left -fill both -expand 1
    .hits.text tag configure anchor -foreground blue -underline 1
    .hits.text tag bind anchor <Enter> {.hits.text configure -cursor hand2}
    .hits.text tag bind anchor <Leave> {.hits.text configure -cursor xterm}
    .hits.text tag bind anchor <Button-1> {
	get_entry_text $book_radiobutton \
		[lindex [.hits.text tag names "@%x,%y"] 1]
    }
    bind .hits.text <Return> {
	get_entry_text $book_radiobutton \
		[lindex [.hits.text tag names "insert lineend - 1 chars"] 1]
    }

    #
    # Text
    #
    frame .text -relief flat
    pack .text -side top -fill both -expand 1

    scrollbar .text.scroll -command ".text.text yview" -takefocus 0
    pack .text.scroll -side right -fill y
    text .text.text -relief sunken -borderwidth 2 -height 9 \
	    -yscrollcommand ".text.scroll set"
    pack .text.text -side left -fill both -expand 1
    .text.text tag configure anchor -foreground blue -underline 1
    .text.text tag bind anchor <Enter> {.text.text configure -cursor hand2}
    .text.text tag bind anchor <Leave> {.text.text configure -cursor xterm}
    .text.text tag bind anchor <Button-1> {
	put_new_text $history_book($history_current) \
		[lindex [.text.text tag names "@%x,%y"] 1]
    }
    bind .text.text <Return> {
	put_new_text $history_book($history_current) \
		[lindex [.text.text tag names insert] 1]
    }
    bind .text.text <space> go_next_link_tag
    bind .text.text <BackSpace> go_previous_link_tag

    #
    # For wheel mouse.
    #
    bind Text <Button-5> {%W yview scroll 5 units}
    bind Text <Button-4> {%W yview scroll -5 units}

    #
    # Prevent an user from editing Hits and Text.
    #
    bind Text <KeyPress> {}
    bind Text <Tab> {}
    bind Text <Return> {}
    bind Text <BackSpace> {}
    bind Text <Control-v> {tkTextSetCursor %W [tkTextScrollPages %W 1]}
    bind Text <M-v> {tkTextSetCursor %W [tkTextScrollPages %W -1]}
    bind Text <Control-u> {tkTextSetCursor %W [tkTextScrollPages %W -1]}

    #
    # Add some keybindngs to the Menu widget.
    #
    bind Menu <p> {tkMenuUpArrow %W}
    bind Menu <Control-p> {tkMenuUpArrow %W}
    bind Menu <n> {tkMenuDownArrow %W}
    bind Menu <Control-n> {tkMenuDownArrow %W}

    #
    # Add some keybindngs to the Entry widget.
    #
    bind Entry <Control-y> {catch {%W insert insert [selection get]}}
}

#
# Reconfigure the main window.
#
proc reconfigure_main_window {} {
    global toolbar_checkbutton
    global information_checkbutton
    global text_spacing

    pack forget .toolbar .hits .text .information
    pack .menubar -side top -fill x
    if {$toolbar_checkbutton} {
	pack .toolbar -side top -anchor w -pady 2 -fill x -before .server
    }
    pack .server -side top -fill x
    pack .book -side top -fill x
    pack .word -side top -fill x
    pack .information -side bottom -anchor w -fill x
    pack .hits -side top -fill both
    pack .text -side top -fill both -expand 1

    .text.text configure -spacing1 $text_spacing -spacing2 $text_spacing
}

#
# Output an information message at the bottom of the main window.
#
proc output_information {message} {
    .information.information configure -text $message
    update
}

#
# Quit.
#
proc quit {} {
    ndtp_close
    setup_save_file

    set widgets {.}
    for {set i 0} {$i < [llength $widgets]} {incr i} {
	foreach j [winfo children [lindex $widgets $i]] {
            bindtags $j dummy
	    lappend widgets $j
	}
    }
    bindtags . dummy
    destroy .
}    

#
# Set `Server' menu.
#
proc set_server_menu {} {
    global server_names
    global server_ports
    global server_radiobutton
    
    #
    # Set a radio button in `Server' menu to `nodict'.
    #
    set server_radiobutton 0

    #
    # Clear the widget.
    #
    .server.menubutton.menu delete 0 end

    #
    # Set `Server' menu.
    #
    .server.menubutton.menu add radiobutton -command {select_server 0} \
	    -label [format "%-45s" "(not selected)"] \
	    -variable server_radiobutton -value 0
    .server.menubutton.menu add separator

    set length [llength $server_names]
    for {set i 1} {$i <= $length} {incr i} {
	set hostname [lindex $server_names [expr $i - 1]]
	set port [lindex $server_ports [expr $i - 1]]
	.server.menubutton.menu add radiobutton -command "select_server $i" \
		-label [format "%-45s" "$hostname:$port"] \
		-variable server_radiobutton -value $i
    }
}

#
# Select a server.
#
proc select_server {server} {
    global server_names
    global server_ports
    global server_starts
    global history_current
    global history_top
    global history_bottom
    global history_size
    global ndtp_error_message
    global server_radiobutton
    global book_radiobutton
    global go_radiobutton

    set server_radiobutton 0
    set book_radiobutton 0
    set go_radiobutton {}

    #
    # Close an old connection.
    #
    if {[ndtp_is_active]} {
	output_information "Disconnected."
	ndtp_close
    }

    #
    # Disable and clear widgets.
    #
    .book.menubutton.menu delete 0 end
    if {0 <= $history_current} {
	.menubar.go.menu delete 3 end
    }
    .word.entry configure -state normal
    .word.entry delete 0 end
    .word.entry configure -state disabled -takefocus 0
    .hits.text delete 1.0 end

    .toolbar.back configure -state disabled
    .toolbar.next configure -state disabled
    .menubar.go.menu entryconfigure 0 -state disabled
    .menubar.go.menu entryconfigure 1 -state disabled
    .word.toolbar.query configure -state disabled
    .word.toolbar.qsel configure -state disabled
    .word.toolbar.clear configure -state disabled
    .toolbar.menu configure -state disabled
    .toolbar.copyright configure -state disabled
    .menubar.view.menu entryconfigure 0 -state disabled
    .menubar.view.menu entryconfigure 1 -state disabled
    .menubar.view.menu entryconfigure 2 -state disabled
    .menubar.view.menu entryconfigure 3 -state disabled
    .server.menubutton configure -text "(not selected)"
    .book.menubutton configure -text [ndtp_title 0]
    focus .

    #
    # Initialize history.
    # 
    set history_current -1
    set history_bottom -1
    set history_top -1

    #
    # Return if the server 0 is selected.
    #
    if {$server == 0} {
	return
    }

    #
    # Clear `Text:' area.
    #
    .text.text delete 1.0 end

    #
    # Connect to the server.
    #
    set hostname [lindex $server_names [expr $server - 1]]
    set port [lindex $server_ports [expr $server - 1]]
    set start [lindex $server_starts [expr $server - 1]]
    output_information "Connect to $hostname:$port..."
    set books {}
    if {![ndtp_open $hostname $port books]} {
	output_information $ndtp_error_message
	set server_radiobutton 0
	return
    }

    .server.menubutton configure -text "$hostname:$port"

    #
    # Update `Book' menu.
    #
    .book.menubutton.menu add radiobutton -command "select_book 0" \
	    -label [format "%-45s" [ndtp_title 0]] \
	    -variable book_radiobutton -value 0
    .book.menubutton.menu add separator
    foreach i $books {
	.book.menubutton.menu add radiobutton -command "select_book $i" \
		-label [format "%-45s" [ndtp_title $i]] \
		-variable book_radiobutton -value $i
    }
    
    #
    # Enable widgets.
    #
    .book.menubutton configure -state normal
    .menubar.view.menu entryconfigure 0 -state normal
    output_information "Connect to $hostname:$port...done."
    set server_radiobutton $server

    if {$start != "" && $start != "nodict"} {
	if {[catch {ndtp_title $start}]} {
	    output_information "Unknown book $start."
	} else {
	    select_book $start
	}
    } else {
	put_new_text nodict booklist
    }
}

#
# Select a book in `Book' menu.
#
proc select_book {book} {
    global ndtp_error_message
    global prefer_sizes
    global prefer_index
    global book_radiobutton
    global bitmap_checkbutton

    #
    # Disable and clear widgets.
    # 
    .hits.text delete 1.0 end

    .word.toolbar.query configure -state disabled
    .word.toolbar.qsel configure -state disabled
    .word.toolbar.clear configure -state disabled
    .toolbar.menu configure -state disabled
    .toolbar.copyright configure -state disabled
    .menubar.view.menu entryconfigure 1 -state disabled
    .menubar.view.menu entryconfigure 2 -state disabled
    .menubar.view.menu entryconfigure 3 -state disabled
    .word.entry configure -state disabled -takefocus 0
    .book.menubutton configure -text [ndtp_title 0]
    focus .

    #
    # Select a book.
    #
    output_information "Select [ndtp_title $book]..."
    if {![ndtp_select_book $book]} {
	output_information $ndtp_error_message
	set book_radiobutton 0
	.book.menubutton configure -text [ndtp_title 0]
	if {![ndtp_is_active]} {
	    select_server 0
	}
	return
    }
    .book.menubutton configure -text [ndtp_title $book]
    set book_radiobutton $book

    #
    # Return immediately if $book is `0' (= nodict).
    #
    if {$book == 0} {
	output_information "Select [ndtp_title $book]...done."
	return
    }

    #
    # Set bitmap size.
    #
    if {$bitmap_checkbutton == 1} {
	set sizes [lindex $prefer_sizes $prefer_index]
    } else {
	set sizes {}
    }
    if {![ndtp_select_bitmap_size $sizes]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	    return
	}
    }

    #
    # Set book title on the menu-button.
    #
    .book.menubutton configure -text [ndtp_title $book_radiobutton]

    #
    # Enable widgets.
    # 
    if {[ndtp_have_menu $book]} {
	.toolbar.menu configure -state normal
	.menubar.view.menu entryconfigure 1 -state normal
    }
    if {[ndtp_have_copyright $book]} {
	.toolbar.copyright configure -state normal
	.menubar.view.menu entryconfigure 2 -state normal
    }
    if {[ndtp_have_word_search $book]} {
	.word.entry configure -state normal -takefocus 1
	.menubar.view.menu entryconfigure 3 -state normal
	.word.toolbar.query configure -state normal
	.word.toolbar.qsel configure -state normal
	.word.toolbar.clear configure -state normal
	focus .word.entry
    }

    output_information "Select [ndtp_title $book]...done."
}    

#
# Query a word to a server.
#
proc query_word {} {
    global hit_positions
    global current_hit
    global input_word
    global ndtp_error_message
    global book_radiobutton
    global bitmap_checkbutton
    global prefer_sizes 
    global prefer_index

    set hit_positions {}
    set current_hit 0
    set hit_headings {}

    #
    # Disable and clear widgets.
    # 
    .hits.text delete 1.0 end

    #
    # Select book.
    #
    if {![ndtp_select_book $book_radiobutton]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	}
	return 0
    }
    if {$bitmap_checkbutton == 1} {
	set sizes [lindex $prefer_sizes $prefer_index]
    } else {
	set sizes {}
    }
    if {![ndtp_select_bitmap_size $sizes]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	    return 0
	}
    }

    #
    # Query a word to a server.
    # 
    regsub -all "\n" $input_word "" input_word
    if {$input_word == ""} {
	output_information "The word is empty."
	return 0
    }
    output_information "Query $input_word..."
    if {![ndtp_query_word $input_word hit_positions hit_headings]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	}
	return
    }

    #
    # Output hit entries received from a server.
    # 
    set length [llength $hit_positions]
    for {set i 0} {$i < $length} {incr i} {
	.hits.text image create end -image bitmap_space
	set heading [lindex $hit_headings $i]
	while {[regexp {([^<]*)<(.*)} $heading dummy head rest]} {
	    if {[regexp {^gaiji:([0-9A-Za-z]+)>(.*)} $rest dummy imageid \
		    tail]} {
		.hits.text insert end $head
		if {![catch {image type "$book_radiobutton/$imageid"}]} {
		    .hits.text image create end \
			    -image "$book_radiobutton/$imageid"
		}
		set heading $tail
	    } else {
		.hits.text insert end $head
		.hits.text insert end "<"
		set heading $rest
	    }
	}
	.hits.text insert end $heading
	.hits.text insert end  "(->text)\n" [list {anchor} $i]
    }
    .hits.text mark set insert 1.0

    #
    # Get text of the first entry in the listbox.
    #
    if {$length != 0} {
	get_entry_text $book_radiobutton 0
    }

    if {$length < 2} {
	output_information "Found $length entry."
    } else {
	output_information "Found $length entries."
    }
}

#
# Get text of an hit entry.
#
proc get_entry_text {book index} {
    global hit_positions
    global current_hit

    if {$index == ""} {
	return
    }

    set insert_index [.hits.text index insert]
    .hits.text delete [expr $current_hit + 1].0
    .hits.text image create [expr $current_hit + 1].0 -image bitmap_space
    .hits.text delete [expr $index + 1].0
    .hits.text image create [expr $index + 1].0 -image bitmap_arrow
    set current_hit $index
    put_new_text $book [lindex $hit_positions $index]
    .hits.text mark set insert $insert_index
}

#
# Query a word in X selection.
# 
proc query_selection {} {
    global input_word
    if {[catch {set input_word [selection get]}]} {
	set input_word ""
    }
    query_word
}

#
# Clear the word entry space.
# 
proc clear_word {} {
    global input_word
    set input_word {}
}    

#
# Get new text.
# 
proc put_new_text {book position} {
    global history_book
    global history_position
    global history_fraction
    global history_cursor
    global history_insertion
    global history_size
    global history_current
    global history_top
    global history_bottom
    global go_radiobutton

    if {$book == "" || $position == ""} {
	return
    }

    #
    # Save the current fraction and cursor of the text widget.
    #
    if {0 <= $history_current} {
	set history_fraction($history_current) [lindex [.text.scroll get] 0]
	set history_cursor($history_current) [.text.text index insert]
	.toolbar.back configure -state normal
	.menubar.go.menu entryconfigure 0 -state normal
    }

    #
    # Put text.
    # 
    if {![put_text $book $position]} {
	return
    }

    #
    # Update history.
    # The top three elements in .menubar.go.menu are `Back', `Next' and 
    # a separator.  We don't remove them.
    # 
    if {0 <= $history_current} {
	while {$history_top != $history_current} {
	    .menubar.go.menu delete 3
	    set history_top [expr ($history_top - 1) % $history_size]
	}
	set history_top [expr ($history_top + 1) % $history_size]
	if {$history_top == $history_bottom} {
	    .menubar.go.menu delete [expr 3 + $history_size - 1]
	    set history_bottom [expr ($history_bottom + 1) % $history_size]
	}
    } else {
	set history_top 0
	set history_bottom 0
    }
    set history_current $history_top

    set headline [kstring range [.text.text get 1.0 1.end] 0 40]
    set history_book($history_current) $book
    set history_position($history_current) $position
    set history_fraction($history_current) 0.0
    set history_cursor($history_current) 1.0
    .menubar.go.menu insert 3 radiobutton -label $headline \
	    -command "go_history $history_current" \
	    -variable go_radiobutton -value $history_top
    set go_radiobutton $history_current

    #
    # Setup `next' and `back' buttons.
    # 
    .toolbar.next configure -state disabled
    .menubar.go.menu entryconfigure 1 -state disabled
    if {$history_current == $history_bottom} {
	.toolbar.back configure -state disabled
	.menubar.go.menu entryconfigure 0 -state disabled
    } else {
	.toolbar.back configure -state normal
	.menubar.go.menu entryconfigure 0 -state normal
    }
}

#
# Go to the specified entry in history.
#
proc go_history {history_id} {
    global history_book
    global history_position
    global history_fraction
    global history_cursor
    global history_current
    global history_top
    global history_bottom
    global go_radiobutton

    #
    # Update history.
    #
    set history_fraction($history_current) [lindex [.text.scroll get] 0]
    set history_cursor($history_current) [.text.text index insert]
    set history_current $history_id
    set go_radiobutton $history_current

    #
    # Put text.
    #
    if {![put_text $history_book($history_current) \
	    $history_position($history_current) \
	    $history_fraction($history_current) \
	    $history_cursor($history_current)]} {
	return
    }

    #
    # Setup `next' and `back' buttons.
    # 
    if {$history_current == $history_top} {
	.toolbar.next configure -state disabled
	.menubar.go.menu entryconfigure 1 -state disabled
    } else {
	.toolbar.next configure -state normal
	.menubar.go.menu entryconfigure 1 -state normal
    }
    if {$history_current == $history_bottom} {
	.toolbar.back configure -state disabled
	.menubar.go.menu entryconfigure 0 -state disabled
    } else {
	.toolbar.back configure -state normal
	.menubar.go.menu entryconfigure 0 -state normal
    }
}    

#
# Get a text.
#
proc put_text {book position {fraction 0.0} {cursor 1.0}} {
    global prefer_sizes
    global prefer_index
    global ndtp_error_message
    global bitmap_checkbutton

    if {$position == "booklist"} {
	return [put_book_list $fraction $cursor]
    }

    #
    # Disable and clear widget.
    # 
    .text.text delete 1.0 end

    #
    # Select book.
    #
    if {![ndtp_select_book $book]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	}
	return 0
    }
    if {$bitmap_checkbutton == 1} {
	set sizes [lindex $prefer_sizes $prefer_index]
    } else {
	set sizes {}
    }
    if {![ndtp_select_bitmap_size $sizes]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	    return 0
	}
    }

    #
    # Send a request to the current server.
    # 
    output_information "Get text..."
    if {![ndtp_get_text $position text]} {
	output_information $ndtp_error_message
	if {![ndtp_is_active]} {
	    select_server 0
	}
	return 0
    }

    #
    # Collect link tags.
    # 
    while {[regexp {([^<]*)<(.*)} $text dummy head rest]} {
	if {[regexp {^([0-9A-Fa-f]+:[0-9A-Fa-f]+)>(.*)} $rest dummy \
		position tail]} {
	    .text.text insert end $head
	    .text.text insert end "(->link)" [list {anchor} $position]
	    set text $tail
	} elseif {[regexp {^gaiji:([0-9A-Za-z]+)>(.*)} $rest dummy imageid \
		tail]} {
	    .text.text insert end $head
	    if {![catch {image type "$book/$imageid"}]} {
		.text.text image create end -image "$book/$imageid"
	    }
	    set text $tail
	} else {
	    .text.text insert end $head
	    .text.text insert end "<"
	    set text $rest
	}
    }
    .text.text insert end "$text\n"
    .text.text yview moveto $fraction
    .text.text mark set insert $cursor

    output_information "Get text...done."
    return 1
}    

#
# Put book list.
#
proc put_book_list {{fraction 0.0} {cursor 1.0}} {
    set length [.book.menubutton.menu index end]

    #
    # Disable and clear widget.
    # 
    .text.text delete 1.0 end

    .text.text insert end "Book list of this server\n"
    for {set i 2} {$i <= $length} {incr i} {
	set id [.book.menubutton.menu entrycget $i -value]
	set title [.book.menubutton.menu entrycget $i -label]
	.text.text insert end "  book title = $title\n"
	.text.text insert end "  book ID    = $id\n\n"
    }
    .text.text yview moveto $fraction
    .text.text mark set insert $cursor

    return 1
}

#
# Move insertion cursor on Text to the next link tag.
#
proc go_next_link_tag {} {
    set tag_range [.text.text tag nextrange anchor insert]
    if {$tag_range != ""} {
	.text.text mark set insert "[lindex $tag_range 0] + 1 chars"
    }
    .text.text see insert
}

#
# Move the insertion cursor on Text to the previous link tag.
#
proc go_previous_link_tag {} {
    set tag_range [.text.text tag prevrange anchor "insert - 2 chars"]
    if {$tag_range != ""} {
	.text.text mark set insert "[lindex $tag_range 0] + 1 chars"
    }
    .text.text see insert
}

startup

# Local Variables: 
# mode: tcl
# End: 
