001package edu.pdx.cs410J.grader.gradebook; 002 003import edu.pdx.cs410J.ParserException; 004 005import java.io.File; 006import java.io.FileNotFoundException; 007import java.io.IOException; 008import java.io.PrintWriter; 009import java.util.*; 010 011/** 012 * This class represents a student who is taking CS410J. 013 */ 014public class Student extends NotableImpl { 015 016 private String id; 017 private String firstName; 018 private String lastName; 019 private String nickName; 020 private String email; 021 private String major; 022 private LetterGrade letterGrade; 023 024 /** Maps name of Assignment to Grade. The grades are sorted so that 025 * they will appear in a canonical order in the student's XML 026 * file. */ 027 private SortedMap<String, Grade> grades; 028 029 private List<String> late; // Names of late Assignments 030 private List<String> resubmitted; // Names of resubmitted Assignments 031 private String canvasId; 032 private Section enrolledSection; 033 034 /////////////////////// Constructors /////////////////////// 035 036 /** 037 * Creates a new <code>Student</code> with a given id. An example 038 * of an id is the student's UNIX login name. 039 */ 040 public Student(String id) { 041 this.id = id; 042 this.grades = new TreeMap<>(); 043 this.late = new ArrayList<>(); 044 this.resubmitted = new ArrayList<>(); 045 } 046 047 /////////////////////// Instance Methods /////////////////////// 048 049 /** 050 * Returns the id of this <code>Student</code> 051 */ 052 public String getId() { 053 return this.id; 054 } 055 056 /** 057 * Returns the first name of this <code>Student</code> 058 */ 059 public String getFirstName() { 060 return this.firstName; 061 } 062 063 /** 064 * Returns the last name of this <code>Student</code> 065 */ 066 public Student setFirstName(String firstName) { 067 this.setDirty(true); 068 this.firstName = firstName; 069 return this; 070 } 071 072 /** 073 * Returns the last name of this <code>Student</code> 074 */ 075 public String getLastName() { 076 return this.lastName; 077 } 078 079 /** 080 * Returns the last name of this <code>Student</code> 081 */ 082 public Student setLastName(String lastName) { 083 this.setDirty(true); 084 this.lastName = lastName; 085 return this; 086 } 087 088 /** 089 * Returns the nick name of this <code>Student</code> 090 */ 091 public String getNickName() { 092 return this.nickName; 093 } 094 095 /** 096 * Returns the nick name of this <code>Student</code> 097 */ 098 public void setNickName(String nickName) { 099 this.setDirty(true); 100 this.nickName = nickName; 101 } 102 103 /** 104 * Returns this <code>Student</code>'s full name including first, 105 * last, and nick names. 106 */ 107 public String getFullName() { 108 StringBuilder sb = new StringBuilder(); 109 if (this.firstName != null) { 110 sb.append(this.firstName); 111 } 112 113 if (this.nickName != null) { 114 sb.append(" \"").append(this.nickName).append("\""); 115 } 116 117 if (this.lastName != null) { 118 sb.append(" ").append(this.lastName); 119 } 120 121 return sb.toString().trim(); 122 } 123 124 /** 125 * Returns the email address of this <code>Student</code> 126 */ 127 public String getEmail() { 128 return this.email; 129 } 130 131 /** 132 * Sets the email address of this <code>Student</code> 133 */ 134 public Student setEmail(String email) { 135 this.setDirty(true); 136 this.email = email; 137 return this; 138 } 139 140 /** 141 * Returns the major of this <code>Student</code> 142 */ 143 public String getMajor() { 144 return this.major; 145 } 146 147 /** 148 * Sets the major of this <code>Student</code> 149 */ 150 public void setMajor(String major) { 151 this.setDirty(true); 152 this.major = major; 153 } 154 155 /** 156 * Returns the names of the assignments for which this 157 * <code>Student</code> has received a <code>Grade</code>. 158 */ 159 public Set<String> getGradeNames() { 160 return this.grades.keySet(); 161 } 162 163 /** 164 * Returns the <code>Grade</code> a student received on an 165 * assignment of a given name. If the student has no grade for that 166 * assignment, <code>null</code> is returned. 167 */ 168 public Grade getGrade(String assignmentName) { 169 return this.grades.get(assignmentName); 170 } 171 172 /** 173 * Sets a <code>Grade</code> a student received on an assignment of 174 * a given name. 175 */ 176 public void setGrade(String assignmentName, Grade grade) { 177 this.setDirty(true); 178 this.grades.put(assignmentName, grade); 179 } 180 181 /** 182 * Returns the names of all of the assignments that are late. 183 */ 184 public List<String> getLate() { 185 return this.late; 186 } 187 188 /** 189 * Makes note of the name of an assignment that is late 190 */ 191 public void addLate(String assignmentName) { 192 this.setDirty(true); 193 this.late.add(assignmentName); 194 } 195 196 /** 197 * Returns the names of all of the assignments that are resubmitted. 198 */ 199 public List<String> getResubmitted() { 200 return this.resubmitted; 201 } 202 203 /** 204 * Makes note of the name of an assignment that is resubmitted 205 */ 206 public void addResubmitted(String assignmentName) { 207 this.setDirty(true); 208 this.resubmitted.add(assignmentName); 209 } 210 211 /** 212 * Marks this <code>Student</code> as being clean 213 */ 214 @Override 215 public void makeClean() { 216 super.makeClean(); 217 218 // Make all Grades clean 219 this.grades.values().forEach(Grade::makeClean); 220 } 221 222 /** 223 * If any of its grades is dirty, then the student is dirty 224 */ 225 @Override 226 public boolean isDirty() { 227 if (super.isDirty()) { 228 return true; 229 230 } else { 231 for (Grade grade : this.grades.values()) { 232 if (grade.isDirty()) { 233 return true; 234 } 235 } 236 237 return false; 238 } 239 } 240 241 /** 242 * Returns a complete textual description of this 243 * <code>Student</code>. 244 */ 245 String getDescription() { 246 Student student = this; 247 248 StringBuilder sb = new StringBuilder(); 249 sb.append(student.getId()).append(": "); 250 sb.append(student.getFullName()); 251 252 String email = student.getEmail(); 253 if (email != null && !email.equals("")) { 254 sb.append(", ").append(email); 255 } 256 257 String major = student.getMajor(); 258 if (major != null && !major.equals("")) { 259 sb.append(", ").append(major); 260 } 261 262 for (Object note : this.getNotes()) { 263 sb.append(", \"").append(note).append("\""); 264 } 265 266 return sb.toString(); 267 } 268 269 /////////////////////// Utility Methods /////////////////////// 270 271 /** 272 * Two <code>Student</code>s are equal if they have the same id 273 */ 274 public boolean equals(Object o) { 275 return o instanceof Student && this.getId().equals(((Student) o).getId()); 276 } 277 278 /** 279 * Two students that are equal must have the same hash code 280 */ 281 public int hashCode() { 282 return this.getId().hashCode(); 283 } 284 285 /** 286 * Returns a brief textual description of this <code>Student</code> 287 */ 288 public String toString() { 289 return this.getId() + " (" + this.getFullName() + ")"; 290 } 291 292 /////////////////////// Main Program /////////////////////// 293 294 private static PrintWriter err = new PrintWriter(System.err, true); 295 296 /** 297 * Prints usage information about the main program 298 */ 299 private static void usage() { 300 err.println("\nusage: java Student -id id -file xmlFile [options]"); 301 err.println(" where [options] are:"); 302 err.println(" -firstName firstName Student's first name"); 303 err.println(" -lastName lastName Student's last name"); 304 err.println(" -nickName nickName Student's nick name"); 305 err.println(" -email email Student's email address"); 306 err.println(" -ssn SSN Student's social security" 307 + " number"); 308 err.println(" -major major Student's major"); 309 err.println(" -note note A note about the student"); 310 err.println("\n"); 311 System.exit(1); 312 } 313 314 /** 315 * Main program that is used to add a <code>Student</code> to a 316 * grade book. 317 */ 318 public static void main(String[] args) { 319 String id = null; 320 String xmlFile = null; 321 String firstName = null; 322 String lastName = null; 323 String nickName = null; 324 String email = null; 325 String ssn = null; 326 String major = null; 327 String note = null; 328 329 // Parse the command line 330 for (int i = 0; i < args.length; i++) { 331 if (args[i].equals("-id")) { 332 if (++i >= args.length) { 333 err.println("** Missing id"); 334 usage(); 335 } 336 337 id = args[i]; 338 339 } else if (args[i].equals("-xmlFile") || args[i].equals("-file")) { 340 if (++i >= args.length) { 341 err.println("** Missing xml file name"); 342 usage(); 343 } 344 345 xmlFile = args[i]; 346 347 } else if (args[i].equals("-firstName")) { 348 if (++i >= args.length) { 349 err.println("** Missing first name"); 350 usage(); 351 } 352 353 firstName = args[i]; 354 355 } else if (args[i].equals("-lastName")) { 356 if (++i >= args.length) { 357 err.println("** Missing last name"); 358 usage(); 359 } 360 361 lastName = args[i]; 362 363 } else if (args[i].equals("-nickName")) { 364 if (++i >= args.length) { 365 err.println("** Missing nick name"); 366 usage(); 367 } 368 369 nickName = args[i]; 370 371 } else if (args[i].equals("-email")) { 372 if (++i >= args.length) { 373 err.println("** Missing email address"); 374 usage(); 375 } 376 377 email = args[i]; 378 379 } else if (args[i].equals("-ssn")) { 380 if (++i >= args.length) { 381 err.println("** Missing social security number"); 382 usage(); 383 } 384 385 ssn = args[i]; 386 387 } else if (args[i].equals("-major")) { 388 if (++i >= args.length) { 389 err.println("** Missing major"); 390 usage(); 391 } 392 393 major = args[i]; 394 395 } else if (args[i].equals("-note")) { 396 if (++i >= args.length) { 397 err.println("** Missing text of note"); 398 usage(); 399 } 400 401 note = args[i]; 402 403 } else if (args[i].startsWith("-")) { 404 err.println("** Unknown option: " + args[i]); 405 usage(); 406 407 } else { 408 err.println("** Spurious command line: " + args[i]); 409 usage(); 410 } 411 } 412 413 // Check to make sure that command line was entered correctly 414 if (id == null) { 415 err.println("** No id specified"); 416 usage(); 417 } 418 419 if (xmlFile == null) { 420 err.println("** No XML file specified"); 421 usage(); 422 } 423 424 // Parse the XML file to get a GradeBook 425 File file = new File(xmlFile); 426 if (!file.exists()) { 427 err.println("** Grade book file " + xmlFile + 428 " does not exist"); 429 System.exit(1); 430 } 431 432 GradeBook book = null; 433 try { 434 XmlGradeBookParser parser = new XmlGradeBookParser(file); 435 book = parser.parse(); 436 437 } catch (FileNotFoundException ex) { 438 err.println("** Could not find file: " + ex.getMessage()); 439 System.exit(1); 440 441 } catch (IOException ex) { 442 err.println("** IOException during parsing: " + ex.getMessage()); 443 System.exit(1); 444 445 } catch (ParserException ex) { 446 err.println("** Exception while parsing " + file + ": " + ex); 447 System.exit(1); 448 } 449 450 // Get the Student 451 Student student = book.getStudent(id).get(); 452 453 if (firstName != null) { 454 student.setFirstName(firstName); 455 } 456 457 if (lastName != null) { 458 student.setLastName(lastName); 459 } 460 461 if (nickName != null) { 462 student.setNickName(nickName); 463 } 464 465 if (email != null) { 466 student.setEmail(email); 467 } 468 469 if (major != null) { 470 student.setMajor(major); 471 } 472 473 if (note != null) { 474 student.addNote(note); 475 } 476 477 // Write the changes back out to the XML file 478 try { 479 XmlDumper dumper = new XmlDumper(file); 480 dumper.dump(book); 481 482 } catch (IOException ex) { 483 err.println("** While dumping to " + file + ": " + ex); 484 System.exit(1); 485 } 486 } 487 488 public Grade getGrade(Assignment project) { 489 return this.getGrade(project.getName()); 490 } 491 492 public Student setCanvasId(String canvasId) { 493 this.setDirty(true); 494 this.canvasId = canvasId; 495 return this; 496 } 497 498 public String getCanvasId() { 499 return canvasId; 500 } 501 502 public LetterGrade getLetterGrade() { 503 return letterGrade; 504 } 505 506 public void setLetterGrade(LetterGrade letterGrade) { 507 this.setDirty(true); 508 this.letterGrade = letterGrade; 509 } 510 511 public Student setGrade(Assignment assignment, Grade grade) { 512 setGrade(assignment.getName(), grade); 513 return this; 514 } 515 516 public void addLate(Assignment assignment) { 517 this.addLate(assignment.getName()); 518 } 519 520 public Student setGrade(Assignment assignment, double score) { 521 this.setGrade(assignment, new Grade(assignment, score)); 522 return this; 523 } 524 525 public Student setEnrolledSection(Section enrolledSection) { 526 this.enrolledSection = enrolledSection; 527 return this; 528 } 529 530 public Section getEnrolledSection() { 531 return enrolledSection; 532 } 533 534 public enum Section { 535 UNDERGRADUATE("undergraduate"), GRADUATE("graduate"); 536 537 private final String stringValue; 538 539 Section(String stringValue) { 540 this.stringValue = stringValue; 541 } 542 543 public static Section fromString(String string) { 544 for (Section section : values()) { 545 if (section.asString().equals(string)) { 546 return section; 547 } 548 } 549 550 throw new IllegalArgumentException("Could not find LetterGrade for string \"" + string + "\""); 551 } 552 553 public String asString() { 554 return stringValue; 555 } 556 557 public String toString() { 558 return asString(); 559 } 560 561 } 562}