summaryrefslogtreecommitdiffstats
path: root/C++/Menu System/MenuSystem.cpp
blob: 20226a4a4f48c50580bce5332392202f3c55ead9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// Name: msglm
// Date: Oct 21st, 2022
// Program Name: Menu System 
// Description: CLI, self-servicing kiosk

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

//Classes

//I would never, ever make this an object in production
//the concept of an "Orderable" is pure data read from a file that should be acted upon, but not act.
class Orderable {
    private:
        string name;
        double price;
    public:
        Orderable(double iprice, string iname) {
            name = iname;
            price = iprice;
        }

        string get_name() {return name;}
        double get_price() {return price;}
};


//Structs
struct foodOrder {
    string name;
    double price;
    int quantity;
};

//Implementation of Nim's readline (https://nim-lang.org/docs/io.html#readLine%2CFile) because 
//I am absolutely sick of having to deal with C++'s obsession with streaming.
//
//I swear if I have to reimplement the entire Nim language in C++20 just 
//to get a compiled language that doesn't increase my chance of stroke 20 fold I will

string readline(ifstream & fileVar) {
    string temp;
    getline(fileVar, temp);
    return temp;
} 


void initalize(string location, ifstream & fileVar) {
    fileVar.open(location);

    if (!fileVar) {
        cout << "ERROR! " << location << " failed to open!";
        exit(1);
    }
}


//Ideally, the input file should be JSON, YAML, or TOML based 
//instead of pure plain text for ease of human access
//but C++ doesn't have JSON parsing library in std for some reason
vector<Orderable> encodeOrderables(ifstream & fileVar) {
    string temp;
    vector<Orderable> orderablesFromFile;
    while(fileVar.peek() != EOF) {
        //Here's something absolutely nasty that I discovered while working on this:
        //when attempting to write the line
        //orderablesFromFile.push_back(Orderable(readline(fileVar)), stod(readline(fileVar)));
        //with the object's constructor taking the name then price parameter, I found out that
        //constructors are executed from right-to-left, not left-to-right and the price would be
        //read first rather than the name.
        //
        //This might be the case for all functions, I did not check.
        //
        //There is literally no good reason for this to be the case.
        orderablesFromFile.push_back(Orderable(stod(readline(fileVar)), readline(fileVar)));
    }
    return orderablesFromFile;
}

//Menu systems
//Wish we could do some ncurses TUI menus, but alas we're stuck with subpar prompts

int catagoryMenu() {
    int choice;
    //No input validation here since the rubric doesn't call for it.
    cout << "Pick a catagory\n";
    cout << "1. Drink\n";
    cout << "2. Appetizer\n";
    cout << "3. Entree\n";
    cout << "4. Dessert\n";
    cout << "5. Finish Order\n";
    cout << "Enter Selection: ";
    cin >> choice;
    return choice;
}

foodOrder orderingMenu(vector<Orderable> items) {
    foodOrder completeOrder;
    int choice;
    for(int itemPos = 0; itemPos < items.size(); itemPos++) {
        cout << itemPos << ". " << items[itemPos].get_name() << " - $" << items[itemPos].get_price() << endl;
    }
    cout << "Enter Selection: ";
    cin >> choice;
    cout << "Enter Amount Desired: ";
    cin >> completeOrder.quantity;

    completeOrder.name = items[choice].get_name();
    completeOrder.price = items[choice].get_price();

    //"...you will need to record the item name, price and the quantity desired inside of variables (vector or array) for output later..."
    //I am modifying this instruction a bit to use a struct instead since structs can hold multiple datatypes and play nice with functions
    return completeOrder;
}

//Who can afford to pay this much when tipping? 
//I can barely afford car insurance!
double tip() {
    int choice;
    //No input validation here since the rubric doesn't call for it.
    cout << "What percent would you like to tip?\n";
    cout << "1. 18%\n";
    cout << "2. 20%.\n";
    cout << "3. 25%.\n";
    cout << "4. Custom Amount.\n";
    cin >> choice;
    switch(choice) {
        case 1:
            return 0.18;
            break;
        case 2:
            return 0.20;
            break;
        case 3:
            return 0.25;
            break;
        case 4:
            double tip;
            cout << "Enter a tip amount (decimal notation) [ex: 0.18]: ";
            cin >> tip;
            //Evil solution to evil users
            return abs(tip);
            break;
        default:
            cout << "ERROR: Your input was invalid, terminating";
            exit(1);

    }
    return choice;

}

double figureTotal(vector<foodOrder> orderList) {
    double subtotal;
    for(int orderPos = 0; orderPos < orderList.size(); orderPos++) {
        subtotal = subtotal + orderList[orderPos].price;
    }
    double tax = subtotal*0.1;
    double total = subtotal+tax;

    //tips
    cout << "===Amount Currently Due==\n";
    cout << "Subtotal: $" << subtotal << endl;
    cout << "Tax: $" << tax << endl;
    cout << "Total: $" << total << endl;
    cout << "=========================\n";


    total = total + (total*tip());
    
    cout << "\033[2J\033[1;1H";
    
    cout << "===Amount Currently Due==\n";
    cout << "Subtotal: $" << subtotal << endl;
    cout << "Tax: $" << tax << endl;
    cout << "Total: $" << total << endl;

    return total;
}

void collectDues(double amountDue) {
    double paid;
    while (amountDue > 0) {
        cout << "Please pay for the amount owed: $" << amountDue << endl;
        cout << "Enter payment: ";
        cin >> paid;
        amountDue = amountDue - paid;
        paid = 0;
    }
}

int main() {
    //File Vars & Inits
    ifstream drinkFile;
    ifstream appetizerFile;
    ifstream entreeFile;
    ifstream dessertFile;

    initalize("drink.txt", drinkFile);
    initalize("appetizer.txt", appetizerFile);
    initalize("entree.txt", entreeFile);
    initalize("dessert.txt", dessertFile);

    //Ordering Vars
    vector<Orderable> possibleDrinks = encodeOrderables(drinkFile);
    vector<Orderable> possibleAppetizer = encodeOrderables(appetizerFile);
    vector<Orderable> possibleEntree = encodeOrderables(entreeFile);
    vector<Orderable> possibleDessert = encodeOrderables(dessertFile);
    
    vector<foodOrder> userOrderList;
    bool ordering = true;

    //"The customer should be able to remain in a category menu until they are ready to return to the main menu"
    //I assume this means that the customer should be allows to keep ordering until they're satisfied
    while(ordering) {
    switch(catagoryMenu()) {
        case 1:
            userOrderList.push_back(orderingMenu(possibleDrinks));
            break;
        case 2:
            userOrderList.push_back(orderingMenu(possibleAppetizer));
            break;
        case 3:
            userOrderList.push_back(orderingMenu(possibleEntree));
            break;
        case 4:
            userOrderList.push_back(orderingMenu(possibleDessert));
            break;
        case 5:
            ordering = false;
            break;
        default:
            cout << "ERROR: Your input was invalid, terminating";
            exit(1);
    }

    }
    collectDues(figureTotal(userOrderList));
    //When the customer is finished ordering, display the subtotal, tax, and total on the screen
    //Ask for a tip (make a suggested tip amount with 18%, 20%, 25%), then update the total with the tip amount entered
    //Get payment from the user and display change due to the customer
    //If the customer does not pay enough money, then the program should continue to ask for money until the total is paid in full

}

/*
   This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 ONLY as published by the Free Software Foundation.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License along with this program.  If not, see <https://www.gnu.org/licenses/>.
   */