Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <string>
- #include <stdlib.h> //for system("CLS");
- #include <windows.h> //for GetAsyncKeyState();
- using namespace std;
- struct Email //just a basic struct
- {
- //below is just data stored in the node
- string sender;
- string recipient;
- string day, month, year;
- string title;
- string content;
- //adapted from https://docs.microsoft.com/en-us/cpp/code-quality/c26495?view=msvc-160 , where it is set via default member initialization;
- int index{}; //every new email will have a different index, used to traverse and pinpoint the correct email.
- Email* prev{}, * next{}; //just previous and next nodes
- };
- Email* myTemplate() //used to initialise a struct (alternative of constructor)
- {
- Email* temp = new Email;
- temp->sender = "\0";
- temp->recipient = "\0";
- temp->day = "\0";
- temp->month = "\0";
- temp->year = "\0";
- temp->title = "\0";
- temp->content = "\0";
- temp->index = 0;
- temp->next = NULL;
- temp->prev = NULL;
- return temp;
- };
- struct UI //another basic struct, but using constructors
- {
- UI* prev, * next; //previous and next nodes
- string text[2]; //stores the selected text and unselected text
- bool selected; //bool to know when to trigger selected text
- int menuFunc; //used to determine which function to call, can also be used to represent Email's index when passing in values
- UI()
- {
- prev = NULL;
- next = NULL;
- text[0] = "\0";
- text[1] = "\0";
- selected = false;
- menuFunc = -1;
- }
- UI(UI* myPrev, UI* myNext, int myMFunc, string myText)
- {
- prev = myPrev;
- next = myNext;
- menuFunc = myMFunc;
- text[0] = myText;
- text[1] = "<<" + text[0] + ">>";
- selected = false;
- }
- };
- void mainMenu(UI* uiNavi, UI* uiHead)
- {
- uiNavi = uiHead; //sets navigator to first element if it isn't already
- cout << endl <<
- "Welcome to the email simulator! Please select your operation from the list below." << endl <<
- "_________________________________________________________________________________" << endl << endl;
- while (uiNavi != NULL)//loop stops when it finally reaches NULL
- {
- cout << uiNavi->text[(int)uiNavi->selected] << endl << endl; //if the current uiNavi->selected is true, then the selected text will be displayed instead
- uiNavi = uiNavi->next;
- }
- cout <<
- "_________________________________________________________________________________" << endl <<
- "[Use ARROW KEYS UP & DOWN to navigate, ENTER/RETURN to select operation]" << endl;
- }
- int getKeyInt() //just a function to get relevant key codes
- {
- if (GetAsyncKeyState(VK_UP))
- {
- return VK_UP;
- }
- else if (GetAsyncKeyState(VK_DOWN))
- {
- return VK_DOWN;
- }
- else if (GetAsyncKeyState(VK_RETURN))
- {
- return VK_RETURN;
- }
- else if (GetAsyncKeyState(VK_ESCAPE))
- {
- return VK_ESCAPE;
- }
- else
- {
- return -1;
- }
- }
- void displayEmail(int mailIndex, Email* eNavi, Email* eHead, Email* eTail) //used when displaying the individual stored emails
- {
- system("CLS");
- eNavi = eHead; //sets email navigator to earliest element in the stack
- while (eNavi->index != mailIndex) //traverse the linked list until it reaches the email with the same index, reference line XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX for explanation
- {
- eNavi = eNavi->next;
- }
- cout <<
- "\nSender's Name: " << eNavi->sender <<
- "\nRecipient's Name: " << eNavi->recipient <<
- "\n\nDate: " << eNavi->day + " . " + eNavi->month + " . " + eNavi->year <<
- "\n\nTitle: " << eNavi->title <<
- "\n\nContent: \n" << eNavi->content << endl;
- system("pause");
- return;
- }
- void deleteMail(Email*& eNavi, Email*& eHead, Email*& eTail, int mailIndex, bool& modified) //used to remove nodes from the link list, not exactly popping though.
- {
- system("CLS");
- string temp = "\0"; //just to get user confirmation
- cout << "\nAre you sure you want to delete this mail? Once deleted the data is gone forever!\nType DELETE to confirm mail deletion (CASE SENSITIVE), type anything else to cancel.\n:";
- cin >> temp;
- if (temp == "DELETE")
- {
- eNavi = eHead; //sets email navigator to earliest element in the node again if it isn't already
- while (eNavi->index != mailIndex) //traversing until the desired email to delete is reached, lets call this node a "node of interest"
- {
- eNavi = eNavi->next;
- }
- if (eNavi != NULL)//just in case for some reason the email was a NULL
- {
- if (eNavi->next != NULL)//if the "node of interest" has an earlier node
- {
- eNavi = eNavi->next;//navigator will switch addresses to earlier node
- if (eNavi->prev->prev != NULL)//if the "node of interest" has a newer node after itself
- {
- eNavi->prev = eNavi->prev->prev; //navigator will point it's current "prev" to change from "node of interest" to the node after the "node of interest"
- eNavi->prev->next = eNavi; //and that node will point it's "next" to the navigator's current address
- }
- else//if "node of interest" doesn't have a newer node, ie. it is the latest added node
- {
- eNavi->prev = NULL;//navigator will point it's current "prev" to change from "node of interest" to NULL
- eTail = eNavi; //a tail node will be assigned to navigator's address
- }
- }
- else if(eNavi->prev != NULL)//if "node of interest" has a newer node added after itself
- {
- eNavi = eNavi->prev; //navigator will then siwtch addresses to newer node
- eNavi->next = NULL; //navigator will point it's "next" to change from "node of interest" to a NULL
- eHead = eNavi; //a head node will be assigned to navigator's address
- }
- else// if "node of interest" doesn't have an earlier node or a newer node after itself
- {
- eHead = myTemplate(); //head will be reinitialised
- eTail = eHead; //tail will have the same address as head
- eNavi = eHead; //navigator will also have the same address as head
- }
- }
- cout << "Mail was deleted." << endl;
- modified = true; //used in refreshing the displayInbox() function to re-trigger the stuff outside the loop
- system("pause");
- return;
- }
- else
- {
- return;
- }
- }
- bool mailExecute(int executionCode, bool runFlag, UI* myNavi, UI* myHead, UI* uiTailIB, Email*& eNavi, Email*& eHead, Email*& eTail, int mailIndex, bool& modified) //a hub to determine what function is to be called based on the selected UI node
- {
- if (executionCode == 1)
- {
- if (mailIndex != -1 && mailIndex != 0) // -1 and 0 are both default nodes, so they shouldn't trigger
- {
- displayEmail(mailIndex, eNavi, eHead, eTail);
- }
- else
- {
- system("CLS");
- cout << "\nNo mail to read!" << endl;
- system("pause");
- }
- return runFlag; //used to determine if the main loop outside this function with continue running or not
- }
- else if (executionCode == 2)
- {
- deleteMail(eNavi, eHead, eTail, mailIndex, modified);
- runFlag = false;
- return runFlag;
- }
- else if (executionCode == 99)
- {
- runFlag = false;
- return runFlag;
- }
- else
- {
- cout << "\nINVALID CODE" << endl; //usually not triggered, just in case
- return runFlag;
- }
- }
- bool prompt(string selectedText, int mailIndex, Email*& eNavi, Email*& eHead, Email*& eTail, bool& modified) //a selected mail hub to determine what function is to be called based on the selected UI node, triggered when a mail is selected
- {
- bool tempRunFlag = true; // just a temporary run flag to determine if the loop will continue to run
- int tempKeyPress; // to log the current keypress
- UI* myNavi = new UI, * myHead = myNavi, * myTail = myNavi; //creating temporary UI nodes to use with this function
- UI* refreshCache = new UI; // to log the navigator's location upon reprinting the screen
- //initialising the UI nodes
- myNavi->next = new UI(NULL, NULL, 1, "READ EMAIL");
- myNavi = myNavi->next;
- myHead = myNavi;
- myHead->selected = true;
- myNavi->next = new UI(myNavi, NULL, 2, "DELETE EMAIL");
- myNavi = myNavi->next;
- myNavi->next = new UI(myNavi, NULL, 99, "BACK");
- myNavi = myNavi->next;
- myTail = myNavi;
- refreshCache = myHead; //before the loop happens, it points to a head node
- while (tempRunFlag)
- {
- system("CLS");
- cout << "SELECTED MAIL:\n" + selectedText << endl << endl; //shares the same text to indicate selected mail
- myNavi = myHead; //navigator will switch to head's address
- while (myNavi != NULL)//printing out the UI nodes
- {
- cout << myNavi->text[(int)myNavi->selected] << endl;
- myNavi = myNavi->next;
- }
- cout << "\n[Use ARROW KEYS UP & DOWN to navigate, ENTER / RETURN to select operation]" << endl;
- myNavi = refreshCache;//will be used to point navigator to a different node after printing for selection purposes
- system("pause");
- tempKeyPress = getKeyInt();
- //used to navigate the nodes
- switch (tempKeyPress)
- {
- case VK_UP:
- if (myNavi != myHead)
- {
- myNavi->selected = false;
- myNavi = myNavi->prev;
- myNavi->selected = true;
- refreshCache = myNavi; //saves the address to be reassigned to navigator after the reprinting
- }
- else
- {
- break;
- }
- break;
- case VK_DOWN:
- if (myNavi != myTail)
- {
- myNavi->selected = false;
- myNavi = myNavi->next;
- myNavi->selected = true;
- refreshCache = myNavi;
- }
- else
- {
- break;
- }
- break;
- case VK_RETURN:
- tempRunFlag = mailExecute(myNavi->menuFunc, tempRunFlag, myNavi, myHead, myTail, eNavi, eHead, eTail, mailIndex, modified); //to determine whether the loop should continue or break after function is called
- break;
- default:
- break;
- }
- }
- return !modified; //returns an inverse of the "modified" bool, to determine whether the loop should continue or break
- }
- void displayInbox(UI* myNavi, UI* myHead, UI* myTail, Email*& eNavi, Email*& eHead, Email*& eTail) //displays the inbox of the mail
- {
- bool modified = false;
- bool tempRunFlag = true;
- int tempKeyPress;
- UI* refreshCache = myHead; // to log the navigator's location upon reprinting the screen, points to head before the loop begins
- myNavi = myHead; //points the navigator to the newest node in the list
- eNavi = eTail; //email navigator switches address to the newest node in the email linked list
- if (eNavi->sender != "\0") //to check if newest mail has values, just in case
- {
- myNavi->menuFunc = eNavi->index; //assigns the email index to the "menuFunc" to be passed when calling deleteMail() and displayMail()
- myNavi->text[0] = eNavi->sender + "|| " + eNavi->title + " || " + (string)eNavi->day + " . " + (string)eNavi->month + " . " + (string)eNavi->year; //sets the UI text of navigator
- myNavi->text[1] = "<<" + myNavi->text[0] + ">>";
- myHead = myNavi;//setting myHead to point to navigator's current address
- myHead->selected = true; //this will trigger the selected text's output later
- refreshCache = myHead;// assigns refreshCache to myHead
- myTail = myHead; //if it's only 1 mail in the list, then this will prevent UI from traversing into NULL, if not, below will change the values
- if (eNavi->prev != NULL)//if email navigator has a earlier mail to point to, false if there's only 1 element in the list, which is already done above
- {
- while (eNavi != NULL)//if email navigator is not pointing to the earliest mail, or if theres only 1 element
- {
- if (eNavi != eHead) //double checking if email navigator hasn't reached the earliest mail yet, if it is, then no need to go even earlier
- {
- eNavi = eNavi->prev; //email navigator approaches eHead by 1 node
- }
- myNavi->next = new UI(myNavi, NULL, eNavi->index, eNavi->sender + "|| " + eNavi->title + " || " + eNavi->day + " . " + eNavi->month + " . " + eNavi->year); //creates a new node to point to
- myNavi = myNavi->next; // navigator switch to the next address that it created
- myTail = myNavi; //assigns tail to newly created UI navigator node
- }
- }
- }
- else //if newest mail has no values, or no mail
- {
- myHead = new UI(NULL, NULL, 0, "nothing to see here");
- myHead->selected = true;
- refreshCache = myHead;
- myTail = myHead;
- }
- while (tempRunFlag)
- {
- system("CLS");
- cout <<
- "\nNow browsing inbox..." << endl <<
- "_____________________________________________________________________________________________________________________" << endl <<
- "SENDER\t\t||\t\t\t\tTITLE\t\t\t\t\t||\tDATE" << endl;
- myNavi = myHead; //UI navigator will be reassigned to point to first UI
- while (myNavi != NULL)
- {
- cout << myNavi->text[(int)myNavi->selected] << endl;
- myNavi = myNavi->next;
- }
- myNavi = refreshCache;//similar implementation in the prompt() function;
- if (myNavi != NULL)
- {
- cout << "\nMenu Function code: " << myNavi->menuFunc << endl;//used for debugging, displays the menuFunc
- }
- cout <<
- "\n\nReached end of inbox" << endl <<
- "_____________________________________________________________________________________________________________________" << endl <<
- "[Use ARROW KEYS UP & DOWN to navigate, ENTER/RETURN to select operation, ESC to return to Main Menu]" << endl;
- system("pause");
- tempKeyPress = getKeyInt();
- switch (tempKeyPress)
- {
- case VK_UP:
- if (myNavi != myHead)
- {
- myNavi->selected = false;
- myNavi = myNavi->prev;
- myNavi->selected = true;
- refreshCache = myNavi;
- }
- break;
- case VK_DOWN:
- if (myNavi != myTail)
- {
- myNavi->selected = false;
- myNavi = myNavi->next;
- myNavi->selected = true;
- refreshCache = myNavi;
- }
- break;
- case VK_RETURN:
- if (eHead->sender != "\0")
- {
- tempRunFlag = prompt(myNavi->text[(int)myNavi->selected], myNavi->menuFunc, eNavi, eHead, eTail, modified); //to determine whether the loop should continue or break after function is called
- }
- break;
- case VK_ESCAPE:
- tempRunFlag = false;
- break;
- default:
- break;
- }
- }
- return;
- }
- void pushMail(Email * &eHead, Email * &eTail, Email * &draft) //used to actually push the mail into the mail linked list
- {
- if (eHead->sender == "\0") //if current head node is empty
- {
- draft->prev = NULL;
- draft->index = eTail->index + 1;
- eHead = draft;
- eTail = eHead;
- }
- else //if head node already has a value
- {
- draft->prev = eTail;
- draft->index = eTail->index + 1;
- eTail->next = draft;
- eTail = draft;
- }
- }
- void composeEmail(Email*& eHead, Email*& eTail) //prompting the user to get data
- {
- Email* draft = new Email;
- system("CLS");
- if (eHead->sender != "\0") ///used to get rid of a \n character in the buffer for no reason, I don't know why it's there, but whats weird is that it only happens once the email linked list already has 1 element inside of it
- {
- cin.ignore();
- }
- do
- {
- cout << "\nPlease type in the sender's name (16 Character Limit)" << endl;
- getline(cin, draft->sender);
- }
- while (draft->sender.length() > 16 || draft->sender.length() <= 0);
- while (draft->sender.length() < 16)
- {
- draft->sender += " ";
- }
- do
- {
- cout << "\nPlease type in the recipient's name (16 Character Limit)" << endl;
- getline(cin, draft->recipient);
- }
- while (draft->recipient.length() > 16 || draft->recipient.length() <= 0);
- //I forgot why I separated day, month and year
- do
- {
- cout << "\nPlease type in the date of the month in numbers (Eg. 02 for 2nd day of the month, 10 for 10th)" << endl;
- cin >> draft->day;
- } while (draft->day.length() != 2);
- do
- {
- cout << "\nPlease type in the month in numbers (Eg. 03 for MARCH, 12 for DECEMBER)" << endl;
- cin >> draft->month;
- } while (draft->month.length() != 2 );
- do
- {
- cout << "\nPlease type in the year (Eg. 2020, 1956, 0126)" << endl;
- cin >> draft->year;
- cin.ignore();
- } while (draft->year.length() != 4);
- do
- {
- cout << "\nPlease type in the email title (72 Character Limit)" << endl;
- getline(cin, draft->title);
- }
- while (draft->title.length() > 68 || draft->title.length() <= 0);
- while (draft->title.length() < 68)
- {
- draft->title += " ";
- }
- cout << "\nPlease type in your email content below: " << endl;
- cout << "(When done, enter a \\ character to complete the email and send it)" << endl;
- getline(cin, draft->content, '\\'); //changed the delimiter to a "\" character so we can type in paragraphs without worry
- cout << "\n\nEmail is sent! Please check inbox." << endl;
- draft->next = NULL;
- pushMail(eHead, eTail, draft);
- system("pause");
- }
- bool terminateSim(bool runFlag) //used to confirm if user wants to quit the email simulator
- {
- system("CLS");
- string temp = "\0";
- cout << "\nAre you sure you want to quit? Any data during this session is NOT stored\n\n Type \"QUIT\" to confirm (CASE SENSITIVE)\n or type anything else to continue session.\n";
- cin >> temp;
- if (temp == "QUIT")
- {
- return !runFlag;
- }
- else
- {
- return runFlag;
- }
- }
- bool mainMenuExecute(int executionCode, bool runFlag, UI* uiNaviIB, UI* uiHeadIB, UI* uiTailIB, Email*& eNavi, Email*& eHead, Email*& eTail) //a hub similar to prompt()
- {
- if (executionCode == 1)
- {
- composeEmail(eHead, eTail);
- return runFlag;
- }
- else if (executionCode == 2)
- {
- displayInbox(uiNaviIB, uiHeadIB, uiTailIB, eNavi, eHead, eTail);
- return runFlag;
- }
- else if (executionCode == 99)
- {
- return terminateSim(runFlag);
- }
- else
- {
- cout << "\nINVALID CODE" << endl;
- return runFlag;
- }
- }
- int main()
- {
- //Main Menu UI
- UI * composer = new UI(NULL, NULL, 1, "Compose an email to yourself"),
- * inboxer = new UI(composer, NULL, 2, "Look through your inbox"),
- * terminator = new UI(inboxer, NULL, 99, "Terminate email simulator");
- composer->next = inboxer;
- inboxer->next = terminator;
- UI * uiHeadMM = composer,
- * uiTailMM = terminator,
- * uiNaviMM = uiHeadMM;
- uiNaviMM->selected = true;
- //Inbox UI
- UI * uiHeadIB = new UI(NULL,NULL,0,"nothing to see here"),
- * uiTailIB = uiHeadIB,
- * uiNaviIB = uiHeadIB;
- uiNaviIB->selected = true;
- //Actual mail stuff
- Email * mHead = myTemplate(),
- * mTail = mHead;
- Email * mNavi = mHead;
- bool simulate = true; ///similar to tempRunFlag
- int keypress;
- while (simulate)
- {
- system("CLS");
- mainMenu(uiNaviMM, uiHeadMM);
- system("pause");
- keypress = getKeyInt();
- switch (keypress)
- {
- case VK_UP:
- if (uiNaviMM->prev != NULL)
- {
- uiNaviMM->selected = false;
- uiNaviMM = uiNaviMM->prev;
- uiNaviMM->selected = true;
- }
- else //used to rotate selection
- {
- uiNaviMM->selected = false;
- uiNaviMM = uiTailMM;
- uiNaviMM->selected = true;
- }
- break;
- case VK_DOWN:
- if (uiNaviMM->next != NULL)
- {
- uiNaviMM->selected = false;
- uiNaviMM = uiNaviMM->next;
- uiNaviMM->selected = true;
- }
- else
- {
- uiNaviMM->selected = false;
- uiNaviMM = uiHeadMM;
- uiNaviMM->selected = true;
- }
- break;
- case VK_RETURN:
- simulate = mainMenuExecute(uiNaviMM->menuFunc, simulate, uiNaviIB, uiHeadIB, uiTailIB, mNavi, mHead, mTail);
- break;
- default:
- break;
- }
- }
- system("CLS");
- cout << "\nThank you for using email simulator, the program will now terminate." << endl;
- system("pause");
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement