#include "friends.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

/*
 * Create a new user with the given name.  Insert it at the tail of the list
 * of users whose head is pointed to by *user_ptr_add.
 *
 * Return:
 *   - 0 if successful
 *   - 1 if a user by this name already exists in this list
 *   - 2 if the given name cannot fit in the 'name' array
 *       (don't forget about the null terminator)
 */
int create_user(const char *name, User **user_ptr_add) {
	if (strlen(name) > (MAX_NAME - 1)){
		return 2;
	}

	else if (*user_ptr_add == NULL){
		*user_ptr_add = malloc(sizeof(User));
		if (*user_ptr_add == NULL){return 3;} //non-zero return val for malloc fail
		strncpy((*user_ptr_add)->name, name, (MAX_NAME - 1));
		(*user_ptr_add)->name[(MAX_NAME - 1)] = '\0';
		(*user_ptr_add)->next = NULL;
		(*user_ptr_add)->profile_pic[0] = '\0';
		return 0;
	}

	else{
		User *p = malloc(sizeof(User));
		if (p == NULL){return 3;} //non-zero return val for malloc fail
		strncpy(p->name, name, (MAX_NAME - 1));
		p->name[(MAX_NAME - 1)] = '\0';
		p->next = NULL;
		(*user_ptr_add)->profile_pic[0] = '\0';
		User *curr = *user_ptr_add;
		while (curr->next != NULL){
			if (strcmp(curr->name, name) == 0){
				return 1;
			}
			curr = curr->next;
		}
		curr->next = p;
		return 0;
	}
}


/*
 * Return a pointer to the user with this name in
 * the list starting with head. Return NULL if no such user exists.
 *
 * NOTE: You'll likely need to cast a (const User *) to a (User *)
 * to satisfy the prototype without warnings.
 */
User *find_user(const char *name, const User *head) {
    User *curr = (User *) head;
    while (curr != NULL){
        if (strcmp(curr->name, name) == 0){
            return &(*curr);
        }
        curr = curr->next;
    }
    return NULL;
}


/*
 * Print the usernames of all users in the list starting at curr.
 * Names should be printed to standard output, one per line.
 */
void list_users(const User *curr) {
	printf("User List\n");
	if (curr != NULL){
		User *cur = (User *) curr;
		while (cur != NULL){
			printf("\t%s\n", cur->name);
			cur = cur->next;
		}
	}
}


/*
 * Change the filename for the profile pic of the given user.
 *
 * Return:
 *   - 0 on success.
 *   - 1 if the file does not exist or cannot be opened.
 *   - 2 if the filename is too long.
 */
int update_pic(User *user, const char *filename) {
	FILE *error = fopen(filename, "r");
	if (error == NULL){return 1;}
	else if (strlen(filename) > (MAX_NAME - 1)){fclose(error); return 2;}
	else{
		strncpy(user->profile_pic, filename, (MAX_NAME - 1));
		user->profile_pic[(MAX_NAME - 1)] = '\0';
		fclose(error);
		return 0;
	}
	fclose(error);
}

/*
 * Returns the number of friends a user has
 * Used as a helper for make_friends
*/
int num_friends_helper(User *user) {
	int friend_count = 0;
	while ((user->friends)[friend_count] != NULL){friend_count++;}
	return friend_count;
}

/*
 * Make two users friends with each other.  This is symmetric - a pointer to
 * each user must be stored in the 'friends' array of the other.
 *
 * New friends must be added in the first empty spot in the 'friends' array.
 *
 * Return:
 *   - 0 on success.
 *   - 1 if the two users are already friends.
 *   - 2 if the users are not already friends, but at least one already has
 *     MAX_FRIENDS friends.
 *   - 3 if the same user is passed in twice.
 *   - 4 if at least one user does not exist.
 *
 * Do not modify either user if the result is a failure.
 * NOTE: If multiple errors apply, return the *largest* error code that applies.
 */

int make_friends(const char *name1, const char *name2, User *head) {
	User *first = find_user(name1, head);
	User *second = find_user(name2, head);
	if ((first == NULL) || (second == NULL)){return 4;}
	else if (strcmp(name1, name2) == 0){return 3;}
	//int i=0, j=0;
	int val = 0;
	int first_count = num_friends_helper(first);
	int second_count = num_friends_helper(second);
	if ((first_count == MAX_FRIENDS) || (second_count == MAX_FRIENDS)){return 2;}
	/*
	while ((first->friends)[i] != NULL){
		if (strcmp(((first->friends)[i])->name, name2) == 0){val++;}
		i++;
	}
	while ((second->friends)[j] != NULL){
		if (strcmp(((second->friends)[j])->name, name1) == 0){val++;}
		j++;
	}
	*/
	if (val == 2){return 1;}
	//else if (((i+1) > (MAX_FRIENDS)) || ((j+1) > (MAX_FRIENDS))){return 2;}
	else {
		(first->friends)[first_count] = second;
		(second->friends)[second_count] = first;
		return 0;
	}
}


/*
 * Print a user profile.
 * For an example of the required output format, see the example output
 * linked from the handout.
 * Return:
 *   - 0 on success.
 *   - 1 if the user is NULL.
 */
