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

#define RUNNING     0
#define INFECTED    1
#define RECOVERED   2

typedef struct game_info {
    int num_systems;
    int infected_systems;
    float infection_rate;
    float recovered_rate;
    float patch_rate;
} Info;

typedef struct sys {
    int system_num;
    /**
     * 0 = Running, Not Infected
     * 1 = Infected, Spreading
     * 2 = Recovered, Patched
     */
    int status;
} System;

void print_game_info(Info *info);
void run_game(Info *info);
bool print_population_info(System **systems, int num_systems);

int main(int argc, char *argv[]) {

    /*if (argc != 6) {
        fprintf(stderr, "usage: ./main [systems] [infected] [rate 1] [rate 2] [rate 3]\n");
        return EXIT_FAILURE;
    }*/

    srand(time(NULL));

    Info *info = NULL;
    info = calloc(1, sizeof(Info));

    printf("input: ");
    fscanf(stdin, "%d %d %f %f %f", &info->num_systems, &info->infected_systems, &info->infection_rate, &info->recovered_rate, &info->patch_rate);
    printf("\n");

    /*sscanf(argv[1], "%d", &info->num_systems);
    sscanf(argv[2], "%d", &info->infected_systems);
    sscanf(argv[3], "%f", &info->infection_rate);
    sscanf(argv[4], "%f", &info->recovered_rate);
    sscanf(argv[5], "%f", &info->patch_rate);*/

    print_game_info(info);
    run_game(info);

    free(info);

    return EXIT_SUCCESS;
}

void run_game(Info *info) {
    int num_systems = info->num_systems;
    int initial_infected = info->infected_systems;
    float infection_rate = info->infection_rate;
    float recovered_rate = info->recovered_rate;
    float patch_rate = info->patch_rate;

    bool running = true;

    // Setting up all the systems
    System **systems = NULL;
    systems = calloc(num_systems, sizeof(System *));
    unsigned int i;
    for (i = 0; i < num_systems; i++) {
        systems[i] = calloc(1, sizeof(System));
        systems[i]->system_num = i + 1;
        systems[i]->status = (i < initial_infected) ? INFECTED : RUNNING;
    }

    printf("Beginning Simulation:\n");
    print_population_info(systems, num_systems);
    while (running == true) {
        for (i = 0; i < num_systems; i++) {
            System *sys = systems[i];
            float random = (rand() % 10) / 10.0;
            switch (sys->status) {
                case RUNNING:
                    if (random <= infection_rate) {
                        systems[i]->status = INFECTED;
                    } else if (random <= patch_rate) {
                        systems[i]->status = RECOVERED;
                    }
                    break;
                case INFECTED:
                    if (random <= recovered_rate) {
                        systems[i]->status = RECOVERED;
                    }
                    break;
                case RECOVERED:
                    break;
                default:
                    fprintf(stderr, "error finding status of system %d\n", (i + 1));
                    break;
            }
        }
        bool stop = print_population_info(systems, num_systems);
        if (stop)
            running = false;
    }

    for (i = 0; i < num_systems; i++)
        free(systems[i]);
    free(systems);
}

bool print_population_info(System **systems, int num_systems) {
    int running = 0;
    int infected = 0;
    int patched = 0;

    unsigned int i;
    for (i = 0; i < num_systems; i++) {
        switch (systems[i]->status) {
            case RUNNING:
                running++;
                break;
            case INFECTED:
                infected++;
                break;
            case RECOVERED:
                patched++;
                break;
            default:
                fprintf(stderr, "error with status code of system %d\n", systems[i]->status);
                break;
        }
    }
    printf("\tRunning: %d\tInfected: %d\tPatched: %d\n", running, infected, patched);
    if (patched == num_systems)
        return true;
    return false;
}

void print_game_info(Info *info) {
    printf("Game Information:\n");
    printf("\tSystem Population: %d\n", info->num_systems);
    printf("\tInitial Infected Systems: %d\n", info->infected_systems);
    printf("\tInfection Rate: %0.3f\t(Opportunites -> Infection)\n", info->infection_rate);
    printf("\tRecovery Rate: %0.3f\t(Infection -> Recovered)\n", info->recovered_rate);
    printf("\tPatch Rate: %0.3f\t(Opportunities -> Patched)\n", info->patch_rate);
}