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