#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define BUFFER_SZ 50

// Prototypes
void usage(char *);
void print_buff(char *, int);
int setup_buff(char *, char *, int);
int count_words(char *, int, int);
void reverse_string(char *, int);
void word_print(char *, int, int);

int setup_buff(char *buff, char *user_str, int len) {   //TODO: #4:  Implemented the setup buff as per the directions
    char *b_ptr = buff;
    char *u_ptr = user_str;
    int user_len = 0;
    bool last_was_space = false;

    while (*u_ptr != '\0') {
        if (user_len >= len) {
            return -1; // Error: Input string exceeds buffer size
        }

        if (*u_ptr == ' ' || *u_ptr == '\t') {
            if (!last_was_space) {
                *b_ptr = ' ';
                b_ptr++;
                user_len++;
                last_was_space = true;
            }
        } else {
            *b_ptr = *u_ptr;
            b_ptr++;
            user_len++;
            last_was_space = false;
        }
        u_ptr++;
    }

    while (user_len < len) {
        *b_ptr = '.';
        b_ptr++;
        user_len++;
    }

    return user_len;
}

int count_words(char *buff, int len, int str_len) {
    if (str_len > len) {
        return -1; // Error: String length exceeds buffer size
    }

    int word_count = 0;
    bool at_start = true;

    for (int i = 0; i < str_len; i++) {
        char c = *(buff + i);

        if (at_start && c != ' ') {
            word_count++;
            at_start = false;
        } else if (c == ' ') {
            at_start = true;
        }
    }

    return word_count;
}

void reverse_string(char *buff, int str_len) {
    for (int i = 0, j = str_len - 1; i < j; i++, j--) {
        char temp = *(buff + i);
        *(buff + i) = *(buff + j);
        *(buff + j) = temp;
    }
}

void word_print(char *buff, int len, int str_len) {
    printf("Word Print\n----------\n");
    int word_start = 0;

    for (int i = 0; i <= str_len; i++) {
        if (i == str_len || *(buff + i) == ' ') {
            printf("%.*s (%d)\n", i - word_start, buff + word_start, i - word_start);
            word_start = i + 1;
        }
    }
}

void print_buff(char *buff, int len) {
    printf("Buffer: ");
    for (int i = 0; i < len; i++) {
        putchar(*(buff + i));
    }
    putchar('\n');
}

void usage(char *exename) {
    printf("usage: %s [-h|c|r|w|x] \"string\" [other args]\n", exename);
}

int main(int argc, char *argv[]) {
    char *buff;
    char *input_string;
    char opt;
    int rc;
    int user_str_len;

    // TODO: #1 Explain why this is safe
    // This ensures that argv[1] exists and starts with '-'. If not, the program exits.
    if ((argc < 2) || (*argv[1] != '-')) {
        usage(argv[0]);
        exit(1);
    }

    opt = (char) *(argv[1] + 1); // Get the option flag

    if (opt == 'h') {
        usage(argv[0]);
        exit(0);
    }

    // TODO: #2 Explain the purpose of this check
    // This ensures the user provided a string as the second argument (argv[2]).
    if (argc < 3) {
        usage(argv[0]);
        exit(1);
    }

    input_string = argv[2]; // Capture user input string

    // TODO: #3 Allocate buffer and handle memory allocation failure
    buff = (char *) malloc(BUFFER_SZ);
    if (buff == NULL) {
        printf("Error: Memory allocation failed.\n");
        exit(99);
    }

    user_str_len = setup_buff(buff, input_string, BUFFER_SZ);
    if (user_str_len < 0) {
        printf("Error setting up buffer, error = %d\n", user_str_len);
        free(buff);
        exit(2);
    }

    switch (opt) {
        case 'c': // Word count
            rc = count_words(buff, BUFFER_SZ, user_str_len);
            if (rc < 0) {
                printf("Error counting words, rc = %d\n", rc);
                free(buff);
                exit(2);
            }
            printf("Word Count: %d\n", rc);
            break;
                    //TODO:  #5 Implemented the other cases for 'r' and 'w' by extending
                    //the case statement options
        case 'r': // Reverse string
            reverse_string(buff, user_str_len);
            printf("Reversed String: %.*s\n", user_str_len, buff);
            break;

        case 'w': // Word print
            word_print(buff, BUFFER_SZ, user_str_len);
            break;
        

        default:
            usage(argv[0]);
            free(buff);
            exit(1);
    }

    // TODO: #6 Free the buffer before exiting
    free(buff);
    exit(0);
}

// TODO: #7 Answer
// Providing both the pointer and length ensures safer processing, as functions
// cannot assume strings are null-terminated or rely on external constraints.
// This minimizes memory-related errors.