# Chat.tcl
# Copyright 2005 Emiel Bruijntjes
# All rights reserved

# List of ignored users
set Chat_IgnoredUsers {}

# Check if a user is ignored
proc Chat_IsIgnored {nickname} {

	# Use a global variable
	global Chat_IgnoredUsers

	# Check if nickname is in list	
	return [expr [lsearch -exact $Chat_IgnoredUsers $nickname] >= 0]
}

# Mark a user as ignored or not ignored
proc Chat_Ignore {nickname} {

	# Use a global variable
	global Chat_IgnoredUsers

	# Current index in the list
	set index [lsearch -exact $Chat_IgnoredUsers $nickname]

	# Check if user is already ignored
	if {$index < 0} {

		# User is not ignored, ignore it now
		lappend Chat_IgnoredUsers $nickname

		# Strikeout the name of the user in the chatboxes
		chatbox global strikeout $nickname yes
		chatbox game strikeout $nickname yes
		chatbox member strikeout $nickname yes
	
	} else {

		# User is already ignored, remove from the list
		set Chat_IgnoredUsers [lreplace $Chat_IgnoredUsers $index $index]

		# Remove the strikeout
		chatbox global strikeout $nickname no
		chatbox game strikeout $nickname no
		chatbox member strikeout $nickname no
	}
}

# Check if a user was recently active
proc Chat_NotActive {nickname} {

	if {[userinfo active $nickname] > 300} {
		
		# user was active more than 300 seconds ago: not active
		return 1

	} else {

		# user was active during the last five minutes
		return 0
	}
}

# Procedure returns the circle color for a player
proc Chat_CircleColor {nickname} {

	# Fetch player-ID
	set id [playerinfo number $nickname yes]

	# Use default color when id is not valid
	if {$id < 0} {
		
		# Not a player, use default color
		return white
	
	} else {

		# Use color
		return [color background $id]
	}
}

# Procedure returns the text color of player
proc Chat_TextColor {isFriend isEnemy isAdmin} {

	# blue if user is admin
	if {$isAdmin} {
		return "darkblue"
	}

	# red if user is an enemy
	if {$isEnemy} {
		return "red"
	}

	# green if user is a friend
	if {$isFriend} {
		return "darkgreen"
	}

	# black by default
	return "black"
}

# Procedure is called whenever a new user logs on
proc Chat_OnNewUserMessage {nickname hostname} {

	# Add a nickname to the global chatbox
	chatbox global adduser $nickname

	# User should be striked out?
	chatbox global strikeout $nickname [Chat_IsIgnored $nickname]

	# Check if the application is initialized. If the application is not yet
	# initialized, it is still receiving set-up information from the server that
	# we do not want to display in the chatbox
	if {[status initialized] || $nickname == [status nickname]} {

		# The application is initialized, add a message to the global chatbox
		chatbox global output lightgray darkgreen "$nickname ($hostname) logs on" [Chat_NotActive $nickname]
	}
}

