# OpenVerse Passageways Module
# 
# this file initalizes the program and does any
# platform specific things/setup. It will then source 
# supporting modules.
#
# Module Name		- Passageways Module
# Current Maintainter 	- Cruise <cruise@openverse.org>
# Sourced By		- Init Main Window
#
# Modifications by KaosBeetl:
#    Room History, 01/16/2000, revised 02/07/2000, 02/09/2000, 02/12/2000
#
# Copyright (C) 1999 David Gale <cruise@openverse.org>
# For more information visit http://OpenVerse.org/
#
# 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
# of the License, 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.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
# USA.

#Performance enhancements using string compare
# Now using curley braces to increase performance

proc DoBookmarks {} {
	global MV

	destroy $MV(passageways_menu).m

	if {!$MV(use_windowmanager_colors)} {
		menu $MV(passageways_menu).m -bg $MV(colors.pw.bg) \
			-fg $MV(colors.pw.fg) -activeforeground $MV(colors.pw.afg) \
			-activebackground $MV(colors.pw.abg)
	} else {
		menu $MV(passageways_menu).m
	}

	$MV(passageways_menu).m add command -label [Trns add_current_room] \
		-command "AddBookmark"
	$MV(passageways_menu).m add command -label [Trns refresh_list] \
		-command "QueryServers 1"

 	set MV(pwq.queries) 0
 	set server 0
 
	# History and Passageways menu code merged; KaosBeetl 02/07/2000
	foreach filename [list $MV(history) $MV(bookmarks)] \
		menudef [list [Trns history] [Trns passageways]] \
		getsdepth [list 0 1] {
	    set depth 0
	    set marks 0
	    if {[file exists "$filename"]} {
		set depth 0
		set infile [open "$filename" r]
		while {[eof $infile] != 1} {
		    gets $infile input
		    set bm [split $input "|"]
		    set serv [split [lindex $bm 1] ":"]
		    if {[string first "|" $input] != -1} {
			if {!$depth} {
			    incr depth
			    if {$getsdepth} {
				set menulabel "$menudef $depth"
			    } else {
				set menulabel "$menudef"
			    }
			    $MV(passageways_menu).m add cascade -menu \
				    $MV(passageways_menu).m.m$menudef$depth -label "$menulabel"
			    if {!$MV(use_windowmanager_colors)} {					
				menu $MV(passageways_menu).m.m$menudef$depth -bg $MV(colors.pw.bg) \
					-fg $MV(colors.pw.fg) -activeforeground $MV(colors.pw.afg) \
					-activebackground $MV(colors.pw.abg)
			    } else {
				menu $MV(passageways_menu).m.m$menudef$depth
			    }
			} 
			set prepend ""
			if {[info exists MV(pwq.$server.users)]} {
				append prepend "($MV(pwq.$server.users)) ($MV(pwq.$server.users)) "
			}
			set name_label "$prepend [lindex $bm 0] [HistoryAge [lindex $bm 2]]"
			set MV(pwq.queries) "$server"
			set MV(pwq.$server.name) "$name_label"
			set MV(pwq.$server.short_name) "[lindex $bm 0] [HistoryAge [lindex $bm 2]]"
			set MV(pwq.$server.host) "[lindex $serv 0]"
			set MV(pwq.$server.port) "[lindex $serv 1]"
			set MV(pwq.$server.menu) "$MV(passageways_menu).m.m$menudef$depth"
			$MV(passageways_menu).m.m$menudef$depth add command -label "$name_label" \
				-command "ConnectToRoom [lindex $serv 0] [lindex $serv 1]"
			if {[info exists MV(pwq.$server.users)]} {
				$MV(pwq.$server.menu) entryconfigure $MV(pwq.$server.name) -label "$name_label" -foreground $MV(pwq.$server.color) -activeforeground $MV(pwq.$server.color)
			}
			if {$getsdepth} {
			    incr marks
			}
			incr server
			if {$marks > 19} {
			    # this will only happen if $getsdepth is set
			    incr depth
			    $MV(passageways_menu).m add cascade -menu \
				    $MV(passageways_menu).m.m$menudef$depth -label "$menudef $depth"
			    if !$MV(use_windowmanager_colors) {
				menu $MV(passageways_menu).m.m$menudef$depth -bg $MV(colors.pw.bg) \
					-fg $MV(colors.pw.fg) -activeforeground $MV(colors.pw.afg) \
					-activebackground $MV(colors.pw.abg)
			    } else {
				menu $MV(passageways_menu).m.m$menudef$depth
			    }
			    set marks 0
			}
		    }
		}
		close $infile
	    }
	}
}

