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.time.LocalDateTime;
010
011/**
012 * This class represents an assignment give to students in The Joy of Coding.
013 *
014 * @author David Whitlock
015 */
016public class Assignment extends NotableImpl {
017
018  public enum AssignmentType {
019    PROJECT,
020    QUIZ,
021    OTHER,
022    POA,
023    OPTIONAL
024  }
025
026
027  public enum ProjectType {
028    APP_CLASSES,
029    TEXT_FILE,
030    PRETTY_PRINT,
031    KOANS,
032    XML,
033    DATABASE,
034    REST,
035    ANDROID
036  }
037
038  private final String name;
039  private String description;
040  private double points;
041  private int canvasId;
042  private AssignmentType type;
043  private LocalDateTime dueDate;
044  private ProjectType projectType;
045
046  /**
047   * Creates a new <code>Assignment</code> with the given name and
048   * point value.
049   */
050  public Assignment(String name, double points) {
051    this.name = name;
052    this.points = points;
053    this.type = AssignmentType.PROJECT;
054    this.setDirty(false);
055  }
056
057  /**
058   * Returns the name of this <code>Assignment</code>
059   */
060  public String getName() {
061    return this.name;
062  }
063
064  /**
065   * Returns the number of points this <code>Assignment</code> is
066   * worth
067   */
068  public double getPoints() {
069    return this.points;
070  }
071
072  /**
073   * Sets the number of points that this <code>Assignment</code> is
074   * worth.
075   */
076  public Assignment setPoints(double points) {
077    this.setDirty(true);
078    this.points = points;
079    return this;
080  }
081
082  /**
083   * Returns a description of this <code>Assignment</code>
084   */
085  public String getDescription() {
086    return this.description;
087  }
088
089  /**
090   * Sets the description of this <code>Assignment</code>
091   */
092  public Assignment setDescription(String description) {
093    this.setDirty(true);
094    this.description = description;
095    return this;
096  }
097
098  /**
099   * Returns the type of this <code>Assignment</code>
100   */
101  public AssignmentType getType() {
102    return this.type;
103  }
104
105  /**
106   * Sets the type of this <code>Assignment</code>
107   */
108  public Assignment setType(AssignmentType type) {
109    this.setDirty(true);
110    this.type = type;
111    return this;
112  }
113
114
115  public Assignment setCanvasId(int canvasId) {
116    this.canvasId = canvasId;
117    this.setDirty(true);
118    return this;
119  }
120
121  public int getCanvasId() {
122    return canvasId;
123  }
124
125
126  /**
127   * Returns a brief textual description of this
128   * <code>Assignment</code>
129   */
130  public String toString() {
131    return "Assignment " + this.getName() + " worth " +
132           this.getPoints();
133  }
134  
135
136  private static PrintWriter err = new PrintWriter(System.err, true);
137
138  /**
139   * Prints usage information about the main program.
140   */
141  private static void usage() {
142    err.println("\njava Assignment [options] -xmlFile xmlFile " +
143                "-name name");
144    err.println("  where [options] are:");
145    err.println("  -points points        Points assignment is worth");
146    err.println("  -description desc     Description of assignment");
147    err.println("  -type type            Type of assignment " +
148                "(PROJECT, QUIZ, or OTHER)");
149    err.println("  -note note            Note about assignment");
150    err.println("\n");
151    System.exit(1);
152  }
153
154  /**
155   * Main program that creates/edits an <code>Assignment</code> in a
156   * grade book stored in an XML file.
157   */
158  public static void main(String[] args) {
159    String fileName = null;
160    String name = null;
161    String points = null;
162    String desc = null;
163    AssignmentType type = null;
164    String note = null;
165
166    // Parse the command line
167    for (int i = 0; i < args.length; i++) {
168      if (args[i].equals("-xmlFile")) {
169        if (++i >= args.length) {
170          err.println("** Missing XML file name");
171          usage();
172        }
173
174        fileName = args[i];
175
176      } else if (args[i].equals("-name")) {
177        if (++i >= args.length) {
178          err.println("** Missing assignment name");
179          usage();
180        }
181
182        name = args[i];
183
184      } else if (args[i].equals("-points")) {
185        if (++i >= args.length) {
186          err.println("** Missing points value");
187          usage();
188        }
189
190        points = args[i];
191
192      } else if (args[i].equals("-description")) {
193        if (++i >= args.length) {
194          err.println("** Missing description");
195          usage();
196        }
197        
198        desc = args[i];
199
200      } else if (args[i].equals("-type")) {
201        if (++i >= args.length) {
202          err.println("** Missing type");
203          usage();
204        }
205
206        // Make sure type is valid
207        switch (args[i]) {
208          case "PROJECT":
209            type = AssignmentType.PROJECT;
210            break;
211          case "QUIZ":
212            type = AssignmentType.QUIZ;
213            break;
214          case "POA":
215            type = AssignmentType.POA;
216            break;
217          case "OTHER":
218            type = AssignmentType.OTHER;
219            break;
220          case "OPTIONAL":
221            type = AssignmentType.OPTIONAL;
222            break;
223          default:
224            err.println("** Invalid type: " + args[i]);
225            usage();
226            break;
227        }
228
229      } else if (args[i].equals("-note")) {
230        if (++i >= args.length) {
231          err.println("** Missing note");
232          usage();
233        }
234
235        note = args[i];
236
237      } else {
238        err.println("** Unknown option: " + args[i]);
239      }
240    }
241
242    // Verify command line
243    if (fileName == null) {
244      err.println("** No file name specified");
245      usage();
246    }
247
248    if (name == null) {
249      err.println("** No assignment name specified");
250      usage();
251    }
252
253    File file = new File(fileName);
254    if (!file.exists()) {
255      err.println("** Grade book file " + fileName + 
256                  " does not exist");
257      System.exit(1);
258    }
259
260    if (name == null) {
261      err.println("** No assignment name specified");
262      usage();
263    }
264
265    GradeBook book = null;
266    try {
267      XmlGradeBookParser parser = new XmlGradeBookParser(file);
268      book = parser.parse();
269
270    } catch (FileNotFoundException ex) {
271      err.println("** Could not find file: " + ex.getMessage());
272      System.exit(1);
273
274    } catch (IOException ex) {
275      err.println("** IOException during parsing: " + ex.getMessage());
276      System.exit(1);
277
278    } catch (ParserException ex) {
279      err.println("** Exception while parsing " + file + ": " + ex);
280      System.exit(1);
281    }
282
283    // Get the assignment
284    Assignment assign = book.getAssignment(name);
285    if (assign == null) {
286      // Did we specify a points value?
287      if (points == null) {
288        err.println("** No points specified");
289        usage();
290      }
291
292      double value = -1.0;
293      try {
294        value = Double.parseDouble(points);
295
296      } catch (NumberFormatException ex) {
297        err.println("** Not a valid point value: " + points);
298        System.exit(1);
299      }
300
301      if (value < 0.0) {
302        err.println("** Not a valid point value: " + value);
303        System.exit(1);
304      }
305
306      // Create a new Assignment
307      assign = new Assignment(name, value);
308      book.addAssignment(assign);
309    }
310
311    // Set the properties of the assignment
312    if (desc != null) {
313      assign.setDescription(desc);
314    }
315
316    if (type != null) {
317      assign.setType(type);
318    }
319
320    if (note != null) {
321      assign.addNote(note);
322    }
323
324    // Write the grade book back out to the XML file
325    try {
326      XmlDumper dumper = new XmlDumper(file);
327      dumper.dump(book);
328
329    } catch (IOException ex) {
330      err.println("** While dumping to " + file + ": " + ex);
331      System.exit(1);
332    }
333  }
334
335  public void setDueDate(LocalDateTime dueDate) {
336    this.dueDate = dueDate;
337  }
338
339  public LocalDateTime getDueDate() {
340    return dueDate;
341  }
342
343  public boolean isSubmissionLate(LocalDateTime submissionTime) {
344    if (this.dueDate == null) {
345      return false;
346
347    } else {
348      return submissionTime.isAfter(this.dueDate);
349    }
350  }
351
352  public Assignment setProjectType(ProjectType projectType) {
353    this.projectType = projectType;
354    return this;
355  }
356
357  public ProjectType getProjectType() {
358    return projectType;
359  }
360
361}