#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) {
 User *curr = *user_ptr_add; // pointer to head of user list
    if(strlen(name) >= MAX_NAME){
        return 2;
    }
    if(*user_ptr_add == NULL){ // if user list is empty
        User *newbie = (User *) malloc(sizeof(User));
        if(newbie == NULL){
            exit(1);
        }
        strcpy(newbie->name, name); //copy name
        *user_ptr_add = newbie; // add user with name to head of list
        return 0;
    }

    while(curr->next != NULL){ //traverse through link list
        if(strcmp(curr->name, name) == 0){ //check for case 1 at each node
            return 1;
        }
        curr = curr->next; //traversal step
    }
    if(strcmp(name, curr->name)==0){
        return 1;
    }
    User *user = (User *) malloc(sizeof(User));
    if(user == NULL){
        exit(1);
    }
    strcpy(user->name, name); //copy name into user
    for(int i = 0; i<10; i++){
        user->friends[i] = NULL;
        }
    strcpy(user->profile_pic, ""); //set profile pic to empty string
    user->first_post = NULL; //set first post to NULL
    user->next = NULL; //set next to NULL
    curr->next = user; //add user to tail of list
    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; //current user in head after first if statement
    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) {
    User *user = (User *) curr; // pointer to head of user list
    printf("User List\n");
    while(user != NULL){
        printf("\t%s\n", user->name);
        user = user->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 *f = fopen(filename, "r"); // Open the file for reading.
    
    // Check for if the filename is too long.
    if(strlen(filename) >= MAX_NAME){
        fclose(f);
        return 2;
    }
    // Check for if the file could not be opened.
    else if(f == NULL){
        fclose(f);
        return 1;
    }
    else{
        strcpy(user->profile_pic, filename); // Copy the filename to the user's profile picture field.
        fclose(f);
        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 fri  ends, 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) {
    // Find user a(name1) and b(name2) using find_user
    User *a = find_user(name1, head);
    User *b = find_user(name2, head);

    // Initialize counters for user a and b
    int num_a = 0; //number of friends of user a
    int num_b = 0; //number of friends of user b

    // Check if either user does not exist
    if(a == NULL || b == NULL){
        return 4;
    }

    // Check if the two users are the same
    if(a == b){
        return 3;
    }

    // Find an empty spot in user a's friend list
    while(num_a < 10 && a->friends[num_a] != NULL){
        if(a->friends[num_a] == b){
            return 1;
        }
        num_a += 1;
    }

    // Find an empty spot in user b's friend list
    while(num_b < 10 && b->friends[num_b] != NULL){
        if(b->friends[num_b] == a){
            return 1;
        }
        num_b += 1;
    }

    // Check if either user has reached the friend limit (10)
    if(num_a > 9 || num_b > 9){
        return 2;
    }

    // Add user b to user a's friend list
    a->friends[num_a] = b;

    // Add user a to user b's friend list
    b->friends[num_b] = a;

    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) {
    // check if user is NULL
    if(user == NULL){
        return 1;
    }

    // declare a file pointer, a char and a Post pointer
    FILE *f;
    char c;
    Post *currpost = user->first_post;

    // set the file pointer to the opened profile picture file for reading
    f = fopen(user->profile_pic, "r");

    // if the file exists, print its contents
    if(f!=NULL){
        while ((c = fgetc(f)) != EOF) {
            printf("%c", c);
        }
        fclose(f);
    }
    // print the user's name
    printf("\n");
    printf("%s %s\n", "Name:", user->name);
    printf("------------------------------------------\n");

    // print the user's friends
    printf("Friends:\n");
    for(int i = 0; i < 10; i++){
        if(user->friends[i] != NULL){
            printf("%s\n", user->friends[i]->name);
        }
    }
    printf("------------------------------------------\n");

    // print the user's posts
    printf("Posts:\n");
    if(currpost != NULL){
        printf("From: %s\n", currpost->author);
        printf("Date: %s\n", ctime(currpost->date));
        printf("%s\n", currpost->contents);

        // iterate over all other elements of the linked list and print each post
        while(currpost->next != NULL){
            printf("\n");
            printf("===\n");
            printf("\n");
            printf("From: %s\n", currpost->next->author);
            printf("Date: %s\n", ctime(currpost->next->date));
            printf("%s\n", currpost->next->contents);
            currpost = currpost->next;
        }
    }

    // print the separator line and return 0 to indicate success
    printf("------------------------------------------\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) {
    Post *target_first_post = target->first_post; // the first post of the target user
    time_t *t = malloc(sizeof(time_t)); // allocate memory for time
    if(t == NULL){ //checking for malloc error
        exit(1);
    } 
    time(t); // get the current time and store it in the time t
    Post *newpost = (Post *) malloc(sizeof(Post)); // allocate memory for the new post
    if(newpost == NULL){
        exit(1);
    }
    if(author == NULL || target == NULL){ 
        return 2;
    }
    for(int i = 0; i < 10; i++){ // check if target is a friend of author
        if(author->friends[i] == target){ 
            strcpy(newpost->author, author->name); //copy author name into new post 
            newpost->date = t; // set the date of the new post to the current time
            newpost->contents = contents; // set the contents of the new post to the given contents
            newpost->next = target_first_post; // adds the old first post to newpost's next to keep order consistent
            target->first_post = newpost; // update the first post of the target user to the new post
            return 0; 
        }
    }
    return 1;
}

/*
 * 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) {
    User *leaver = find_user(name, *user_ptr_del); //The user we want to delete  
    User *curr = *user_ptr_del; //for traversal   
    if(leaver == NULL || curr == NULL){ //check if leaver exists and if the userlist has anything in it  
        return 1;  
    }  
    if(curr == leaver){ //checks head case if leaver is there  
        *user_ptr_del = curr->next;  
    }  
    while(curr->next != NULL){
        if(curr->next == leaver){
            curr->next = curr->next->next;
        }
        curr = curr->next;
    }  
    for(int i = 0; i< 10; i++){
        if(leaver->friends[i] == NULL){
            continue;
        }
        int k = 0;
        for(int j = 0; j<10; j++){
            if(leaver->friends[i]->friends[j] != leaver){
                leaver->friends[i]->friends[k] = leaver->friends[i]->friends[j];
                k++;
            }
        }
        while(k<9){
            leaver->friends[i]->friends[k+1] = NULL;
            k+=1;
        }
    }
    free(leaver->name);
    for(int i = 0; i<10; i++){
        leaver->friends[i] = NULL;
    }
    while(leaver->first_post != NULL){  
        Post *temp = leaver->first_post->next;  //temp post
        free(leaver->first_post->contents);  
        free(leaver->first_post->date);  
        free(leaver->first_post);  
        leaver->first_post = temp;  
    }  
    free(leaver);  
      
    return 0;
}
fix memory leak