int print_user(const User *user) {
    char *dashes = {"------------------------------------------"};
	if (user == NULL){return -1;}
	else{
		FILE *profile = fopen(user->profile_pic, "r");
		if (profile == NULL){
			printf("Name: %s\n%s\nFriends:\n", user->name, dashes);
			int i  = 0;
			while ((user->friends)[i] != NULL){printf("%s\n", (user->friends)[i]->name); i++;}
			printf("%s\nPosts:\n", dashes);
			Post *curr = user->first_post;
			while (curr != NULL){
				printf("From: %s\nDate: %s\n%s\n", curr->author, ctime(curr->date), curr->contents);
				curr = curr->next;
				if (curr == NULL){}
				else{
					printf("\n===\n\n");
				}
			}
			printf("%s\n", dashes);
			return 0;
		}
		else {
			char line[1000];
			while (fgets(line, 1000, profile) != NULL){
				printf("%s", line);
			}
			printf("\n");
			printf("Name: %s\n%s\nFriends:\n", user->name, dashes);
			int i  = 0;
			while ((user->friends)[i] != NULL){printf("%s\n", (user->friends[i])->name); i++;}
			printf("%s\nPosts:\n", dashes);
			Post *curr = user->first_post;
			while (curr != NULL){ 
				printf("From: %s\nDate: %s\n%s\n", curr->author, ctime(curr->date), curr->contents);
				curr = curr->next;
				if (curr == NULL){}
				else{
					printf("\n===\n\n");
				}
			}
			if (profile != NULL){fclose(profile);}
			printf("%s\n", dashes);
			return 0;
		}
	}
}


/*
 * Make a new post from 'author' to the 'target' user,
 * containing the given contents, IF the users are friends.
 *
 * Insert the new post at the *front* of the user's list of posts.
 *
 * 'contents' is a pointer to heap-allocated memory - you do not need
 * to allocate more memory to store the contents of the post.
 *
 * Return:
 *   - 0 on success
 *   - 1 if users exist but are not friends
 *   - 2 if either User pointer is NULL
 */
int make_post(const User *author, User *target, char *contents) {
    
	if (author == NULL || target == NULL){return 2;}
	
	int i=0, j=0;
	int val = 0;
	while ((author->friends)[i] != NULL){
		if (strcmp(((author->friends)[i])->name, target->name) == 0){val = 1;}
		i++;
	}
	while ((target->friends)[j] != NULL){
		if (strcmp(((target->friends)[j])->name, author->name) == 0){val = 1;}
		j++;
	}
	if (val == 0){return 1;}

	else {
		Post *new_post = malloc(sizeof(Post));
		time_t *seconds = malloc(sizeof(time_t));
		if (seconds == NULL || new_post == NULL){return 3;} //non-zero return val for malloc fail
		*seconds = time(NULL);
		new_post->date = seconds;
		new_post->contents = contents;
		strcpy(new_post->author, author->name);
		new_post->next = target->first_post;
		target->first_post = &(*new_post);
		return 0;
	}
	
}


/*
 * From the list pointed to by *user_ptr_del, delete the user
 * with the given name.
 * Remove the deleted user from any lists of friends.
 *
 * Return:
 *   - 0 on success.
 *   - 1 if a user with this name does not exist.
 */
int delete_user(const char *name, User **user_ptr_del) {
    if (find_user(name, *user_ptr_del) == NULL){return 1;}
	else {
		int f = 0, k = 0;
		User *user = find_user(name, *user_ptr_del);
		while ((user->friends)[f] != NULL){
			User *friend = find_user((user->friends)[f]->name, *user_ptr_del);
			int i = 0;
			while ((friend->friends)[i] != NULL){
				if (strcmp(((friend->friends)[i])->name, name) == 0){
					while ((friend->friends)[i] != NULL){
						if ((friend->friends)[i+1] == NULL){
							(friend->friends)[i] = NULL;
						}
						else {
							(friend->friends)[i] = (friend->friends)[i+1];
						}
						i++;
					}
					break;
				}
				i++;
			}
			f++;
		}
		while ((user->friends)[k] != NULL){
			(user->friends)[k] = NULL;
			k++;
		}

		User *curr = *user_ptr_del;
		User *head = *user_ptr_del;
		User *head_next = (*user_ptr_del)->next;

		while (curr != NULL){
			if (curr->next != NULL && strcmp(curr->next->name, name) == 0){
				//User *prev = curr;
				User *nex;
				
				if (curr->next->next != NULL){
					nex = curr->next->next;
				}
				else {
					nex = NULL;
				}
				curr->next = nex;
				break;
			}
			curr = curr->next;
		}
		if (strcmp(head->name, name) == 0){
					*user_ptr_del = head_next;
		}
		Post *posts = user->first_post;
		while (posts != NULL){
			free(posts->date);
			free(posts->contents);
			posts = posts->next;
		}
		free(user->first_post);
		free(user);
		return 0;
	}
}

making friends MAX_FRIEND number of times should not result in a segmentation fault