#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;}
    else{
        User *new_user = malloc(sizeof(User));
        strcpy(new_user->name, name);
        new_user->profile_pic[0] = '\0';
        for(int i = 0;i<MAX_FRIENDS;i++){
            new_user->friends[i] = NULL;
        }
        new_user->first_post = NULL;
        new_user->next = NULL;

        
        User *prev = NULL;
        User *user = *user_ptr_add;
        
        while(user != NULL){
            if(strcmp(name, user->name) == 0){return 1;}
            prev = user;
            user = user-> next;
        }

        if(prev == NULL){*user_ptr_add = new_user;}
        else{prev->next = new_user;}
        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 = (User *) head; 
    while(user != NULL){        
        if(strcmp(name, user->name) == 0){return user;}
        user = user-> 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;
    fprintf(stdout, "User List\n");
    while(user != NULL){        
        fprintf(stdout, "  %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) {
    if(strlen(filename) >= MAX_NAME){return 2;}
    FILE * f = fopen(filename, "r");
    if(f == NULL){return 1;}
    fclose(f);
    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 *usr1 = find_user(name1, head);
    User *usr2 = find_user(name2, head);
    if(strcmp(name1, name2)==0){return 3;}
    if(usr1 == NULL || usr2 == NULL){return 4;}

    int i = 0;
    while((usr1->friends)[i] != NULL && i != MAX_FRIENDS){
        if(strcmp((usr1->friends)[i]->name, name2) == 0){
            return 1;
        }
        i ++;
    }

    int j = 0;
    while((usr2->friends)[j] != NULL && j != MAX_FRIENDS){
        if(strcmp((usr2->friends)[j]->name, name1) ==0){
            return 1;
        }
        j ++;
    }

    if(i==MAX_FRIENDS || j==MAX_FRIENDS){return 2;}
    (usr1->friends)[i] = usr2;
    (usr2->friends)[j] = usr1;
    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[0] == '\0'){
            FILE * f = fopen(user->profile_pic, "r");
            if(f!=NULL){
                char line[101]; 
                while(fgets(line, 101, f)!= NULL){
                    fprintf(stdout, "%s", line);
                }
                fprintf(stdout, "\n");
                fclose(f);
            }
        }

        fprintf(stdout, "Name: %s\n", user->name);
        fprintf(stdout, "------------------------------------------\n");

        fprintf(stdout, "Friends:\n");
        int i = 0;
        while((user->friends)[i] != NULL && i != MAX_FRIENDS){
            fprintf(stdout, "%s\n", (user->friends)[i]->name);
            i++;
        }
        fprintf(stdout, "------------------------------------------\n");

        fprintf(stdout, "Posts:\n");
        Post *post;
        post = user->first_post;
        while(post != NULL){
            fprintf(stdout, "From: %s\n", post->author);
            fprintf(stdout, "Date: %s", ctime(post->date));
            fprintf(stdout,"\n");
            fprintf(stdout,"%s\n", post->contents);

            if(post->next != NULL){
                fprintf(stdout,"\n");
                fprintf(stdout,"===\n");
                fprintf(stdout,"\n");
            }
            post = post->next;
        }
        fprintf(stdout, "------------------------------------------\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;
        free(contents);
        }

    int i =0;
    while((author->friends)[i] != NULL && i != MAX_FRIENDS){
        if((author->friends)[i] == target){
            Post *p = malloc(sizeof(Post));
            strcpy(p->author, author->name);
            p->contents = contents;
            p->date = malloc(sizeof(time_t));
            time(p->date); 
            p->next = target->first_post;

            target->first_post = p;
            return 0;
        }
        i++;
    }
    free(contents);
    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 *prev = NULL;
    User *user = *user_ptr_del; 
    if(user == NULL){return 0;}
    while(user != NULL){
        if(strcmp(name, user->name) == 0){
            int i = 0;
            User *friend = user->friends[0];
            while(friend != NULL && i < MAX_FRIENDS){
                int j = 0;
                int indx = 0;
                while(friend->friends[j]!= NULL && j < MAX_FRIENDS){
                    if(strcmp(friend->friends[j]->name, user->name)==0){
                        indx = j;
                    }
                    j++;
                }
                if(j!=0){
                    friend->friends[indx] = friend->friends[j-1];
                    if(friend->friends[j-1]!= NULL){
                        friend->friends[j-1] = NULL;
                    }
                }
                i++;
                friend = user->friends[i];
            }

            Post* p = user->first_post;
            Post* del = NULL;
            while(p != NULL){
                free(p->contents);
                free(p->date);
                del = p;
                p = p->next;
                free(del);
            }
            user->first_post = NULL;

            if(prev == NULL){
                *user_ptr_del = user->next;
                fprintf(stdout, "DELETE HEAD%s\n", user->name);
            }
            else{
                prev->next = user->next;
                fprintf(stdout, "DELETE some%s\n", user->name);
            }
            free(user);
            return 0;
        }
        prev = user;
        user = user -> next;
    }
    return 1;
}
