WHERE IS MEMORY LEAKING :(
#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){
        return 2;
    }
    User *new_node = calloc(1, sizeof(User));
    
    strcpy(new_node->name, name);

    if(user_ptr_add[0] == NULL){
        user_ptr_add[0] = new_node;
    } else {
        User *curr = user_ptr_add[0];
        while(curr->next != NULL){
            if(strcmp((*curr).name, name) == 0){
                return 1;
            } else {
                curr = curr->next;
            }
        }
        if(strcmp((*curr).name, name) == 0){
            return 1;
        } else {
            curr->next = new_node;
        }
    }
    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 *user_head = (User *) head;
    if(user_head == NULL){
        return NULL;
    } else {
        User *curr = user_head;
        while(curr->next != NULL){
            if(strcmp((*curr).name, name) == 0){
                return curr;
            } else {
                curr = curr->next;
            }
        }
        if(strcmp((*curr).name, name) == 0){
            return curr;
        }
    }
    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) {
    User *user_curr = (User *) curr;
    printf("%s\n", "User List");
    if(user_curr == NULL){
        ;
    } else {
        User curr_user = user_curr[0];
        while(curr_user.next != NULL){
            printf("\t%s\n", curr_user.name);
            curr_user = *(curr_user.next);
        }
        printf("\t%s\n", curr_user.name);
    }
}


/*
 * 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) {
    if(strlen(filename) >= MAX_NAME){
        return 2;
    } else if((fopen(filename, "r")) == NULL){
        return 1;
    } else {
        strcpy(user->profile_pic, filename);
        return 0;
    }
}


/*
 * 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 *user1 = find_user(name1, head);
    User *user2 = find_user(name2, head);
    if((find_user(name1, head) == NULL) || (find_user(name2, head) == NULL)){
        return 4;
    } else if(strcmp(name1, name2) == 0){
        return 3;
    } else {
        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user1->friends)[i] == user2){
                return 1;
            }
        }

        int not_max = 0;

        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user1->friends)[i] == NULL){
                not_max = 1;
            }
        }

        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user2->friends)[i] == NULL){
                not_max = 1;
            }
        }

        if(not_max==0){
            return 2;
        }

        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user1->friends)[i] == NULL){
                (user1->friends)[i] = user2;
                break;
            }
        }

        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user2->friends)[i] == NULL){
                (user2->friends)[i] = user1;
                break;
            }
        }

        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) {
    if(user == NULL){
        return 1;
    } else {
        if(user->profile_pic != NULL){
            FILE *pic_file;
            char line[100];
            pic_file = fopen(user->profile_pic, "r");
            if (pic_file != NULL){
                while (fgets(line, 100, pic_file) != NULL) {
                    printf("%s", line);
                }
                fclose(pic_file);
                printf("\n");
            }

        }

        printf("%s%s\n", "Name: ", user->name);
        printf("%s\n", "------------------------------------------");
        printf("%s\n", "Friends:");
        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user->friends)[i] != NULL){
                printf("%s\n", ((user->friends)[i])->name);
            }
        }
        printf("%s\n", "------------------------------------------");
        printf("%s\n", "Posts:");
        if(user->first_post == NULL){
            ;
        } else {
            Post *curr_post = (user->first_post);
            while(curr_post->next != NULL){
                printf("%s%s\n", "From: ", curr_post->author);
                printf("%s%s\n", "Date: ", ctime(curr_post->date));
                printf("%s\n", curr_post->contents);
                printf("\n%s\n\n", "===");
                curr_post = curr_post->next;
            }
            printf("%s%s\n", "From: ", curr_post->author);
            printf("%s%s\n", "Date: ", ctime(curr_post->date));
            printf("%s\n", curr_post->contents);

        }
        printf("%s\n", "------------------------------------------");
        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;
    } else {
        int friends = 0;
        for(int i = 0; i < MAX_FRIENDS; i++){
            if((author->friends)[i] == target){
                friends = 1;
            }
        }
        if(friends == 0){
            return 1;
        }

        Post *new_post = calloc(1, sizeof(Post));
        strcpy(new_post->author, author->name);
        new_post->contents = contents;
        time_t *post_time = malloc(sizeof(time_t));
        *post_time = time(NULL);
        new_post->date = post_time;

        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[0]) == NULL){
        return 1;
    } else {
        User *user_to_delete = find_user(name, user_ptr_del[0]);

        //remove as friend
        for(int i = 0; i < MAX_FRIENDS; i++){
            if((user_to_delete->friends)[i] != NULL){
                User *friend_user = find_user((user_to_delete->friends)[i]->name, user_ptr_del[0]);
                for(int i = 0; i < MAX_FRIENDS; i++){
                    if(((friend_user->friends)[i] != NULL) && (friend_user->friends)[i] == user_to_delete){
                        friend_user->friends[i] = NULL;
                    }
                }
            }
        }

        //delete the user from the linked list
        User *curr = user_ptr_del[0];
        while((curr->next != NULL) && (curr->next) != user_to_delete){
            curr = curr->next;
        }

        curr->next = user_to_delete->next;

        //free all memory related to the user
        free(user_to_delete->name);
        free(user_to_delete->profile_pic);
        
        Post *curr_post = user_to_delete->first_post;
        while(curr_post != NULL){
            free(author);
            free(curr_post->contents);
            free(curr_post->date);
            free(curr_post);
            curr_post = curr_post->next;
        }
        
        for(int i = 0; i < MAX_FRIENDS; i++){
            free((user_to_delete->friends[i])[i]);
        }
        free(user_to_delete);
        return 0;
    }
}