func main() {
	http.HandleFunc("/", http.NotFound)
	http.HandleFunc("/ws", newConnection)
	logger.Info("Starting Tiberious on", config.Port)
	if err := http.ListenAndServe(config.Port, nil); err != nil {
		logger.Error(err)
	}
}
// TODO move this into a separate handler of some form.
func newConnection(w http.ResponseWriter, r *http.Request) {
	var upgrader = websocket.Upgrader{
		ReadBufferSize:  config.ReadBufferSize,
		WriteBufferSize: config.WriteBufferSize,
	}

	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		logger.Error(err)
		return
	}

	go handlers.ClientHandler(conn)
}
/* This seems extremely cumbersome but it's the best way I can think to handle
 * this without deleting the entire set and recreating it. */
func (r *rClient) updateSet(key string, new []string) {
	old, err := r.Client.SMembers(key).Result()
	if err != nil {
		logger.Error(err)
	}

	for _, o := range old {
		var rem = true
		for _, n := range new {
			if o == n {
				rem = false
			}
		}

		if rem {
			if err := r.Client.SRem(key, o).Err(); err != nil {
				logger.Error(err)
			}
		}
	}

	for _, n := range new {
		var add = true
		for _, o := range old {
			if n == o {
				add = false
			}
		}

		if add {
			if err := r.Client.SAdd(key, n).Err(); err != nil {
				logger.Error(err)
			}
		}
	}
}
// ClientHandler handles all client interactions
func ClientHandler(conn *websocket.Conn) {
	var err error

	client := types.NewClient()
	client.Conn = conn
	client.User = new(types.User)
	// Set the UUID and initialize a username of "guest"
	client.User.ID, err = getUniqueID()
	if err != nil {
		logger.Error(err)
	}

	guests, err := dbClient.GetKeySet("user-guest-*-*")
	if err != nil {
		logger.Error(err)
	}

	// TODO give guests a numeric suffix, allow disabling guest connections.
	client.User.Username = "******" + strconv.Itoa(len(guests)+1)
	client.User.LoginName = client.User.Username
	client.User.Type = "guest"
	client.User.Connected = true

	clients[client.User.ID.String()] = client

	if config.AllowGuests {
		defgroup, err := GetGroup("#default")
		if err != nil {
			logger.Error(err)
		}
		defgroup.Users[client.User.ID.String()] = client.User
		client.User.Groups = append(client.User.Groups, "#default")
		room, err := GetRoom("#default", "#general")
		if err != nil {
			logger.Error(err)
		}
		client.User.Rooms = append(client.User.Rooms, "#default/#general")
		room.Users[client.User.ID.String()] = client.User

		dbClient.WriteUserData(client.User)
		dbClient.WriteGroupData(defgroup)
		dbClient.WriteRoomData(room)

		logger.Info("guest", client.User.ID.String(), "connected")
	} else {
		logger.Info("new client connected")
	}

	if err := client.Alert(types.OK, ""); err != nil {
		logger.Error(err)
	}

	/* TODO we may want to remove this later it's just for easy testing.
	 * to allow a client to get their UUID back from the server after
	 * connecting. */
	if config.AllowGuests {
		if err := client.Alert(types.GeneralNotice, string("Connected as guest with ID "+client.User.ID.String())); err != nil {
			logger.Error(err)
		}
	} else {
		if err := client.Alert(types.ImportantNotice, "No Guests Allowed : send authentication token to continue"); err != nil {
			logger.Error(err)
		}
	}

	/* Never return from this loop!
	 * Never break from this loop unless intending to disconnect the client. */
	for {
		_, rawmsg, err := client.Conn.ReadMessage()
		if err != nil {
			switch {
			case websocket.IsCloseError(err, websocket.CloseNormalClosure):
				if client.User != nil {
					logger.Info(client.User.Type, client.User.ID.String(), "disconnected")
				} else {
					logger.Info("client disconnected")
				}
				break
			// TODO handle these different cases appropriately.
			case websocket.IsCloseError(err, websocket.CloseGoingAway):
			case websocket.IsCloseError(err, websocket.CloseProtocolError, websocket.CloseUnsupportedData):
				// This should utilize the ban-score to combat possible spammers
			case websocket.IsCloseError(err, websocket.ClosePolicyViolation, websocket.CloseMessageTooBig):
				// These should also utilize the ban-score but with a higher ban
			default:
				logger.Info(err)
			}
			break
		}

		ban, err := ParseMessage(client, rawmsg)
		if err != nil {
			logger.Info(err)
		}
		if ban > 0 {
			// TODO handle ban-score
			break
		}
	}

	// We broke out of the loop so disconnect the client.
	client.Conn.Close()
	if client.User != nil {
		if client.User.Type == "guest" {
			if err := dbClient.DeleteUser(client.User); err != nil {
				logger.Error(err)
			}
		} else {
			client.User.Connected = false
			dbClient.WriteUserData(client.User)
		}
	}

	delete(clients, client.User.ID.String())
}