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

#define MAX_RESOURCES 10
#define GROUP_SIZE 10

typedef struct { // Stack for resources
    char *array[MAX_RESOURCES];
    int top;
} resources;

// Zone representation
typedef struct Zone {
    resources resources;   
    int people;            
    struct Zone *next;
    char *zoneID;          
    int zonePriority;      
} zone;

// Priority Queue implementation 
typedef struct PriorityZones {
    zone *head;
    zone *tail;
} PriorityZones;

// Team representation
typedef struct Team {
    char *id;
    int numMembers;
} Team;


// Binary tree for rescue ops:
typedef struct RescuedRecord {
    char *groupID; 
    struct RescuedRecord *left;
    struct RescuedRecord *right;
} RescuedRecord;

typedef struct {
    RescuedRecord *root;
} RescuedTree;

// Function Declaration:
void initPriorityZones(PriorityZones *zoneSet);
zone *createZone();
void insertZone(PriorityZones *zoneSet, zone *newZone);
zone *dequeueZone(PriorityZones *zoneSet);
void addRandomResource(resources *r, int resourceCount);
void manageSupplies(resources *zoneResources, Team *team);
RescuedRecord *insertRescued(RescuedRecord *node, char *groupID);
void printRescued(RescuedRecord *root);
void setTeam(Team *team, int teamIndex);
void freeZone(zone *z);
void transferResources(zone *fromZone, zone *toZone);

// Function Logic:

// Functions for Identifying and Setting Zones
void initPriorityZones(PriorityZones *zoneSet) {
    zoneSet->head = NULL;
    zoneSet->tail = NULL;
}

zone *createZone() {
    zone *newZone = (zone *)malloc(sizeof(zone));
    newZone->resources.top = -1;

    newZone->zoneID = (char *)malloc(50 * sizeof(char));
    printf("Enter Zone ID: ");
    scanf("%49s", newZone->zoneID);

    printf("Enter number of people in %s: ", newZone->zoneID);
    scanf("%d", &newZone->people);

    printf("Enter priority for %s (1-5): ", newZone->zoneID);
    scanf("%d", &newZone->zonePriority);

    printf("Enter number of resources in %s: ", newZone->zoneID);
    int resourceCount;
    scanf("%d", &resourceCount);
    addRandomResource(&newZone->resources, resourceCount);

    printf("\n");
    newZone->next = NULL;
    return newZone;
}

void insertZone(PriorityZones *zoneSet, zone *newZone) {
    if (zoneSet->head == NULL) {
        zoneSet->head = zoneSet->tail = newZone;
    } else {
        zone *current = zoneSet->head, *prev = NULL;
        while (current != NULL && current->zonePriority <= newZone->zonePriority) {
            prev = current;
            current = current->next;
        }
        if (prev == NULL) {
            newZone->next = zoneSet->head;
            zoneSet->head = newZone;
        } else if (current == NULL) {
            zoneSet->tail->next = newZone;
            zoneSet->tail = newZone;
        } else {
            prev->next = newZone;
            newZone->next = current;
        }
    }
}

zone *dequeueZone(PriorityZones *zoneSet) {
    if (zoneSet->head == NULL) {
        printf("No zones left to process.\n");
        return NULL;
    }
    zone *zoneToProcess = zoneSet->head;
    zoneSet->head = zoneSet->head->next;
    return zoneToProcess;
}

// Code for Resource Management:
void addRandomResource(resources *r, int resourceCount) {
    const char *resourceTypes[] = {"Water", "Food", "Medicine", "Tools", "Blankets"};
    int numResourceTypes = sizeof(resourceTypes) / sizeof(resourceTypes[0]);

    for (int i = 0; i < resourceCount && i < MAX_RESOURCES; i++) {
        r->top++;
        int randomIndex = rand() % numResourceTypes;
        r->array[r->top] = (char *)resourceTypes[randomIndex];
    }
}

void manageSupplies(resources *zoneResources, Team *team) {
    if (zoneResources->top >= 0) {
        printf("Team %s using resource %s from zone.\n", team->id, zoneResources->array[zoneResources->top]);
        zoneResources->top--;
    } else {
        printf("No resources left in this zone.\n");
    }
}