proc AddBookmark {} {
	global MV

	set outfile [open "$MV(bookmarks)" a+]
	puts $outfile "$MV(roomname)|$MV(roomhost):$MV(roomport)|[clock seconds]"
	close $outfile
	DoBookmarks
}

#
# Will query all servers in the passageways list
# and retrieve a number of users on each server.
# It will also note the time it took to respond to the query.
#
# This information will be stored into an array for future use when
# updating the history information when changing rooms.
#
proc QueryServers {BookMark} {
	global MV

	if {[llength $MV(server_queries)] > 0} {return}
	set MV(nosort) 1
	if $BookMark {
		DoBookmarks
	}
	set time 500
	for {set c 0} {$c <= $MV(pwq.queries)} {incr c} {
		lappend MV(server_queries) $c
		after $time "PWQueryServer $c"
		incr time 500
		update idletasks
	}
}

proc PWQueryServer {idx} {
	global MV

	set MV(pwq.$idx.sock) -1
	set sck -1
	catch {set sck [socket -async $MV(pwq.$idx.host) $MV(pwq.$idx.port)]}
	catch {fconfigure $sck -blocking 0}
	set MV(pwq.$idx.sock) $sck
	set MV(pwq.$idx.time) [clock seconds]
	after 30000 "PWKillRequestSocket $idx"
	catch {puts $MV(pwq.$idx.sock) "USERS"}
	catch {flush $MV(pwq.$idx.sock)}
	update idletasks
	catch {fileevent $MV(pwq.$idx.sock) readable "PWGetUsers $idx"}
}

proc PWGetUsers {idx} {
	global MV

	set input "AUTH REQD"
	catch {gets $MV(pwq.$idx.sock) input}
	if {[eof $MV(pwq.$idx.sock)]} {
		set MV(pwq.$idx.time) 0
		set id [lsearch -exact $MV(server_queries) $idx]
		set MV(server_queries) [lreplace $MV(server_queries) $id $id]
		catch {close $MV(pwq.$idx.sock)}
		return
	}
	DebugIt "<-(P) [eof $MV(pwq.$idx.sock)] $MV(pwq.$idx.sock) $input" prot
	set parms [split $input]
	set users [lindex $parms 1]
	set tme [expr [clock seconds] - $MV(pwq.$idx.time)]
	switch -exact -- [lindex $parms 0] {
		"PING" { 
			return
		}
		"AUTH" {
			$MV(pwq.$idx.menu) entryconfigure $MV(pwq.$idx.name) -label "(??) ($tme S) $MV(pwq.$idx.short_name)" -foreground red -activeforeground red
			set MV(pwq.$idx.users) "??"
			set MV(pwq.$idx.time) $tme
			set MV(pwq.$idx.color) "red"
		}
		"USERS" {
			# Performance Enhancement
			if {[string compare $users ""] && $users > 0} {
				$MV(pwq.$idx.menu) entryconfigure $MV(pwq.$idx.name) -label "($users) ($tme S) $MV(pwq.$idx.short_name)" -foreground blue -activeforeground blue
				set MV(pwq.$idx.color) "blue"
			} else {
				$MV(pwq.$idx.menu) entryconfigure $MV(pwq.$idx.name) -label "($users) ($tme S) $MV(pwq.$idx.short_name)" -foreground "dark green" -activeforeground "dark green"
				set MV(pwq.$idx.color) "dark green"
			}
			set MV(pwq.$idx.users) "$users"
			set MV(pwq.$idx.time) $tme
		}
		default {return}
	}
	set MV(pwq.$idx.time) 0
	set id [lsearch -exact $MV(server_queries) $idx]
	set MV(server_queries) [lreplace $MV(server_queries) $id $id]
	catch {close $MV(pwq.$idx.sock)}
	update idletasks
}

