func (c *appContext) friendUserHandler(w http.ResponseWriter, r *http.Request) {
	params := context.Get(r, "params").(httprouter.Params)

	userToFriendId := params.ByName("id")
	userId := r.Header.Get("x-key")

	if userToFriendId == userId {
		WriteError(w, ErrCannotFriendSelf)
		return
	}

	if c.alreadyFriendsCheck(userId, userToFriendId) == true {
		WriteError(w, ErrAlreadyFriends)
		return
	}

	err := c.addFriend(userId, userToFriendId)
	if err != nil {
		WriteError(w, ErrInternalServer)
		log.Println("Error friending user: ", err)
		return
	}

	Respond(w, r, 204, nil)

	c.SendNewFriendPush(userToFriendId, userId)
}
func (c *appContext) postContactsHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	body := context.Get(r, "body").(*RecieveContacts)
	contacts := body.Data

	response, err := c.processContacts(contacts, userId)
	if err != nil {
		log.Println("Error setting device token: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 201, response)
}
func (c *appContext) postPhoneNumberHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	body := context.Get(r, "body").(*RecievePhoneNumberResource)
	phoneNumber := body.Data

	err := c.addPhoneNumber(phoneNumber.PhoneNumber, userId)
	if err != nil {
		log.Println("Error setting phone number: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)
}
func (c *appContext) postDeviceTokenHandler(w http.ResponseWriter, r *http.Request) {
	params := context.Get(r, "params").(httprouter.Params)
	userId := r.Header.Get("x-key")
	deviceToken := params.ByName("token")

	err := c.addDeviceToken(deviceToken, userId)
	if err != nil {
		log.Println("Error setting device token: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)
}
func (c *appContext) postFeedbackHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	body := context.Get(r, "body").(*RecieveFeedbackResource)
	feedback := body.Data

	err := c.addFeedback(feedback.Feedback, userId)
	if err != nil {
		log.Println("Error adding feedback: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)
}
// Returns all users that match search
func (c *appContext) searchUsersHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	params := context.Get(r, "params").(httprouter.Params)
	searchTerm := params.ByName("term")

	detailedResponseUsers, err := c.searchUsers(searchTerm, userId)
	if err != nil {
		log.Println("Error searching on users: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 201, detailedResponseUsers)
}
// Creates a user.
func (c *appContext) createUserHandler(w http.ResponseWriter, r *http.Request) {
	body := context.Get(r, "body").(*RecieveUserResource)
	user := body.Data

	// Check if this username is already taken.
	_, err := c.getUserWithUsername(user.Username)
	if err != sql.ErrNoRows {
		log.Println("Signup failed ", err)
		WriteError(w, ErrUserExists)
		return
	}

	if len(user.Password) < 4 {
		log.Println("Signup failed password too short")
		WriteError(w, ErrShortPassword)
		return
	}

	// Letters and numbers only. 3-16 characters.
	match, _ := regexp.MatchString("^[a-z0-9]{3,16}$", user.Username)
	if match != true {
		log.Println("Signup failed invalid username.")
		WriteError(w, ErrInvalidUsername)
		return
	}

	// Create the user
	err = c.createUser(user.Username, user.Password)
	if err != nil {
		log.Println("Error creating user: "******"User created but there was an error on return: ", err)
	}

	newUserId := fmt.Sprintf("%d", newUser.Id)
	c.addDefaultMessages(newUserId)

	Respond(w, r, 201, *newUser)

	// Increment Register Count
	UserCount.Inc()
}
func (c *appContext) readMessageHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	params := context.Get(r, "params").(httprouter.Params)
	messageId := params.ByName("id")

	err := c.markMessageAsRead(userId, messageId)
	if err != nil {
		log.Println("Error: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)

	// Increment message read stat
	MessageReadCount.Inc()
}
func (c *appContext) unfriendUserHandler(w http.ResponseWriter, r *http.Request) {
	params := context.Get(r, "params").(httprouter.Params)

	userIdToUnfriend := params.ByName("id")
	userId := r.Header.Get("x-key")

	if c.alreadyFriendsCheck(userId, userIdToUnfriend) == false {
		WriteError(w, ErrNotFriends)
		return
	}

	err := c.deleteFriend(userId, userIdToUnfriend)
	if err != nil {
		log.Println("Error removing friend ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)
}
func (c *appContext) postMessageHandler(w http.ResponseWriter, r *http.Request) {
	userId := r.Header.Get("x-key")
	body := context.Get(r, "body").(*RecieveMessageResource)
	message := body.Data

	newMessageId, err := c.addMessage(userId, message.Message.Message, message.Type)
	if err != nil {
		log.Println("Error adding message: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	toUsersIds, err := c.getToUsersForMessageType(message.Type, userId, message)
	if err != nil {
		log.Println("Error: ", err)
		WriteError(w, ErrInternalServer)
		return
	}

	err = c.addMessageToUsers(toUsersIds, newMessageId)
	if err != nil {
		log.Println("Error adding toUsers", err)
		WriteError(w, ErrInternalServer)
		return
	}

	Respond(w, r, 204, nil)

	// Send pushes increment message stats.
	if message.Type == "direct" {
		c.SendNewDirectMessagePush(toUsersIds)
		DirectMessageCount.Inc()
	}
	if message.Type == "public" {
		c.SendNewPublicMessagePush(toUsersIds)
		PublicMessageCount.Inc()
	}

	MessageSentCount.Inc()
}
func (c *appContext) loginUserHandler(w http.ResponseWriter, r *http.Request) {
	body := context.Get(r, "body").(*RecieveUserResource)
	user := body.Data

	// Check if this username exists
	savedUser, err := c.getUserWithUsername(user.Username)
	if err == sql.ErrNoRows {
		// User doesn't exist.
		log.Println("Invalid login attempt.")
		WriteError(w, ErrInvalidLogin)
		return
	}
	if err != nil {
		log.Println("Error finding user: "******"Error on login: "******"Failed to retrieve phone user: ", err)
		WriteError(w, ErrInvalidLogin)
		return
	}

	Respond(w, r, 201, *userToReturn)
}