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


#define SPACE_CHAR ' '

//prototypes for functions to handle required functionality

// TODO: #1 What is the purpose of providing prototypes for
//          the functions in this code module


/*
Prototypes in C are critical for forward declarations, 
type checking, code modularity, and enhancing readability. 
They ensure the program compiles without errors 
when functions are used before being defined.
*/


void  usage(char *);
int   count_words(char *);
void  reverse_string(char *);
void  word_print(char *);


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

//count_words algorithm
//  1.  create a boolean to indicate if you are at the start of a word
//      initialize to false
//  2.  Loop over the length of the string
//      2a.  Get the current character aka str[i]
//      2b.  Is word_start state false?
//           -  Is the current character a SPACE_CHAR?
//              * if YES, continue loop (a.k.a) goto top with "continue;"
//              * if NO, we are at the start of a new word
//                > increment wc
//                > set word_start to true
//      2c. Else, word_start is true
//          - Is the current character a SPACE_CHAR?
//            * if YES we just ended a word, set word_start to false
//            * if NO, its just a character in the current word so
//                     there is nothing more to do
//  3.  The current word count for the input string is in the wc variable
//      so just 'return wc;' 
int count_words(char *str){
    // Suggested local variables
    int len = strlen(str);
    int wc = 0;
    bool word_start = false;

    // Please implement

    for (int i = 0; i < len; i++) {
        char current = str[i]; // Get the current character

        if (!word_start) { // If not in a word
            if (current != SPACE_CHAR) { // If the current character is not a space
                wc++; // Increment word count
                word_start = true; // Mark the start of a new word
            }
        } else { // If already in a word
            if (current == SPACE_CHAR) { // If the current character is a space
                word_start = false;  // Mark the end of the current word
            }
        }
    }


    return wc;
}

//reverse_string() algorithm
//  1.  Initialize the start and end index variables
//      a.  end_idx is the length of str - 1.  We want to remove one
//          becuase at index str[len(str)] is the '\0' that we want
//          to preserve because we are using C strings.  That makes
//          the last real character in str as str[len(str)-1]
//      b.  start_idx is 0, thus str[0] is the first character in the
//          string.
//
//  2.  Loop while end_idx > start_idx
//      2a. swap the characters in str[start_idx] and str[end_idx]
//      2b. increment start_idx by 1
//      2c. decrement end_indx by 1
//
//  3. When the loop above terminates, the string should be reversed in place
void  reverse_string(char *str){
    // Suggested local variables
    int end_idx = strlen(str) - 1;        //should be length of string - 1
    int start_idx = 0;
    char tmp_char;

    // Please implement
    while (end_idx > start_idx) {
        tmp_char = str[start_idx]; // Store the start character temporarily
        str[start_idx] = str[end_idx];  // Replace start character with end character
        str[end_idx] = tmp_char; // Replace end character with the temporary character

        start_idx++; // move the start index forward
        end_idx--; // move the end index backward
    }

   //return;
}

//word_print() - algorithm
//
// Start by copying the code from count words.  Recall that that code counts
// individual words by incrementing wc when it encounters the first character 
// in a word.
// Now, at this point where we are incrementing wc we need to do a few more things
//      1. incrment wc, and set word_start to true like before
//      2. Now, set wlen to zero, as we will be counting characters in each word
//      3. Since we are starting a new word we can printf("%d. ", wc);
//
// If word_start is true, we are in an active word, so each time through the loop
// we would want to:
//      1. Check if the current character is not a SPACE_CHARACTER
//         a.  IF it is NOT A SPACE -> print the current character, increment wlen
//
//      2.  In the loop there are 2 conditions that indicate a current word is ending:
//          a. word_start is false and the current character is a SPACE_CHARACTER
//                  OR
//          b. the current loop index is the last character in the string (aka the
//             loop index is last_char_idx) 
//
//          IF either of these conditions are true:
//              * Print the word length for current word - printf(" (%d)\n", wlen);
//              * Set word_start to false
//              * Set wlen to 0 given we are starting a new word
//
// EXAMPLE OUTPUT
// ==============
// ./stringfun -w "C programming is fun"
// Word Print
// ----------
// 1. C (1)
// 2. programming (11)
// 3. is (2)
// 4. fun (3)
void  word_print(char *str){
    //suggested local variables
    int len = strlen(str);            //length of string - aka strlen(str);
    int last_char_idx = len - 1;  //index of last char - strlen(str)-1;
    int wc = 0;         //counts words
    int wlen = 0;       //length of current word
    bool word_start = false;    //am I at the start of a new word

    // Please implement

    for (int i = 0; i < len; i++) {

        char current = str[i]; // Get the current character

        if (!word_start) {
            if (current != SPACE_CHAR) { // If not in a word
                wc++;   // Increment word count
                word_start = true;   // Mark the start of a new word
                wlen = 0;  // Reset word length for the new word
                printf("%d. ", wc);  // Print the word index

            }
        }

         if (word_start) { // If we are in a word
            if (current != SPACE_CHAR) { // If the current character is not a space
                printf("%c", current);  // Print the character
                wlen++;   // Increment the word length
            } 
            
            // Check if we reached the last character or the end of the word
            if (current == SPACE_CHAR || i == last_char_idx) {
                if (i == last_char_idx && current != SPACE_CHAR) {
                    // Handle the last word if it doesn't end with a space
                    //wlen++;
                //if (word_start){
                    printf(" (%d)\n", wlen);
                
                    
                } else if (current == SPACE_CHAR) {
                printf(" (%d)\n", wlen); // Print the word length and newline

                }
                
                word_start = false;  // Mark the end of the current word
            }
        }   


    }
    

}


