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}