//Maxwell Brewer                   CS1A                  Chapter 11, p. 648, #13
//
/*******************************************************************************
 * VEND SOFT DRINKS
 * _____________________________________________________________________________
 * This program simulates the operations of a soft drink vending machine. It allows
 * users to view available drinks, select a drink, insert money, and receive change.
 * The program also tracks the machine's profits and updates the stock of drinks
 * after each purchase.
 * 
 * INPUT:
 *    - User inputs the amount of money to insert for their selected drink.
 *    - User selects a drink from a list by entering a number corresponding
 *      to the drink.
 * 
 * OUTPUT:
 *    - Displays the change returned to the user.
 *    - Updates the number of available drinks and displays the current
 *      machine earnings.
 *    - Informs the user if a drink is sold out or if an invalid amount
 *      is entered.
 *******************************************************************************/

#include <iostream>
#include <iomanip>
using namespace std;

// Structure to represent a soft drink
struct Drink {
    string name;         // Name of the drink
    double cost;         // Cost of a single drink
    int numberAvailable; // Number of available drinks
};

// Function prototypes
void initializeDrinks(Drink*&, unsigned&);
void displayDrinks(const Drink*, const unsigned);
double processRequest(Drink*, const unsigned);
void release(Drink*&);

// Main function
int main() {
    cout << "============================================\n";
    cout << "\t     :: Soft Drink Machine ::\n";
    cout << "This program simulates a soft drink machine.\n";
    cout << "It displays the list of available drinks,\n";
    cout << "allows you to choose a drink, calculates the change,\n";
    cout << "and keeps track of the profit earned.\n";
    cout << "============================================\n";

    // Variables
    int choice = 0;
    unsigned numDrinks = 0;
    double totalEarned = 0;

    // Pointer for the drinks array
    Drink* drinks = nullptr;

    // Initialize the drinks array
    initializeDrinks(drinks, numDrinks);

    // Main loop
    do {
        displayDrinks(drinks, numDrinks);
        cout << "Enter the number of the drink you want [or 0 to quit]: ";
        cin >> choice;

        if (choice < 0 || choice > numDrinks) {
        	
        cout << "Invalid choice! Please choose a valid number or 0 to quit.\n";
        
        } else if (choice > 0 && choice <= numDrinks) {
            totalEarned += processRequest(drinks, choice - 1);
        }

        cout << "============================================\n";

    } while (choice != 0);

    // Final earnings display
    cout << "Total money earned in this session: $"
         << setprecision(3) << totalEarned << "\n";
    cout << "--------------------------------------------\n";
    cout << "Thank you for using the vending machine!\n";
    cout << "============================================\n";

    // Release dynamically allocated memory
    release(drinks);
    return 0;
}

// Initialize the drinks array with data
void initializeDrinks(Drink*& drinks, unsigned& size) {
    size = 5;
    drinks = new Drink[size];

    // Drink names, prices, and quantities
    string names[] = {"Cola", "Root Beer", "Lemon-Lime", "Grape Soda",
                      "Cream Soda"};
                      
    double prices[] = {0.75, 0.75, 0.75, 0.80, 0.80};
    int    quantities[] = {20, 20, 20, 20, 20};

    for (unsigned i = 0; i < size; ++i) {
        drinks[i].name = names[i];
        drinks[i].cost = prices[i];
        drinks[i].numberAvailable = quantities[i];
    }
}

// Display available drinks
void displayDrinks(const Drink* drinks, const unsigned size) {
    cout << setw(5) << left << "#" << setw(15) << left << "Drink Name"
         << "Cost"  << setw(20) << right << "Available" << endl;
    cout << "--------------------------------------------\n";

    for (int i = 0; i < size; i++) {
        cout << setw(5)  << left  << (i + 1) << setw(15) << left
             << drinks[i].name
             << setw(6)  << right << fixed << setprecision(2) << drinks[i].cost
             << setw(10) << right << drinks[i].numberAvailable << endl;
    }
    cout << "--------------------------------------------\n";
    cout << "Enter the drink number to select or 0 to quit.\n";
}

// Process user selection and return the earnings
double processRequest(Drink* drinks, const unsigned index) {
    cout << "============================================\n";
    if (drinks[index].numberAvailable <= 0) {
        cout << "Sorry, this drink is sold out.\n";
        return 0;
    }

    double moneyInserted;
    cout << "Enter the amount of money (max $1.00): ";
    cin >> moneyInserted;

    while (moneyInserted != 0 && (moneyInserted > 1.00 ||
           moneyInserted < drinks[index].cost)) 
    
    {
        cout << "Invalid amount. Please enter an amount between " 
             << drinks[index].cost << " and 1.00 or 0 to cancel: ";
        cin  >> moneyInserted;
    }

    if (moneyInserted == 0) {
        return 0;
    }

    cout << "Your change is: $" << fixed << setprecision(3)
         << (moneyInserted - drinks[index].cost) << endl;
         
    drinks[index].numberAvailable--;
    return drinks[index].cost;
}

// Release dynamically allocated memory, separate function helps with efficiency
void release(Drink* &drinks) {
     delete[] drinks;
     drinks = nullptr;
}