/*
* Get Organized - Organize your schedule, course assignments, and grades
* Copyright © 2012 Alex Laird
* getorganized@alexlaird.com
* alexlaird.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package adl.go.types;
import adl.go.gui.Domain;
import adl.go.resource.LocalUtility;
import adl.go.resource.Utility;
import java.text.ParseException;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Scanner;
/**
* An assignment is owned by a course and can be attached to a type or textbook
* that is also owned by the same course. An assignment can eventually be marked
* as completed, and when it is completed its grade can be accessed. The
* assignment must be attached to a type to properly define its weight in the
* grading process.
*
* @author Alex Laird
*/
public class Assignment extends ExtendedJPanelForAssignment implements ListItem
{
/**
* A reference to the utility is needed for coloring.
*/
private Utility utility;
/**
* A reference to the containing course.
*/
private Course course;
/**
* The textbook this assignment uses.
*/
private Textbook textbook;
/**
* The type this assignment is tied to.
*/
private AssignmentType type;
/**
* The due date for the assignment.
*/
private String dueDate = Domain.DATE_FORMAT.format (new Date ());
/**
* The due hour for the assignment.
*/
private String hr = "12";
/**
* The due minute for the assignment.
*/
private String min = "00";
/**
* The due meridian for the assignment.
*/
private String m = "PM";
/**
* The grade for the assignment.
*/
private String grade = "";
/**
* The comments for the assignment.
*/
private String comments = "";
/**
* The row object for use in the assignmentsAndEvents table.
*/
private Object[] rowObject = new Object[]
{
null, null, null, null, null, null, null
};
/**
* The unique ID of the course this assignment is attached to.
*/
protected long courseID;
/**
* The unique ID for the type of this course.
*/
protected long typeID;
/**
* The unique ID for the textbook of this course.
*/
protected long textbookID;
/**
* The priority of this assignment.
*/
private int priority = 3;
/**
* True if the assignment is completed, false otherwise.
*/
private boolean isDone = false;
/**
* True if an immediate save is needed after application startup.
*/
private boolean immediateSaveNeeded = false;
/**
* Constructs an assignment with a given name, unique ID, and reference to
* its containing course.
*
* @param name The name of the assignment.
* @param id A unique ID not used by any other type in the application.
* @param course A reference to the containing course.
* @param utility A reference to the utility is needed for coloring.
*/
public Assignment(String name, long id, Course course, LocalUtility utility)
{
super (name, id, utility);
setCourse (course);
hr = course.getStartTime (0);
min = course.getStartTime (1);
m = course.getStartTime (2);
this.utility = utility;
refreshRowObject ();
refreshText ();
}
/**
* Parses a single input string into every attribute's initial state for
* this object--this is specifically used by the loading methods from the
* data file.
*
* @param parse The string of all data to be used for initialization.
* @param utility A reference to the utility is needed for coloring.
*/
public Assignment(String parse, LocalUtility utility)
{
super ("", -1, utility);
this.utility = utility;
Scanner scan = new Scanner (parse).useDelimiter ("(?<!\\\\)" + SEPARATOR + "|" + "(?<!\\\\)" + END_OF_LINE);
// throw away the true saying this is an assignment
String throwAway = null;
try
{
throwAway = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
if (throwAway != null && (throwAway.equals ("true") || throwAway.equals ("false")))
{
setItemName (scan.next ().replaceAll ("\\\\" + SEPARATOR, SEPARATOR).replaceAll ("\\\\" + END_OF_LINE, END_OF_LINE));
}
else
{
setItemName (throwAway);
}
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
setUniqueID (scan.nextLong ());
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
courseID = scan.nextLong ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
typeID = scan.nextLong ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
textbookID = scan.nextLong ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
setIsDone (scan.nextBoolean ());
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
dueDate = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
grade = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
comments = scan.next ().replaceAll ("\\\\" + SEPARATOR, SEPARATOR).replaceAll ("\\\\" + END_OF_LINE, END_OF_LINE).replaceAll ("\\\\<br />", LINE_RETURN);
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
priority = scan.nextInt ();
if (priority > 5)
{
priority = (int) Math.round ((double) priority / 20);
}
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
hr = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
if (hr.contains (":"))
{
min = hr.split (":")[1].split (" ")[0];
m = hr.split (":")[1].split (" ")[1];
hr = hr.split (":")[0];
immediateSaveNeeded = true;
}
else
{
try
{
min = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
try
{
m = scan.next ();
}
catch (NoSuchElementException ex)
{
immediateSaveNeeded = true;
}
}
scan.close ();
}
/**
* Check if the assignment needs an immediate save after startup.
*
* @return True if an immediate save is needed, false otherwise.
*/
public boolean needsImmediateSaveNeeded()
{
return immediateSaveNeeded;
}
/**
* Reset the needsImmedateSave flag.
*/
public void resetNeedsImmediateSaveNeeded()
{
immediateSaveNeeded = false;
}
/**
* Retrieves the unique ID of the course this assignment is attached to.
*
* @return The unique ID of this assignment's course.
*/
public long getCourseID()
{
return courseID;
}
/**
* Retrieves the unique ID of the type this assignment is attached to.
*
* @return The unique ID of this assignment's type.
*/
public long getTypeID()
{
return typeID;
}
/**
* Retrieves the unique ID of the textbook this assignment is attached to.
*
* @return The unique ID of this assignmentsAndEvents's textbook.
*/
public long getTextbookID()
{
return textbookID;
}
/**
* Refreshes the text of the component that is shown in Calendar View.
*/
@Override
public final void refreshText()
{
switch (utility.preferences.colorByIndex)
{
// color by due date
case 0:
{
String[] assignmentDate = getDueDate ().split ("/");
String[] currentDate = Domain.DATE_FORMAT.format (new Date ()).split ("/");
try
{
if (!isDone () && ((new Date ()).before (Domain.DATE_FORMAT.parse (getDueDate ()))
|| (Domain.DATE_FORMAT.format (new Date ()).equals (getDueDate ())))
&& (Integer.parseInt (assignmentDate[2]) - Integer.parseInt (currentDate[2]) == 0
&& Integer.parseInt (assignmentDate[0]) - Integer.parseInt (currentDate[0]) == 0))
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 3)
{
getLabel ().setForeground (utility.preferences.dueDateColors[5]);
}
else if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 2)
{
getLabel ().setForeground (utility.preferences.dueDateColors[4]);
}
else
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 1)
{
getLabel ().setForeground (utility.preferences.dueDateColors[3]);
}
else
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 0)
{
getLabel ().setForeground (utility.preferences.dueDateColors[2]);
}
else
{
getLabel ().setForeground (utility.preferences.dueDateColors[0]);
}
}
}
getLabel ().setFont (utility.currentTheme.fontPlain11);
}
else
{
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
getLabel ().setForeground (utility.preferences.dueDateColors[1]);
getLabel ().setFont (utility.currentTheme.fontItalic11);
}
else
{
getLabel ().setForeground (utility.preferences.dueDateColors[6]);
getLabel ().setFont (utility.currentTheme.fontPlain11);
}
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
break;
}
// color by course
case 1:
{
getLabel ().setForeground (getCourse ().getColor ());
try
{
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
getLabel ().setFont (utility.currentTheme.fontItalic11);
}
else
{
getLabel ().setFont (utility.currentTheme.fontPlain11);
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
break;
}
// color by priority
case 2:
{
try
{
switch (priority)
{
case 5:
{
getLabel ().setForeground (utility.preferences.priorityColors[4]);
break;
}
case 4:
{
getLabel ().setForeground (utility.preferences.priorityColors[3]);
break;
}
case 2:
{
getLabel ().setForeground (utility.preferences.priorityColors[1]);
break;
}
case 1:
{
getLabel ().setForeground (utility.preferences.priorityColors[0]);
break;
}
case 3:
default:
{
getLabel ().setForeground (utility.preferences.priorityColors[2]);
break;
}
}
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
getLabel ().setFont (utility.currentTheme.fontItalic11);
}
else
{
getLabel ().setFont (utility.currentTheme.fontPlain11);
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
break;
}
}
if (isDone)
{
getLabel ().setText ("<html><strike>" + getItemName () + "</strike></html>");
}
else
{
getLabel ().setText ("<html>" + getItemName () + "</html>");
}
}
/**
* Refreshes the row object with the values stored in this assignment object
* to ensure they are all correct.
*/
public final void refreshRowObject()
{
rowObject[0] = Boolean.valueOf (isDone);
String openTags = "<html><b>";
String closeTags = "</b></html>";
switch (utility.preferences.colorByIndex)
{
// color by due date
case 0:
{
String[] assignmentDate = getDueDate ().split ("/");
String[] currentDate = Domain.DATE_FORMAT.format (new Date ()).split ("/");
try
{
if (!isDone () && ((new Date ()).before (Domain.DATE_FORMAT.parse (getDueDate ()))
|| (Domain.DATE_FORMAT.format (new Date ()).equals (getDueDate ())))
&& (Integer.parseInt (assignmentDate[2]) - Integer.parseInt (currentDate[2]) == 0
&& Integer.parseInt (assignmentDate[0]) - Integer.parseInt (currentDate[0]) == 0))
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 3)
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[5].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
else if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 2)
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[4].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
else
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 1)
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[3].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
else
{
if (Integer.parseInt (assignmentDate[1]) - Integer.parseInt (currentDate[1]) == 0)
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[2].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
else
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[0].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
}
}
}
else
{
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
openTags += "<em><font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[1].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font></em>" + closeTags;
}
else
{
openTags += "<font color=\"#" + Integer.toHexString (utility.preferences.dueDateColors[6].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeTags;
}
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
if (isDone)
{
openTags += "<strike>";
closeTags = "</strike>" + closeTags;
}
break;
}
// color by course
case 1:
{
String openEmTags = "";
String closeEmTags = "";
try
{
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
openEmTags += "<em>";
closeEmTags += "</em>";
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
String rgb = Integer.toHexString (getCourse ().getColor ().getRGB ());
openTags += openEmTags + "<font color=\"#" + rgb.substring (2, rgb.length ()) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
if (isDone)
{
openTags += "<strike>";
closeTags = "</strike>" + closeTags;
}
break;
}
// color by priority
case 2:
{
String openEmTags = "";
String closeEmTags = "";
try
{
if (!isDone () && (new Date ()).after (Domain.DATE_FORMAT.parse (getDueDate ())))
{
openEmTags += "<em>";
closeEmTags += "</em>";
}
switch (priority)
{
case 5:
{
openTags += openEmTags + "<font color=\"#" + Integer.toHexString (utility.preferences.priorityColors[4].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
break;
}
case 4:
{
openTags += openEmTags + "<font color=\"#" + Integer.toHexString (utility.preferences.priorityColors[3].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
break;
}
case 2:
{
openTags += openEmTags + "<font color=\"#" + Integer.toHexString (utility.preferences.priorityColors[1].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
break;
}
case 1:
{
openTags += openEmTags + "<font color=\"#" + Integer.toHexString (utility.preferences.priorityColors[0].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
break;
}
case 3:
default:
{
openTags += openEmTags + "<font color=\"#" + Integer.toHexString (utility.preferences.priorityColors[2].getRGB () & 0x00FFFFFF) + "\">";
closeTags = "</font>" + closeEmTags + closeTags;
break;
}
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
if (isDone)
{
openTags += "<strike>";
closeTags = "</strike>" + closeTags;
}
break;
}
}
rowObject[1] = openTags + getItemName () + closeTags;
if (getType () != null)
{
rowObject[2] = getType ().getTypeName ();
}
else
{
rowObject[2] = "";
}
rowObject[3] = getCourse ().getTypeName ();
rowObject[4] = getDueDate ();
if (isDone ())
{
rowObject[5] = getGrade ();
}
else
{
rowObject[5] = "";
}
rowObject[6] = getUniqueID ();
}
/**
* Retrieves the row object for use in the assignmentsAndEvents table.
*
* @return The row object.
*/
@Override
public Object[] getRowObject()
{
refreshRowObject ();
return rowObject;
}
/**
* Check if the assigment is completed or not.
*
* @return True if the assignment is done, false otherwise.
*/
public boolean isDone()
{
return isDone;
}
/**
* Checks if the assignment is overdue or not.
*
* @return True if the assignment is overdue, false otherwise.
*/
public boolean isOverdue()
{
boolean overdue = false;
try
{
if (!isDone
&& Domain.DATE_FORMAT.parse (dueDate).before (utility.domain.today))
{
overdue = true;
}
}
catch (ParseException ex)
{
Domain.LOGGER.add (ex);
}
return overdue;
}
/**
* Returns the due time in h:mm a format.
*
* @return The due time string.
*/
public String getDueTime()
{
return hr + ":" + min + " " + m;
}
/**
* Retrieves the due time of the assignment.
*
* @param index 0 will return the hr, 1 will return the minute, 2 will
* return the meridian.
* @return The hour, minute, or meridian of the assignment.
*/
public String getDueTime(int index)
{
String time = "";
switch (index)
{
case 0:
{
time = hr;
break;
}
case 1:
{
time = min;
break;
}
case 2:
{
time = m;
break;
}
}
return time;
}
/**
* Sets the due time of the assignment.
*
* @param index 0 is hours, 1 is minutes, 2 is meridian
* @param time The due time to be set.
*/
public void setDueTime(int index, String time)
{
switch (index)
{
case 0:
{
hr = time;
break;
}
case 1:
{
min = time;
break;
}
case 2:
{
m = time;
break;
}
}
}
/**
* Set the done state of this assignment to completed or non-completed.
*
* @param isDone True if the assignment should be set to done, false if it
* should be set to not done.
*/
public final void setIsDone(boolean isDone)
{
this.isDone = isDone;
getCheckBox ().setSelected (isDone);
}
/**
* Retrieve the reference to the containing course.
*
* @return The containing course.
*/
public Course getCourse()
{
return course;
}
/**
* Set the reference to the containing course.
*
* @param course The containing course.
*/
public final void setCourse(Course course)
{
this.course = course;
}
/**
* Retrieve the due date.
*
* @return The due date.
*/
@Override
public String getDueDate()
{
return dueDate;
}
/**
* Set the due date.
*
* @param dueDate The due date to be set.
*/
public void setDueDate(String dueDate)
{
this.dueDate = dueDate;
}
/**
* Retrieve the grade.
*
* @return The grade.
*/
public String getGrade()
{
return grade;
}
/**
* Set the grade.
*
* @param grade The grade to be set.
*/
public void setGrade(String grade)
{
this.grade = grade;
}
/**
* Retrieves the comments.
*
* @return The comments for this assignment.
*/
public String getComments()
{
return comments;
}
/**
* Sets the comments for this assignment.
*
* @param comment The comments to be set.
*/
public void setComments(String comment)
{
this.comments = comment;
}
/**
* Retrieves the priority of this assignment.
*
* @return The priority of the assignment.
*/
public int getPriority()
{
return priority;
}
/**
* Sets the priority of the assignment.
*
* @param priority The priority to be set.
*/
public void setPriority(int priority)
{
this.priority = priority;
}
/**
* Retrieves the textbook object for this assignment.
*
* @return The textbook for this assignment.
*/
public Textbook getTextbook()
{
return textbook;
}
/**
* Sets the textbook of this assignment to the passed in textbook object.
*
* @param textbook The textbook to be set.
*/
public void setTextbook(Textbook textbook)
{
this.textbook = textbook;
}
/**
* Retrieves the type of this assignment.
*
* @return The type of this assignment.
*/
public AssignmentType getType()
{
return type;
}
/**
* Sets the type of this assignment to the passed in type object.
*
* @param type The type to be set.
*/
public void setType(AssignmentType type)
{
this.type = type;
}
/**
* Always returns true, because this is an assignment type.
*
* @return True because this is an assignment.
*/
@Override
public boolean isAssignment()
{
return true;
}
/**
* Returns a string of all components in this object that is formatted that
* the file reader/writer will cooperate with it.
*
* @return The formatted output string.
*/
@Override
public String out()
{
String typeSeg = "-1";
if (type != null)
{
typeSeg = type.getUniqueID () + "";
}
String textbookSeg = "-1";
if (textbook != null)
{
textbookSeg = textbook.getUniqueID () + "";
}
return isAssignment () + SEPARATOR
+ getItemName ().replaceAll (SEPARATOR, "\\\\" + SEPARATOR).replaceAll (END_OF_LINE, "\\\\" + END_OF_LINE) + SEPARATOR
+ getUniqueID () + SEPARATOR
+ getCourse ().getUniqueID () + SEPARATOR
+ typeSeg + SEPARATOR
+ textbookSeg + SEPARATOR
+ isDone + SEPARATOR
+ dueDate + SEPARATOR
+ grade + SEPARATOR
+ comments.replaceAll (SEPARATOR, "\\\\" + SEPARATOR).replaceAll (END_OF_LINE, "\\\\" + END_OF_LINE).replaceAll (LINE_RETURN, "\\\\<br />") + SEPARATOR
+ priority + SEPARATOR
+ hr + SEPARATOR
+ min + SEPARATOR
+ m;
}
}