proc Chat_OnUserMessage {nickname rating games gameID isPlayer isObserver isMember smilie isAdmin level} {

	# Check if the user becomes an admin or loses his adminship
	if {$isAdmin != [userinfo admin $nickname]} {

		# What color to use?
		set color [Chat_TextColor [userinfo friend $nickname] [userinfo enemy $nickname] $isAdmin]

		# Mark the user in the chatboxes
		chatbox global color $nickname $color
		chatbox game color $nickname $color
		chatbox member color $nickname $color
	}

	# Store some info in local variables for faster use
	set myNickname [status nickname]
	set initialized [status initialized]
	set myGameID 0
	set hostname [userinfo hostname $nickname]
	set notActive [Chat_NotActive $nickname]

	# GameID is only set if game is initialized
	if {$initialized} {
		set myGameID [userinfo game $myNickname]
	}

	# Check if someone joins our game
	if {![userinfo game $nickname] && $gameID && $initialized && ($gameID == $myGameID || $nickname == $myNickname)} {

		# We join a game or a user joins our game, add user to the game dialog 
		chatbox game adduser $nickname

		# Strikeout the user if he is ignored
		chatbox game strikeout $nickname [Chat_IsIgnored $nickname]

		# What color to use?
		set color [Chat_TextColor [userinfo friend $nickname] [userinfo enemy $nickname] $isAdmin]

		# Set the color
		chatbox game color $nickname $color

		# Display a message
		chatbox game output lightgray darkgreen "$nickname ($hostname) has joined the game" $notActive
	}

	# Check if someone leaves our current game
	if {!$gameID && $myGameID && $myGameID == [userinfo game $nickname]} {
		
		# Remove the user from the list
		chatbox game removeuser $nickname

		# Display a message
		chatbox game output lightgray red "$nickname has left the game" $notActive
	}

	# Check if we join or leave a game
	if {$nickname == $myNickname && $myGameID != $gameID} {

		# Reset the game chatbox
		chatbox game reset

		# Check if we join a game
		if {$gameID} {

			# The users who already are in the game
			set users [gameinfo users $gameID]
			set count [llength $users]

			# Loop through the users and add them to the game chatbox
			for {set i 0} {$i < $count} {incr i} {

				# The nickname
				set n [lindex $users $i]

				# Add the user to the chatbox
				chatbox game adduser $n

				# Is the user ignored?
				chatbox game strikeout $n [Chat_IsIgnored $n]

				# The color of the user
				set color [Chat_TextColor [userinfo friend $n] [userinfo enemy $n] [userinfo admin $n]]
				
				# Set the color
				chatbox game color $n $color
			}

			# Add our own nickname to the chatbox as well
			chatbox game adduser $myNickname

			# Are we ignoring ourselves?
			chatbox game strikeout $myNickname [Chat_IsIgnored $myNickname]

			# Our own color
			set color [Chat_TextColor [userinfo friend $nickname] [userinfo enemy $nickname] $isAdmin]
				
			# Set the color
			chatbox game color $nickname $color
		}
	}

	# Check if someone loses his member status, and we're a member ourselves
	if {$initialized && [userinfo member $myNickname] && [userinfo member $nickname] && !$isMember} {

		# The user no longer is a member, add a message
		chatbox member output lightgray red "$nickname has left the members" $notActive

		# Remove the nickname from the list
		chatbox member removeuser $nickname

		# If we were the user who lost his member status, reset the chatbox
		if {$nickname == $myNickname} {

			# Reset the chatbox
			chatbox member reset
		}
	}

	# Check if someone becomes a member
    if {![userinfo member $nickname] && $isMember && $initialized && ([userinfo member $myNickname] || $nickname == $myNickname)} {

		# Someone becomes a member, check if we are the lucky one
		if {$nickname == $myNickname} {

			# We become a member, get access to the list of all members
			set users [users]
			set count [llength $users]

			# Loop through the users
			for {set i 0} {$i < $count} {incr i} {

				# Store nickname in tmp var
				set tmpname [lindex $users $i]

				# If the user is a member, add him to the chatbox
				if {[userinfo member $tmpname]} {

					# Add nickname to the chatbox
					chatbox member adduser $tmpname

					# Strikeout user if it is ignored
					chatbox member strikeout $tmpname [Chat_IsIgnored $tmpname]

					# The color of the user
					set color [Chat_TextColor [userinfo friend $tmpname] [userinfo enemy $tmpname] [userinfo admin $tmpname]]
				
					# Set the color
					chatbox member color $tmpname $color
				}
			}
		}

		# Add the user to the list of users
		chatbox member adduser $nickname

		# Strikeout user if it is ignored
		chatbox member strikeout $nickname [Chat_IsIgnored $nickname]

		# Display a message in the members chatbox
		chatbox member output lightgray darkgreen "$nickname ($hostname) has joined the members" $notActive

		# The color of the user
		set color [Chat_TextColor [userinfo friend $nickname] [userinfo enemy $nickname] $isAdmin]
	
		# Set the color
		chatbox member color $nickname $color
	}
}

# Procedure is called when a user signs off
proc Chat_OnEndUserMessage {nickname} {

	# check if user is active
	set notActive [Chat_NotActive $nickname]

	# Remove the user from the global chatbox
	chatbox global output lightgray red "$nickname logs off" $notActive

	# Store some info in local variables for faster use
	set myNickname [status nickname]
	set initialized [status initialized]
	set myGameID 0

	# GameID is only set if game is initialized
	if {$initialized} {
		set myGameID [userinfo game $myNickname]
	}

	# Check if the user was in our game
	if {$myGameID && $myGameID == [userinfo game $nickname]} {

		# User was in our game, display a message
		chatbox game output lightgray red "$nickname has left the game" $notActive
	}

	# Check if the user was a member
	if {$initialized && [userinfo member $myNickname] && [userinfo member $nickname]} {

		# User was a member, display a message
		chatbox member output lightgray red "$nickname has left the members" $notActive
	}

	# Remove the user from all chatboxes
	chatbox global removeuser $nickname
	chatbox game removeuser $nickname
	chatbox member removeuser $nickname
}

# Procedure is called when a chat message is received from the server
proc Chat_OnChatMessage {chatbox nickname message} {

	# find appropriate color
	set color [Chat_CircleColor $nickname]

	# Add message to chatbox
	chatbox $chatbox output $color black "$nickname: $message" 0

	# Mark the chatbox as active
	chatbox $chatbox active
}

# Proc is called when a message is entered in the chatbox
proc Chat_OnMessage {chatbox message} {

	# Our nickname
	set nickname [status nickname]

	# find appropriate color
	set color [Chat_CircleColor $nickname]

	# Skip when game message is entered while we are not in a game
	if {$chatbox == "game" && ![userinfo game $nickname]} return

	# Display the message in the chatbox
	chatbox $chatbox output $color darkblue "$nickname: $message" 0

	# Send the message to the server
	send chat $chatbox $message
}

# Proc is called when a whisper message from the server is caught
proc Chat_OnWhisperMessage {nickname text} {

	# find appropriate color
	set color [Chat_CircleColor $nickname]

	# Add message to whisper box
	whisper output $nickname $color black "$nickname: $text"

	# Mark the whisper box as active
	whisper active $nickname
}

# Proc is called when user enters a message in a whisper box
proc Chat_OnWhisper {nickname text} {

	# Check if we're in a game
	set myNickname [status nickname]
	set initialized [status initialized]

	# Skip when not yet initialized, its impossible to chat then
	if {!$initialized} return

	# Id of our current game
	set gameID [userinfo game $myNickname]

	# Check if we're in a game and whispering is not allowed
	if {$gameID && [gameinfo nowhispers $gameID] && ![userinfo admin $myNickname]} {

		# whisper not allowed
		whisper output $nickname red black "Your current game does not allow private messages"
	
	} else {

		# find appropriate color
		set color [Chat_CircleColor $myNickname]

		# display the whisper
		whisper output $nickname $color darkblue "$myNickname: $text"

		# send the message to the server
		send whisper $nickname $text
	}
}

# Proc is called when the whisper button is clicked
proc Chat_OnWhisperButton {nickname} {

	# TODO: check if user is ignored
	
	# Open whisper window
	whisper open $nickname
}

# Proc is called when close button is clicked on a whisper box
proc Chat_OnCloseButton {nickname} {

	# Close the whisper tab
	whisper close $nickname
}

# Proc is called when someone becomes a friend
proc Chat_UserBecomesFriend {nickname isFriend} {

	# Find out the color
	set color [Chat_TextColor $isFriend [userinfo enemy $nickname] [userinfo admin $nickname]]

	# Change chatboxes
	chatbox global color $nickname $color
	chatbox game color $nickname $color
	chatbox member color $nickname $color
}

# Proc is called when someone becomes an enemy
proc Chat_UserBecomesEnemy {nickname isEnemy} {

	# Find out the color
	set color [Chat_TextColor [userinfo friend $nickname] $isEnemy [userinfo admin $nickname]]

	# Change chatboxes
	chatbox global color $nickname $color
	chatbox game color $nickname $color
	chatbox member color $nickname $color
}

# Register the callback procedures. For every procedure, we use
# weight 10. It is possible to register multiple procedures. The
# procedures will then be sorted by weight and the lightest one
# is called first
on 10 server_newuser		Chat_OnNewUserMessage
on 10 server_user			Chat_OnUserMessage
on 10 server_enduser		Chat_OnEndUserMessage
on 10 server_chat			Chat_OnChatMessage
on 10 server_whisper		Chat_OnWhisperMessage
on 10 chat_message			Chat_OnMessage
on 10 chat_whisper			Chat_OnWhisper
on 10 chat_whisperbutton	Chat_OnWhisperButton
on 10 chat_closebutton		Chat_OnCloseButton
on 10 chat_ignore			Chat_Ignore
on 10 user_becomes_friend	Chat_UserBecomesFriend
on 10 user_becomes_enemy	Chat_UserBecomesEnemy