int main(int argc, char *argv[]){
    char *input_string;     //holds the string provided by the user on cmd line
    char *opt_string;       //holds the option string in argv[1]
    char opt;               //used to capture user option from cmd line

    //THIS BLOCK OF CODE HANDLES PROCESSING COMMAND LINE ARGS
    if (argc < 2){
        usage(argv[0]);
        exit(1);
    }
    opt_string = argv[1];

    //note arv[2] should be -h -r -w or -c, thus the option is
    //the second character and a - is the first char
    if((opt_string[0] != '-') && (strlen(opt_string) != 2)){
        usage(argv[0]);
        exit(1);
    }

    opt = opt_string[1];   //get the option flag

    //handle the help flag and then exit normally
    if (opt == 'h'){
        usage(argv[0]);
        exit(0);
    }

    //Finally the input string must be in argv[2]
    if (argc != 3){
        usage(argv[0]);
        exit(1);
    }

    input_string = argv[2];
    //ALL ARGS PROCESSED - The string you are working with is
    //is the third arg or in arv[2]
    
    switch (opt){
        case 'c': {
            int wc = count_words(input_string);         //variable for the word count

            //TODO: #2. Call count_words, return of the result
            //          should go into the wc variable
            printf("Word Count: %d\n", wc);
            break;
        }
        case 'r': {
            //TODO: #3. Call reverse string using input_string
            //          input string should be reversed
            reverse_string(input_string);  
            printf("Reversed string: %s\n", input_string);

            //TODO:  #4.  The algorithm provided in the directions 
            //            state we simply return after swapping all 
            //            characters because the string is reversed 
            //            in place.  Briefly explain why the string 
            //            is reversed in place - place in a comment

            /*
            The string is reversed in place because strings in C 
            are arrays of characters passed by reference (via a pointer).
            Modifying the array elements inside the function directly
            affacts the original string in memory, which avoids the need
            for creating and copying to a new string to save memory and 
            processing time.
            */
            break;
        }
        case 'w': {
            printf("Word Print\n----------\n");
            word_print(input_string);   

            //TODO: #5. Call word_print, output should be
            //          printed by that function
            break;
        }

        //TODO: #6. What is the purpose of the default option here?
        //          Please describe replacing this TODO comment with
        //          your thoughts.

        /*
        The default option acts as a catch-all for invalid or unexpected input. 
        This ensures the program can gracefully handle incorrect command-line arguments 
        by providing usage information and exiting. 
        It prevents undefined behavior by validating all inputs.
        */
        default:
            usage(argv[0]);
            printf("Invalid option %c provided, exiting!\n", opt);
            exit(1);
    }
    //TODO: #7. Why did we place a break statement on each case
    //          option, and did not place one on default.  What
    //          would happen if we forgot the break statement?

    /*
    The break statements prevent fall-through behavior in a switch statement. 
    Without them, the program would execute all subsequent cases until it encounters a break. 
    This could lead to incorrect or unintended behavior.
    */
   return 0;
}