// Code for Rescued-recording: Entry for all individuals who are rescued 
RescuedRecord *insertRescued(RescuedRecord *node, char *groupID) {
    if (node == NULL) {
        RescuedRecord *newRecord = (RescuedRecord *)malloc(sizeof(RescuedRecord));
        newRecord->groupID = groupID;
        newRecord->left = newRecord->right = NULL;
        return newRecord;
    }
    if (strcmp(groupID, node->groupID) < 0) {
        node->left = insertRescued(node->left, groupID);
    } else {
        node->right = insertRescued(node->right, groupID);
    }
    return node;
}

void printRescued(RescuedRecord *root) {
    if (root != NULL) {
        printRescued(root->left);
        printf("Rescued Group: %s\n", root->groupID);
        printRescued(root->right);
    }

// Setting and organizing the teams
void setTeam(Team *team, int teamIndex) {
    team->id = (char *)malloc(20 * sizeof(char));
    team->id[0] = '\0';
    sprintf(team->id, "Team_%d", teamIndex + 1);

    printf("Enter number of members in %s: ", team->id);
    scanf("%d", &team->numMembers);
}

void freeZone(zone *z) {
    free(z->zoneID);
    free(z);
}

// Transfer resources from one zone to another
void transferResources(zone *fromZone, zone *toZone) {
    while (fromZone->resources.top >= 0) {
        if (toZone->resources.top < MAX_RESOURCES - 1) {
            toZone->resources.top++;
            toZone->resources.array[toZone->resources.top] = fromZone->resources.array[fromZone->resources.top];
            fromZone->resources.top--;
        } else {
            break;
        }
    }
}

int main() {
    PriorityZones zoneSet;
    initPriorityZones(&zoneSet);

    RescuedTree rescuedTree = {NULL};

    int numberOfZones;
    printf("Enter number of zones to process: ");
    scanf("%d", &numberOfZones);
    zone **zones = (zone **)malloc(numberOfZones * sizeof(zone *)); // Array to keep track of all zones
    for (int i = 0; i < numberOfZones; ++i) {
        zone *newZone = createZone();
        zones[i] = newZone;
        insertZone(&zoneSet, newZone);
    }

    int numberOfTeams;
    printf("Enter number of rescue teams: ");
    scanf("%d", &numberOfTeams);
    Team *teams = (Team *)malloc(numberOfTeams * sizeof(Team));
    for (int i = 0; i < numberOfTeams; i++) {
        setTeam(&teams[i], i);
    }

    zone *currentZone;
    while ((currentZone = dequeueZone(&zoneSet)) != NULL) {
        printf("\nProcessing %s with priority %d\n", currentZone->zoneID, currentZone->zonePriority);
        for (int teamIndex = 0; teamIndex < numberOfTeams; ++teamIndex) {
            int remainingPeople = currentZone->people;

            // Attempt to transfer resources if the current zone is out of resources
            if (currentZone->resources.top < 0) {
                for (int i = 0; i < numberOfZones; i++) {
                    if (zones[i]->resources.top >= 0 && strcmp(zones[i]->zoneID, currentZone->zoneID) != 0) {
                        transferResources(zones[i], currentZone);
                        printf("Transferred resources from zone %s to zone %s.\n", zones[i]->zoneID, currentZone->zoneID);
                        break;
                    }
                }
            }

            while (remainingPeople > 0) {
                printf("Team %s entering %s...\n", teams[teamIndex].id, currentZone->zoneID);
                manageSupplies(&currentZone->resources, &teams[teamIndex]);

                int peopleToRescue = (remainingPeople < GROUP_SIZE) ? remainingPeople : GROUP_SIZE;
                remainingPeople -= peopleToRescue;

                printf("Team %s rescuing %d people.\n", teams[teamIndex].id, peopleToRescue);

                for (int g = 0; g < (peopleToRescue/GROUP_SIZE + (peopleToRescue%GROUP_SIZE > 0 ? 1 : 0)); g++) {
                    char *groupID = (char *)malloc(50 * sizeof(char));
                    groupID[0] = '\0';
                    sprintf(groupID, "Group_%d_From_%s", g + 1, currentZone->zoneID);
                    rescuedTree.root = insertRescued(rescuedTree.root, groupID);
                }
            }
        }
        freeZone(currentZone);
    }

    printf("\nList of Rescued Groups:\n");
    printRescued(rescuedTree.root);

    for (int i = 0; i < numberOfTeams; i++) {
        free(teams[i].id);
    }
    free(teams);
    free(zones); // Free the array keeping track of all zones

    return 0;
}