#include <stdio.h>

#define TRUE 1
#define FALSE 0

#define HEAD 0
#define BODY 1
#define ARMS 2
#define LEGS 3
#define DONE 4

#define MAX_STR_LEN 32

int nparts = 3;
// 4x4 grid
char *heads[] = {"r--7\n|o.|\n\\ -|\n Lc*\n", "^  ^\n|--|\n|0o|\n$()$\n", "    \n ^^ \n O  \n-__-\n"};
//4x2 grid
char *miniheads[] = {" oO \n r* \n", "0  0\n|__|\n", "- o \n ~  \n"};

// 6x10 grid
char *bodies[] = {"R-TT-v\n|c--d|\n|-  -|\n|.   |\n|  . |\n \\  / \n__||__\n|    |\nl_  _7\n  ^-  \n", "  9p  \n |--| \n /  \\ \n \\  / \n  ||  \n  ||  \n------\n|    |\n--||--\n +||+ \n", "  --  \n ---- \n/-  -\\\n|    |\n|    |\n|    |\n\\-  -/\n ---- \n  --  \n _--_ \n"};
// 6x6 grid
char *minibodies[] = {"-rv^--\n |  / \n  \\ / \n / |  \n |  \\ \n ^-+} \n", "+-++-+\n|    |\n--  --\n\\    /\n |--| \n-|  |-\n", "__--__\n  ||  \n--||--\n  ||  \n  ||  \n--||--\n"};

// 2x10 grid
char *arms[] = {" |\nP^\n|_\n||\n||\n+)\n (\nTT\n||\n^^\n", "| \n| \no-\n |\n |\n X\n  \n  \n  \n  \n  \n", "  \n+-\n  \n+-\n| \n  \n+-\n  \n+-\n  \n"};
// 2x6 grid
char *miniarms[] = {" |\n |\n |\n |\n| \n+ \n", "  \n+ \n| \n--\n  \n  \n", "|-\n+ \n  \n+ \n| \nO \n"};

// 10x10 grid (have fun)
char *legs[] = {"    TT    \n   R^^7   \n   |  |   \n   |  |   \n   |  |   \n   |  |   \n   |  |   \n   |  |   \n   |  |   \n  _*_ *_  \n", "+--------+\n|        |\n\\        /\n \\      / \n  \\    /  \n   \\  /   \n   |  |   \n   |  |   \n   _- -_   \n___/  \\___\n", "  ||  ||  \n___----___\n|+      +|\n .        \n        . \n      .   \n .     .  \n       .  \n -||--||- \n  ++  ++  \n"};
// 10x6 grid
char *minilegs[] = {"    ||    \n    ||    \n    ||    \n    ||    \n    |+    \n    +_    \n", "    /\\    \n   /  \\   \n  /    \\  \n  |    |  \n  |    |  \n  ++  ++  \n", "    ++    \n      .   \n          \n     .    \n   \\  /   \n   -++-   \n"};

char *headl = "    ";
char *headr = "    ";

struct monster {
    char *head;
    char *arms;
    char *body;
    char *legs;
};

void make_monster(struct monster *monster, int head, int body, int arm, int leg, int choosing,
                  int is_mini);
void print_monster(struct monster monster);

int main(void) {
    // these three variables will need to live on the stack,
    // taking up 16 + 16 + 32 bytes in total.
    struct monster big;
    struct monster mini;
    char family_name[MAX_STR_LEN];

    printf("welcome to monster mips!\n");
    printf("enter the name for your monster duo! ");

    // strictly, the `&` is not necessary here - but it makes it clearer;
    // the array `family_name` would automatically decay to its address 
    // when passed as a function argument!
    fgets(&family_name, MAX_STR_LEN, stdin);

    printf("select your big monster:\n");

    make_monster(&big, 0, 0, 0, 0, HEAD, FALSE);

    printf("select your mini monster:\n");

    make_monster(&mini, 0, 0, 0, 0, HEAD, TRUE);

    printf("unleash the monsters!\n");

    // strictly, the `&` is not necessary here - but it makes it clearer
    // the array `family_name` would automatically decay to its address 
    // when passed as a function argument!
    printf("meet %s", &family_name);

    print_monster(big);
    putchar('\n');
    print_monster(mini);

    return 0;
}

void print_head(char *head) {
    while (1) {
        if (!*head) {
            return;
        }
        printf("%s", headl);
        while (*head != '\n') {
            putchar(*head++);
        }
        head++;
        printf("%s", headr);
        putchar('\n');
    }
}

void print_body(char *body, char *arms) {
    char *a1;
    char *a2;
    while (1) {
        if (!*arms || !*body) {
            return;
        }
        a1 = arms;
        while (*a1 != '\n') {
            putchar(*a1++);
        }
        putchar(' ');
        while (*body != '\n') {
            putchar(*body++);
        }
        putchar(' ');
        a2 = arms;
        while (*a2 != '\n') {
            a2++;
        }
        a2--;
        while (a2 != arms) {
            putchar(*a2--);
        }
        putchar(*a2);
        while (*arms != '\n') {
            arms++;
        }
        arms++;
        body++;
        putchar('\n');
    }
}

void print_legs(char *legs) {
    while (1) {
        if (!*legs) {
            return;
        }
        putchar(' ');
        while (*legs != '\n') {
            putchar(*legs++);
        }
        legs++;
        putchar(' ');
        putchar('\n');
    }
}

void help_make_monster(char **bigparts, char **miniparts, int *monster_index, 
                       char **edit_monster, int *choosing, int is_mini) {
    char choose;

    printf("selecting:\n");
    if (is_mini) {
        *edit_monster = miniparts[*monster_index];
        printf("%s", miniparts[*monster_index]);
    } else {
        *edit_monster = bigparts[*monster_index];
        printf("%s", bigparts[*monster_index]);
    }
    
    printf("choose? (y/n): ");

    choose = getchar();
    while (choose == '\n') {
        choose = getchar();
    }

    if (choose == 'y' || choose == 'Y') {
        (*choosing)++;
    } else {
        (*monster_index)++;
        *monster_index %= nparts;
    }

}

void make_monster(struct monster *monster, int head, int body, int arm, int leg, int choosing,
                  int is_mini) {
    char **bigparts;
    char **miniparts;
    char **edit_monster;
    int *monster_index;

    switch (choosing) {
        case HEAD:
            bigparts = heads;
            miniparts = miniheads;
            monster_index = &head;
            edit_monster = &monster->head;
            break;
        case BODY:
            bigparts = bodies;
            miniparts = minibodies;
            monster_index = &body;
            edit_monster = &monster->body;
            break;
        case ARMS:
            bigparts = arms;
            miniparts = miniarms;
            monster_index = &arm;
            edit_monster = &monster->arms;
            break;
        case LEGS:
            bigparts = legs;
            miniparts = minilegs;
            monster_index = &leg;
            edit_monster = &monster->legs;
            break;
        case DONE: return;
    }

    help_make_monster(bigparts, miniparts, monster_index, edit_monster, &choosing, is_mini);
    
    make_monster(monster, head, body, arm, leg, choosing, is_mini);

    return;
}

void print_monster(struct monster monster) {
    print_head(monster.head);
    print_body(monster.body, monster.arms);
    print_legs(monster.legs);
}

