forked from benkei-kuruma/CodeNext-CSSI-2018-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsmart-contacts.js
501 lines (422 loc) · 17.7 KB
/
smart-contacts.js
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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
// Author: FirstName lastName
/******************************************************************************
constant variables
These are global variables that should stay the same throughout the run of the
program. After being initialized, JavaScript won't let you change them ever
again. Great for when you want to "protect" certain variables from accidental
tampering!
*******************************************************************************/
const READLINE = require("READLINE-sync");
/******************************************************************************
global variables
contacts
Object Array. Each object represents a contact. Contacts have four properties,
and all property values are strings:
-name: The contact's name. Can consist of any characters, spaces, etc.
-number: The contact's 10-digit phone number (as a string).
-email: The contact's email address.
-notes: Any additional text relevant to the contact (e.g., "mobile number")
quit
Boolean. Represents if the program should continue running (true) or
not (false).
*******************************************************************************/
var contacts, quit;
/******************************************************************************
printGreeting()
Prints a simple greeting. Be as creative as you want here. Be sure to include
your name as the author!
*******************************************************************************/
function printGreeting() {
console.log();
console.log("--------------------------------------------------------------");
console.log(" Smart Contacts ");
console.log("--------------------------------------------------------------");
console.log("By: FirstName LastName");
console.log();
}
/******************************************************************************
setupApp()
Initialize global variables as follows:
-contacts initialized as an empty array
-quit initialized as false
*******************************************************************************/
function setup() {
contacts = [];
quit = false;
}
/******************************************************************************
getNameInput()
Continuously ask user to enter a name until a valid name is entered, then
return that name.
Valid names must be at least one character.
*******************************************************************************/
function getNameInput() {
var nameInput = READLINE.question("Name: ").trim();
while(nameInput.length === 0) {
console.log("Please enter at least one character.");
nameInput = READLINE.question("Name: ").trim();
}
return nameInput;
}
/******************************************************************************
checkNumber()
Check if a phone number is valid, according to the following criteria:
-Phone numbers must be exactly 10 digits (no special characters, spaces, etc).
-Phone numbers must have a value greater than 0.
Return true if a phone number is valid, and false otherwise.
Numbers will be passed in as strings, so use parseInt() to change them into
number data types. From there you can perform all checks above.
*******************************************************************************/
function checkNumber(number) {
number = parseInt(number);
if(number < 0) {
return false;
}
var digits = 0;
while(number > 0) {
digits++;
number = parseInt(number / 10);
}
return digits === 10;
}
/******************************************************************************
getNumberInput()
Continuously ask user to enter a phone number until a valid one is entered,
then return it. Use checkNumber() to validate phone numbers.
*******************************************************************************/
function getNumberInput() {
var numberInput = READLINE.question("Phone Number: ").trim();
while(!checkNumber(numberInput)) {
console.log("Please enter a 10-digit phone number (e.g., 1234567890).");
numberInput = READLINE.question("Phone Number: ").trim();
}
return numberInput;
}
/******************************************************************************
checkEmail()
Check if an email address is valid, according to the following criteria:
-Email addresses are optional, so they can be length 0. However, if the
length of an email address is greater than 0, it needs to be validated,
so the criteria below apply.
-Email addresses must contain just one "@" symbol, but not as the first
character.
-Email addresses must end in ".com", ".org", ".net", or ".edu".
Return true if an email address is valid, and false otherwise.
*******************************************************************************/
function checkEmail(email) {
if(email.length === 0) {
return true;
}
var firstAT = email.indexOf("@");
var secondAT = email.indexOf("@", firstAT + 1);
if(firstAT < 1 || secondAT != -1) {
return false;
}
var topLevelDomains = [".com", ".org", ".net", ".edu"];
var lastFourCharacters = email.substring(email.length - 4);
if(topLevelDomains.indexOf(lastFourCharacters) === -1) {
return false;
}
return true;
}
/******************************************************************************
getEmailInput()
Continuously ask user to enter an email address until a valid one is entered,
then return it. Use checkEmail() to validate email addresses.
*******************************************************************************/
function getEmailInput() {
var emailInput = READLINE.question("Email Address (Optional): ").trim();
while(!checkEmail(emailInput)) {
console.log("Please enter a valid email address.");
emailInput = READLINE.question("Email Address (Optional): ").trim();
}
return emailInput;
}
/******************************************************************************
compareContacts()
Compares the names of two contacts, a and b, to determine their alphabetical
order. If a's name comes before b's, return -1. If a's name comes after b's,
return 1. If a's name does not come before or after b's, then they must share
the same name, in which case you should return 0.
To compare strings alphabetically, you can use comparison operators, just as
you would with numbers. For example, "c" < "d" is true, while "c" > "d" is
false.
Note that a and b are passed in as objects, so you should access their name
properties before comparing. Also before comparing, you should convert both
names to lowercase or uppercase. This will make the comparison ignore
capitalization, which is important for comparing strings alphabetically.
*******************************************************************************/
function compareContacts(a, b) {
var nameA = a.name.toLowerCase();
var nameB = b.name.toLowerCase();
if(nameA < nameB) {
return -1;
} else if(nameA > nameB) {
return 1;
} else {
return 0;
}
}
/******************************************************************************
addContact()
Ask user to enter values for a new contact. Then create a contact object
with those values, add the object to the global contacts array, and sort
the array according to the compareContacts() function. Finally, let the user
know that the contact was added successfully.
You should get the user's input for name, number, and email by calling the
getNameInput(), getNumberInput(), and getEmailInput() functions, respectively.
However, notes are optional and don't need to be validated.
Sort the contacts array alphabetically by contact name using this code:
contacts.sort(compareContacts)
*******************************************************************************/
function addContact() {
console.log("Add Contact");
var nameInput = getNameInput();
var numberInput = getNumberInput();
var emailInput = getEmailInput();
var notesInput = READLINE.question("Notes (optional): ").trim();
var contact = {
name:nameInput,
number:numberInput,
email:emailInput,
notes:notesInput
};
contacts.push(contact);
contacts.sort(compareContacts);
console.log();
console.log("Contact added successfully!");
console.log();
}
/******************************************************************************
getContactIndex()
Seach the global contacts array for the first instance of a contact whose
name matches contactName. Return the index of the first matching contact.
If no match is found, return -1.
Be sure to convert both comparison strings to lowercase or uppercase before
comparing, to account for possible capitalization inconsistencies.
*******************************************************************************/
function getContactIndex(contactName) {
for(var i = 0; i < contacts.length; i++) {
if(contacts[i].name.toLowerCase() === contactName.toLowerCase()) {
return i;
}
}
return -1;
}
/******************************************************************************
removeContact()
Attempt to remove a contact from the global contacts array.
Ask the user to enter the contact's name, and search the contacts array for
that contact by name (you have functions for both of these actions).
If the contact isn't in the contact array, let the user know that you couldn't
find it. Otherwise, remove the contact, and let the user know that this was
done successfully.
*******************************************************************************/
function removeContact() {
console.log("Remove Contact");
var contactIndex = getContactIndex(getNameInput());
if(contactIndex != -1) {
contacts.splice(contactIndex, 1);
console.log();
console.log("Contact removed!");
} else {
console.log();
console.log("Can't find that contact.");
}
console.log();
}
/******************************************************************************
displayUpdateMenu()
Display the contact update menu, with the following choices:
1) Name
2) Phone Number
3) Email Address
4) Notes
0) Return to Main Menu
Based on what the user chooses, update the appropriate value for the contact
located at contactIndex. Call the necessary functions to get input for
name, number, and email, while notes do not need any special validation. Also
be sure to allow the user to quit this menu and return to the main menu
by entering "0" (or anything else you want).
Don't forget to re-sort the contacts array if the user updates any contact's
name!
*******************************************************************************/
function displayUpdateMenu(contactIndex) {
console.log("Update " + contacts[contactIndex].name);
console.log("1: Name");
console.log("2: Phone Number");
console.log("3: Email Address");
console.log("4: Notes");
console.log("0: Return to Main Menu")
var choice = READLINE.question("Enter a value: ").trim();
while(!(choice >= 0 && choice <= 4)) {
console.log("Please make a valid choice");
choice = READLINE.question("Enter a value: ").trim();
}
if(choice == 1) {
contacts[contactIndex].name = getNameInput();
contacts.sort(compareContacts);
console.log();
console.log("Contact name updated!");
} else if(choice == 2) {
contacts[contactIndex].number = getNumberInput();
console.log();
console.log("Contact phone number updated!");
} else if(choice == 3) {
contacts[contactIndex].email = getEmailInput();
console.log();
console.log("Contact email address updated!");
} else if(choice == 4) {
contacts[contactIndex].notes = READLINE.question("Notes (optional): ").trim();
console.log();
console.log("Contact notes updated!");
} else if(choice == 0) {
console.log();
console.log("Nothing updated!");
}
}
/******************************************************************************
updateContact()
Ask the user to enter the contact's name, and search the contacts array for
that contact by name (you have functions for both of these actions).
If the contact isn't in the contact array, let the user know that you couldn't
find it. Otherwise, call displayContactMenu() with the contact's index passed
to it as an argument.
*******************************************************************************/
function updateContact() {
console.log("Update Contact");
var contactIndex = getContactIndex(getNameInput());
if(contactIndex != -1) {
console.log();
displayUpdateMenu(contactIndex);
} else {
console.log();
console.log("Can't find that contact.");
}
console.log();
}
/******************************************************************************
printContactInfo()
Print current values for all four properties of a given contact. You'll first
need to get the index of the contact based on contactName, which is passed in
as input.
*******************************************************************************/
function printContactInfo(contactName) {
var contactIndex = getContactIndex(contactName);
console.log("Name: " + contacts[contactIndex].name);
console.log("Phone Number: " + contacts[contactIndex].number);
console.log("Email Address: " + contacts[contactIndex].email);
console.log("Notes: " + contacts[contactIndex].notes);
console.log();
}
/******************************************************************************
searchContact()
Print the info of all contacts whose names start with what the user types in.
Ask the user to enter a name, and search the contacts list for any names that
start with whatever string user typed in. If there are any matches, print them
all. Otherwise let the user know that no matches were found.
For example, let's say there is a contact named "Barack" and another named
"Barry". If the user searches for "ba", both contacts' info should be printed.
*******************************************************************************/
function searchContact() {
console.log("Search Contact");
var contactName = getNameInput();
var matches = [];
for(var i = 0; i < contacts.length; i++) {
if(contacts[i].name.toLowerCase().startsWith(contactName.toLowerCase())) {
matches.push(contacts[i]);
}
}
if(matches.length > 0) {
console.log();
console.log(matches.length + " matches found:");
console.log();
for(var i = 0; i < matches.length; i++) {
printContactInfo(matches[i].name);
}
} else {
console.log();
console.log("No matches found.");
console.log();
}
}
/******************************************************************************
printAllContacts()
Print the info of every contact in the contacts array. You already have a
function that prints the info for one contact, so this should be very
straightforward.
*******************************************************************************/
function printAllContacts() {
console.log("Printing " + contacts.length + " Contact(s):");
console.log();
for(var i = 0; i < contacts.length; i++) {
printContactInfo(contacts[i].name);
}
}
/******************************************************************************
displayMainMenu()
Display the main menu, with the following choices:
1) Add Contact
2) Remove Contact
3) Update Contact
4) Search Contact
5) Print All Contacts
0) Quit
Based on what the user chooses, call the appropriate function. However, if
the user chooses options 2 through 5 and they don't have any contacts, let
them know and do nothing else (no point in wasting their time).
If the user enters "0" (or anything else you want), set quit to true, which
will prevent this function from running again in the run() loop.
*******************************************************************************/
function displayMainMenu() {
console.log("Main Menu");
console.log("1: Add Contact");
console.log("2: Remove Contact");
console.log("3: Update Contact");
console.log("4: Search Contact");
console.log("5: Print All Contacts");
console.log("0: Quit");
var choice = READLINE.question("Enter a value: ").trim();
while(!(choice >= 0 && choice <= 5)) {
console.log("Please make a valid choice.");
choice = READLINE.question("Enter a value: ").trim();
}
console.log();
if(choice >= 2 && choice <= 5 && contacts.length === 0) {
console.log("You have no contacts.");
console.log();
} else if(choice == 1) {
addContact();
} else if(choice == 2) {
removeContact();
} else if(choice == 3) {
updateContact();
} else if(choice == 4) {
searchContact();
} else if(choice == 5) {
printAllContacts();
} else if(choice == 0) {
quit = true;
}
}
/******************************************************************************
run()
This is the "main" function that runs the entire program. Here's what it needs
to do, in order:
1) Print a greeting.
2) Setup global variables.
3) While the global variable quit is set to false, display the main menu in
an endless loop.
4) Outside of the loop, print a goodbye message.
*******************************************************************************/
function run() {
printGreeting();
setup();
while(!quit) {
displayMainMenu();
}
console.log("Goodbye!");
}
// Run the program!
run();
READLINE.question("Press Enter key to exit.");