#!/usr/bin/env ruby
# $Revision: 1.32 $
# $Date: 2003/12/06 18:12:08 $
# $Author: jefus, mikeman2 $

class Connection
	attr_accessor :socket, :address, :name, :player

	def initialize(socket)
		@socket = socket
		@address = [@socket.peeraddr[3], @socket.peeraddr[1]]
		@name = "someone"
		@player = nil

		Logger.log("#{self} connected.")
		Thread.abort_on_exception = true
		Thread.start do
			write(IO.readlines("../banner").join.gsub(/\n/, "\n\r"))
			# do login stuff
			write("login: ")
			begin # any errors are passed on to the drop method for clean handling
				@name = gets(nolog = true).capitalize

				# try and load the specified player from the database
				if $system.pidHash.attributes.key?(@name)
					@player = Player.new($system.pidHash[@name])
					# player exists, so attach the connection object to it
					@player.connection = self

					# now we'll verify the password
					write("Password: ")
					if gets(nolog = true, obfuscate = true).encrypt.dump.delete('\\').chop.reverse.chop.reverse == $system.passwd[@name] #don't even ask :P
						# matches. greet the player and send him into the game.
						Logger.log("#{@address[0]}:#{@address[1]} authenticated as #{@name}")
						puts(IO.readlines("../motd").join.gsub(/\n/, "\n\r"))
						@player.enterGame
					else
						puts("Wrong password.")
						drop("wrong password")
					end
				else #god this took about 4 hours to debug.  why does crypt have to return a string containing bogus escape chars?
					pid = $system.pidHash.attributes.length #we would want to add 1 but the first pid is 0
					@player = Player.new(pid)
					@player.name = @name
					@player.connection = self
					$system.pidHash[@name] = pid.to_s

					# try and try until the player gets this shit right
					passwordsMatch = false
					while not passwordsMatch
						write("Choose a password: ")
						password = gets(nolog = true)
						write("Enter it again to confirm: ")
						password2 = gets(nolog = true)
						if password == password2
							passwordsMatch = true # exit the loop after this
							puts("#{@player} created.")
							$system.passwd[@name] = password.encrypt.dump.delete('\\').chop.reverse.chop.reverse #hehe.. gotta format the passwd hash so it stores properly in the database
						else
							# i felt like ganking this line from lima. this will all be
							# done on the web in the future anyways.
							puts("Socks don't have to match, but passwords do. Try again.") #this is the worst joke i've heard all week
						end
					end
					@player.enterGame(new = true)
					@player.save
					Logger.log("#{self}> New user successfully created.")
				end
				
			rescue
				drop($!)
				break
			end

			# main command loop
			while true
				# note from jefus to jefus: add some prompt code here, and some in
				# player.rb
				begin
					line = gets
					command, args = line.split(/ /, 2)
					command.downcase! if command
					args = "" if not args

					case command # built-in aliases... for now
					when "l"
						command = "look"
					when "n"
						command = "north"
					when "s"
						command = "south"
					when "e"
						command = "east"
					when "w"
						command = "west"
					when "u"
						command = "up"
					when "d"
						command = "down"
					when "o"
						command = "out"
					when "inv"
						command = "inventory"
					end

					method = "do_#{command}"

					#p command
					#p $system.commands
					handled = false
					if $system.commands.include?(command)
						access = $system.commands[command].access
						if @player.access >= access
							Commands.send(method, @player, args)
						else
							@player.puts("You don't have access to that command.")
							handled = true
						end
					else
						if @player.location
							if @player.location.has_exit?(command)
								handled = true
								@player.puts("You go #{command}.")
								@player.move($system.rooms.fetch(@player.location.exit(command).rid))
							#else
							#	puts("Huh?")
							end
						end
						if command =~ /'(.+)/
							handled = true
							Commands.send("do_say", @player, "#{$1} " << args) if args.length > 0
							Commands.send("do_say", @player, $1) if args == ""
						else
							@player.puts("Huh?") if handled == false
						end
					
					end
				rescue
					drop($!)
					break
				end
			end
		end
	end

	def drop(error = nil)
		@socket.close if @socket
		if error
			Logger.log("#{self} lost connection. (#{error})\n*******TRACE**********\n#{$@}")
			Logger.log($@)
		else
			Logger.log("#{self} lost connection. (no error)")
		end

		$system.server.connections.delete(self)

		if @player
			Logger.log("Saving #{@player}...")
			@player.location.contents.delete(@player)
			@player.save
		end

		Thread.stop
	end

	def write(string)
		@socket.write(string.ansify) if @socket
	end

	def puts(line)
		@socket.puts(line.ansify) if @socket
	end

	def gets(nolog = false, obfuscate = false)
		error = "no error"
		begin
			line = @socket.gets
			if line
				line.chomp!.chomp!
				Logger.log("#{self}> #{line}") if nolog == false
				if obfuscate == true
					logline = "#{self}> "
					for i in line.length
						logline << "*"
					end
					Logger.log(logline)
				end
			end
		rescue
			error = $!
		end

		if line
			return line
		else
			raise error
		end
	end

	def to_s
		return "#{@name}@#{@address[0]}:#{@address[1]}"
	end
end