// No dependencies, just compile with "cc namegen.c -o namegen"
// replacing cc with your compiler of choice!

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

struct nametype {
	const char* name;
    size_t nouns, adjs, gens;
	bool default_article;
	size_t maxadj_n, maxadj_g, minadj_n, minadj_g;
    const char* names[];
};
 
struct nametype conspiracy = { "Conspiracy",
    18,76,72,true,
	3,3,0,0, {   // the horrible data structure here is so that we can keep everything
    //NOUNS         pertaining to the nametype in one place. I wish there were a better way.
        "Order", "Cult", "Temple", "Church", "Hand", "Eyes",
        "Source", "Keepers", "Maidens", "Servants", "Templars",
		"Followers", "Celebrants", "Rite", "Sect", "Guild",
		"Society", "School",
       
    //ADJECTIVES
        "Sanctified", "Blasphemous", "Red", "Yellow", "Ebon",
        "Ochre", "Eternal", "Perpetual", "Everlasting", "Black",
        "White", "Infinite", "Timeless", "Mad", "Terrible", "Sightless",
		"All-Seeing", "Third", "Second", "Endless", "Reviled",
		"Absolute", "Damned", "Cursed", "Blessed", "Lucid",
		"Unthinkable", "Nameless", "Unspeakable", "Glorious",
		"Cold", "Burning", "Shapeless", "Unknowable", "Lifeless",
		"Fatal", "Infernal", "Celestial", "Implacable", "Eldritch",
		"Dark", "Resolute", "Resplendant", "Unstoppable", "Blood-Soaked",
		"Endless", "Forgotten", "Iron", "Secret", "Hidden", "Fiery",
		"Ancient", "Silver", "Screaming", "Mighty", "Thousand-Year",
		"Jewelled", "Damnable", "Creeping", "All-Knowing",
		"All-Hearing", "Holy", "Global", "Leering", "Forty-Second",
		"Divine", "Faithful", "Ageless", "Steadfast", "Cruel",
		"Sapphire", "Sapphic", "Secluded", "Scarlet", "Shrieking",
		"Hollow",
       
    //GENS
        "Prince", "King", "Master", "Princess", "Queen", "Mistress",
        "Devourer", "Obliterator", "Destroyer", "0Doom", "0Death",  // this is extremely hacky
        "0Torment", "Serpent", "Moon", "One", "Two", "Three", "Four",
        "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Twelve",       //there is nothing menacing about the number 11
		"Eye", "God", "Horror", "Thing", "Flames", "Night", "Day",
		"Year", "Years", "Way", "Realm", "Path", "Light", "Fire",
		"Door", "Gate", "Plan", "Terror", "0Pain", "0Screams",
		"Road", "Spire", "Beast", "Flesh", "Sword", "Mountain",
		"River","Crown","Scepter","0Fires","Desecrator","Defiler",
		"Despoiler", "Ravager", "Rite", "Sea", "Ocean", "Chaos",
		"Goat", "Legion", "Pyramid", "Dragon", "Hand", "Pantheon",
		"Spirit", "Devil", "Gods",
    }
};
 
struct nametype government = { "Government",
	10,29,64,false,
	3,3,0,0, {
	//NOUNS
		"Kingdom", "Empire", "Republic", "Principality", "Federation",
		"State", "States", "Confederacy", "Powers", "Duchy",

	//ADJECTIVES
		"United", "Confederated", "Allied", "Unified", "Collective",
		"Democratic", "Republican", "Federated", "Glorious", "People's",
		"Socialist", "Soviet", "New", "Old", "Equatorial", "North",
		"South", "West", "East", "Southwest", "Northwest", "Northeast",
		"Southeast", "Great", "Superior", "Mostly Harmless", "Grand",
		"Nuclear", "Imperial",

	//GENS
		"America", "France", "Spain", "Megaspain", "Hyperfrance",
		"Space America", "Space France", "Arabia", "New Arabia",
		"Jersey", "Zealand", "York", "Manchester", "Britain",
		"Sloravia", "Azmenistan", "Arkansas", "Ruritania", "Kundu",
		"Earth", "Mars", "Pluto", "Kansas", "Nebtratucky", "Arkantucky",
		"Nebrahoma", "New Mexigon", "Hawaishington", "Qurac", "Persia",
		"Nevadakota", "Missisota", "Minnesippi", "Montanabraska",
		"Wyomissouri", "New Hampchigan", "Delachusetts", "Arkantexas",
		"Kentexas", "Bumbelch", "Nebravada", "Tennessaw", "Connectican't",
		"Oklatucky", "Oklabama", "Canuckistan",

		"Russia", "Scotland", "Tanzania", "Ireland", "Togo", "Taiwan",
		"Syria", "Senegal", "Serbia", "Paraguay", "Norway", "Korea",
		"Poland", "Smop",

		"Warsaw", "London", "Moscow", "Rome",
		
		"Goat",
	}
};

const struct nametype* alltypes[] = {&conspiracy, &government};

char* gen_name(const struct nametype* t) {
        size_t length=0;
       
        const char* noun = t->names[rand()%t->nouns];
        length=strlen(noun)+3;
		bool swaparticle;
        const char* gen = t->names[t->nouns + t->adjs + rand()%t->gens];
		if (gen[0]=='0') swaparticle=true, gen++; else swaparticle=false;
		if ((t->default_article && !swaparticle) || (!t->default_article && swaparticle)) {
			length+=4;
		}
        length+=strlen(gen)+1;
       
 
        size_t adjc_n = rand() % (t->maxadj_n-t->minadj_n+1) + t->minadj_n;
        size_t adjc_o = rand() % (t->maxadj_g-t->minadj_g+1) + t->minadj_g;
       
        const char** adjs_n = malloc(sizeof(size_t) * adjc_n);
        for (unsigned char i = 0; i<adjc_n; i++) {
                adjs_n[i] = t->names[t->nouns + rand()%t->adjs];
                length+=strlen(adjs_n[i])+1;
        } // ouch
       
        const char** adjs_o = malloc(sizeof(size_t) * adjc_o);
        for (unsigned char i = 0; i<adjc_o; i++) {
                adjs_o[i] = t->names[t->nouns + rand()%t->adjs];
                length+=strlen(adjs_o[i])+1;
        }
       
        char* name = malloc(length+1);
        name[0] = 0; //herp a derp were there some weird errors without this
        //strcat you are fucking evil
        for (size_t i = 0; i<adjc_n; i++) {
                strcat(name, adjs_n[i]);
                strcat(name, " ");
        }
        strcat(name, noun);
        strcat(name, " of ");
		if ((t->default_article && !swaparticle) || (!t->default_article && swaparticle)) strcat (name, "the ");
        for (size_t i = 0; i<adjc_o; i++) {
                strcat(name, adjs_o[i]);
                strcat(name, " ");
        }
        strcat(name, gen);
        
        free(adjs_o);
        free(adjs_n);
        return name;
}
 
int main() {
        srand(time(NULL));
		for (int c=0;c<sizeof(alltypes)/sizeof(struct nametype*);c++) {
	        for (int i=0;i<10;i++) {
                char* name = gen_name(alltypes[c]);
                printf("\x1b[1m%s %d:\x1b[0m The %s\n",alltypes[c]->name,i,name);
                free(name);
	        }
			putchar('\n');
		}
        return 0;
}