proc PWKillRequestSocket {idx} {
	global MV

	if !$MV(pwq.$idx.time) {
		set id [lsearch -exact $MV(server_queries) $idx]
		set MV(server_queries) [lreplace $MV(server_queries) $id $id]
		return
	}
	catch {close $MV(pwq.$idx.sock)}
	$MV(pwq.$idx.menu) entryconfigure $MV(pwq.$idx.name) -label "(--) (TO) $MV(pwq.$idx.short_name)" -foreground red -activeforeground red
	set MV(pwq.$idx.users) "--"
	set MV(pwq.$idx.time) 0
	set MV(pwq.$idx.color) "red"
	set id [lsearch -exact $MV(server_queries) $idx]
	set MV(server_queries) [lreplace $MV(server_queries) $id $id]
}

# Returns a human-readable form of the difference between $time and 
# current time, in seconds, minutes, hours, days, or "long time"
# KaosBeetl 02/07/2000
proc HistoryAge {time} {
    if {![string compare $time ""] || ($time == 0)} {
	return "(unknown)"
    }

    set age [ expr [clock seconds] - $time ]

    if { $age < 60 } {
	if { $age > 0 } {
	    set age_val $age
	} else {
	    set age_val 0
	}
	set age_unit "sec"
    } elseif { $age < 3600 } {
	set age_val [ expr $age / 60 ]
	set age_unit "min"
    } elseif { $age < 86400 } {
	set age_val [ expr $age / 3600 ]
	set age_unit "hour"
    } elseif { $age > 31536000 } {
	# more than 365 days (86400 * 365)
	return "(long time)"
    } else {
	set age_val [ expr $age / 86400 ]
	set age_unit "day"
    } 

    if { $age_val == 0 } {
	return ""
    }

    if { $age_val == 1 } {
	return "($age_val $age_unit)"
    }

    # note the added s
    return "($age_val ${age_unit}s)"
}

# Updates history and passageways file, setting the last use time for the
# current server to the current time.  Sorts history, and optionally sorts
# passageways.
# KaosBeetl 02/07/2000
proc UpdatePassageways {} {
    global MV
    
    foreach filename [list $MV(bookmarks) $MV(history)] \
	    getssort [list $MV(sort_bookmarks) 1] \
	    max [list 9999 $MV(history_max)] {
	set found 0
	set cur_list [list]
	DebugIt "Processing $filename" other
	if [file exists "$filename"] {
	    set infile [open "$filename" r]
	    while {[eof $infile] != 1} {
		gets $infile input
		set bm [split $input "|"]
		
		if {[string first "|" $input] != -1} {
		    set cur_entry [list]
		    set name "[lindex $bm 0]"
		    set thisserv "[split [lindex $bm 1] ":"]"
		    set host "[lindex $thisserv 0]"
		    set port [lindex $thisserv 1]
		    set time [lindex $bm 2]
		    
		    if {![string compare $time ""]} {
			set time 0
		    }
		    
		    # see if this is the current server
		    if {![string compare $MV(roomhost) $host] && \
			    ![string compare $MV(roomport) $port]} {
			if {!$found} {
			    # update name and time
			    set name "$MV(roomname)"
			    set time [clock seconds]
			    set found 1
			} else {
			    set host ""
			}
		    }
		    
		    if {[string compare $host ""]} {
			set cur_entry [list $name $host $port $time]
			lappend cur_list $cur_entry
		    }
		}
	    }
	}
	
	if {![string compare $filename $MV(history)]} {
	    # for history pass, make sure current room is in
	    if {!$found} {
		set cur_entry [list $MV(roomname) $MV(roomhost) $MV(roomport) [clock seconds]]
		lappend cur_list $cur_entry
		set found 1
	    }
	}
	
	if {$getssort && !$MV(nosort)} {
	    # sort by visiting time
	    set cur_list [lsort -integer -decreasing -index 3 $cur_list]
	}
	
	# write them back out, if necessary
	if {$found} {
	    set outfile [open "$filename" w]
	    set ct 1
	    
	    foreach cur_entry $cur_list {
		if {$ct > $max} {
		    break
		} else {
		    incr ct
		}
		puts $outfile "[lindex $cur_entry 0]|[lindex $cur_entry 1]:[lindex $cur_entry 2]|[lindex $cur_entry 3]"
	    }
	    
	    close $outfile
	}
    }
    DoBookmarks
}

