// Arup Guha
// 9/5/2021
// Solution to Fall 2021 COP 3502 Program 1: Making Smoothies

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct item {
    int itemID;
    int numParts;
} item;

typedef struct recipe {
    int numItems;
    item* itemList;
    int totalParts;
} recipe;

#define MAX_INGRED_SIZE 20

char** readIngredients(int numIngredients);
recipe* readRecipe(int numItems);
recipe** readAllRecipes(int numRecipes);
double* calculateOrder(int numSmoothies, recipe** recipeList, int numIngredients);
void printOrder(char** ingredientNames, double* orderList, int numIngredients);

void freeIngredients(char** ingredientList, int numIngredients);
void freeRecipes(recipe** allRecipes, int numRecipes);

int main(void) {

    // Read in the number of ingredients.
    int numIngredients, numSmoothies;
    scanf("%d", &numIngredients);

    // Read in the ingredients.
    char** ingredientList = readIngredients(numIngredients);

    // Read in all the smoothie recipes.
    scanf("%d", &numSmoothies);
    recipe** allRecipes = readAllRecipes(numSmoothies);

    // Read in the number of stores.
    int numStores;
    scanf("%d", &numStores);

    // Go through each store.
    for (int i=1; i<=numStores; i++) {

        // Read in the # of smoothies THIS store sells.
        int numTypes;
        scanf("%d", &numTypes);

        // Get the order for this store.
        double* order = calculateOrder(numTypes, allRecipes, numIngredients);

        // Print it!
        printf("Store #%d:\n", i);
        printOrder(ingredientList, order, numIngredients);

        // Free this array, we don't need it any more.
        free(order);
    }

    // Free the rest of the stuff.
    freeRecipes(allRecipes, numSmoothies);
    freeIngredients(ingredientList, numIngredients);

    return 0;
}

// Pre-condition: 0 < numIngredients <= 100000
// Post-condition: Reads in numIngredients number of strings
//                 from standard input, allocates an array of
//                 strings to store the input, and sizes each
//                 individual string dynamically to be the
//                 proper size (string length plus 1), and
//                 returns a pointer to the array.
char** readIngredients(int numIngredients) {

    // Make room for the pointers to the strings.
    char** res = malloc(numIngredients*sizeof(char*));

    // Read through each ingredient and store.
    for (int i=0; i<numIngredients; i++) {

        // Read in string, allocate space and copy into our array.
        char temp[MAX_INGRED_SIZE+1];
        scanf("%s", temp);
        res[i] = malloc( (strlen(temp)+1)*sizeof(char));
        strcpy(res[i], temp);
    }

    // Here's the ingredient list.
    return res;
}

// Pre-condition: 0 < numItems <= 100
// Post-condition: Reads in numItems number of items
//                 from standard input for a smoothie recipe,
//                 Dynamically allocates space for a single
//                 recipe, dynamically allocates an array of
//                 item of the proper size, updates the
//                 numItems field of the struct, fills the
//                 array of items appropriately based on the
//                 input and returns a pointer to the struct
//                 dynamically allocated.
recipe* readRecipe(int numItems) {

    // Allocate space for one recipe.
    recipe* rList = malloc(sizeof(recipe));

    // Assign this.
    rList->numItems = numItems;

    // Make room for each item.
    rList->itemList = calloc(numItems, sizeof(item));

    // Set this to 0 and update as we read in the parts.
    rList->totalParts = 0;

    // Read in each ingredient - directly into appropriate struct.
    for (int i=0; i<numItems; i++) {
        scanf("%d%d", &rList->itemList[i].itemID, &rList->itemList[i].numParts);
        rList->totalParts += rList->itemList[i].numParts;
    }

    // This is ready to go.
    return rList;
}

// Pre-condition: 0 < numRecipes <= 100000
// Post-condition: Dynamically allocates an array of pointers to
//                 recipes of size numRecipes, reads numRecipes
//                 number of recipes from standard input, creates
//                 structs to store each recipe and has the
//                 pointers point to each struct, in the order
//                 the information was read in. (Should call
//                 readRecipe in a loop.)
recipe** readAllRecipes(int numRecipes) {

    // Allocate room for the array of pointers.
    recipe** allRecipes = calloc(numRecipes, sizeof(recipe*));

    // Loop through each recipe.
    for (int i=0; i<numRecipes; i++) {

        // Read in the # of items in this recipe and then read it in.
        int numItems;
        scanf("%d", &numItems);
        allRecipes[i] = readRecipe(numItems);
    }

    // All the recipes are stored here.
    return allRecipes;
}

// Pre-condition: 0 < numSmoothies <= 100000, recipeList is pointing to the list of all
//                smoothie recipes and numIngredients equals the number of total ingredients.
// Post-condition: Reads in information from standard input
//                 about numSmoothies number of smoothie orders
//                 and dynamically allocates an array of doubles of size numIngredients
//                 such that index i stores the # of pounds of ingredient i
//                 needed to fulfill all smoothie orders and
//                 returns a pointer to the array.
double* calculateOrder(int numSmoothies, recipe** recipeList, int numIngredients) {

    // calloc zeroes this out since it's a frequency array.
    double* freq = calloc(numIngredients, sizeof(double));

    // Read through each smoothie.
    for (int i=0; i<numSmoothies; i++) {

        // Get the smoothie number & weight.
        int sNum;
        double weight;
        scanf("%d%lf", &sNum, &weight);

        // Go through each item in this smoothie.
        for (int j=0; j<recipeList[sNum]->numItems; j++) {

            // Extract out these pieces of information for this item.
            int myItem = recipeList[sNum]->itemList[j].itemID;
            int parts = recipeList[sNum]->itemList[j].numParts;

            // Update the amount that we need of myItem, using the appropriate proportion.
            freq[myItem] += ( weight * ((double)parts)/recipeList[sNum]->totalParts);
        }
    }

    // Ta da!
    return freq;
}

// Pre-conditions: ingredientNames store the names of each
//                 ingredient and orderList stores the amount
//                 to order for each ingredient, and both arrays are of size numIngredients.
// Post-condition: Prints out a list, in ingredient order, of each
//                 ingredient, a space and the amount of that
//                 ingredient to order rounded to 6 decimal
//                 places. One ingredient per line.
void printOrder(char** ingredientNames, double* orderList, int numIngredients) {

    // Go through each ingredient.
    for (int i=0; i<numIngredients; i++) {

        // Skip ingredients we don't need to order.
        if (orderList[i] < 1e-6) continue;

        // This is the desired format. For both my desktop and Eustis %f worked and %lf didn't. Not sure why.
        printf("%s %.6f\n", ingredientNames[i], orderList[i]);
    }
}

// Pre-conditions: ingredientList is an array of char* of size numIngredients
//                 with each char* dynamically allocated.
// Post-condition: all the memory pointed to by ingredientList is freed.
void freeIngredients(char** ingredientList, int numIngredients) {
    for (int i=0; i<numIngredients; i++)
        free(ingredientList[i]);
    free(ingredientList);
}

// Pre-conditions: allRecipes is an array of recipe* of size numRecipes
//                 with each recipe* dynamically allocated to point to a
//                 single recipe.
// Post-condition: all the memory pointed to by allRecipes is freed.
void freeRecipes(recipe** allRecipes, int numRecipes) {

    for (int i=0; i<numRecipes; i++) {

        // This frees the array of items.
        free(allRecipes[i]->itemList);

        // This was dynamically allocated also and needs to be freed.
        free(allRecipes[i]);
    }

    // Finally free the array of pointers.
    free(allRecipes);
}
