All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.mpxj.Task Maven / Gradle / Ivy

Go to download

Library that provides facilities to allow project information to be manipulated in Java and .Net. Supports a range of data formats: Microsoft Project Exchange (MPX), Microsoft Project (MPP,MPT), Microsoft Project Data Interchange (MSPDI XML), Microsoft Project Database (MPD), Planner (XML), Primavera (PM XML, XER, and database), Asta Powerproject (PP, MDB), Asta Easyplan (PP), Phoenix Project Manager (PPX), FastTrack Schedule (FTS), and the Standard Data Exchange Format (SDEF).

There is a newer version: 13.8.0
Show newest version
/*
 * file:       Task.java
 * author:     Scott Melville
 *             Jon Iles
 * copyright:  (c) Packwood Software 2002-2003
 * date:       15/08/2002
 */

/*
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library 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 Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

package net.sf.mpxj;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import net.sf.mpxj.common.BooleanHelper;
import net.sf.mpxj.common.DateHelper;
import net.sf.mpxj.common.NumberHelper;
import net.sf.mpxj.common.TaskFieldLists;
import net.sf.mpxj.listener.FieldListener;

/**
 * This class represents a task record from an project file.
 */
public final class Task extends ProjectEntity implements Comparable, ProjectEntityWithID, FieldContainer, ChildTaskContainer
{
   /**
    * Default constructor.
    *
    * @param file Parent file to which this record belongs.
    * @param parent Parent task
    */
   Task(ProjectFile file, Task parent)
   {
      super(file);

      setType(TaskType.FIXED_UNITS);
      setConstraintType(ConstraintType.AS_SOON_AS_POSSIBLE);
      setTaskMode(TaskMode.AUTO_SCHEDULED);
      setActive(true);
      set(TaskField.PREDECESSORS, new ArrayList());
      set(TaskField.SUCCESSORS, new ArrayList());

      m_parent = parent;
      ProjectConfig config = file.getProjectConfig();

      if (config.getAutoTaskUniqueID() == true)
      {
         setUniqueID(Integer.valueOf(config.getNextTaskUniqueID()));
      }

      if (config.getAutoTaskID() == true)
      {
         setID(Integer.valueOf(config.getNextTaskID()));
      }

      if (config.getAutoWBS() == true)
      {
         generateWBS(parent);
      }

      if (config.getAutoOutlineNumber() == true)
      {
         generateOutlineNumber(parent);
      }

      if (config.getAutoOutlineLevel() == true)
      {
         if (parent == null)
         {
            setOutlineLevel(Integer.valueOf(1));
         }
         else
         {
            setOutlineLevel(Integer.valueOf(NumberHelper.getInt(parent.getOutlineLevel()) + 1));
         }
      }
   }

   /**
    * This method is used to automatically generate a value
    * for the WBS field of this task.
    *
    * @param parent Parent Task
    */
   public void generateWBS(Task parent)
   {
      String wbs;

      if (parent == null)
      {
         if (NumberHelper.getInt(getUniqueID()) == 0)
         {
            wbs = "0";
         }
         else
         {
            wbs = Integer.toString(getParentFile().getChildTasks().size() + 1);
         }
      }
      else
      {
         wbs = parent.getWBS();

         //
         // Apparently I added the next lines to support MPX files generated by Artemis, back in 2005
         // Unfortunately I have no test data which exercises this code, and it now breaks
         // otherwise valid WBS values read (in this case) from XER files. So it's commented out
         // until someone complains about their 2005-era Artemis MPX files not working!
         //
         //         int index = wbs.lastIndexOf(".0");
         //         if (index != -1)
         //         {
         //            wbs = wbs.substring(0, index);
         //         }

         int childTaskCount = parent.getChildTasks().size() + 1;
         if (wbs.equals("0"))
         {
            wbs = Integer.toString(childTaskCount);
         }
         else
         {
            wbs += ("." + childTaskCount);
         }
      }

      setWBS(wbs);
   }

   /**
    * This method is used to automatically generate a value
    * for the Outline Number field of this task.
    *
    * @param parent Parent Task
    */
   public void generateOutlineNumber(Task parent)
   {
      String outline;

      if (parent == null)
      {
         if (NumberHelper.getInt(getUniqueID()) == 0)
         {
            outline = "0";
         }
         else
         {
            outline = Integer.toString(getParentFile().getChildTasks().size() + 1);
         }
      }
      else
      {
         outline = parent.getOutlineNumber();

         int index = outline.lastIndexOf(".0");

         if (index != -1)
         {
            outline = outline.substring(0, index);
         }

         int childTaskCount = parent.getChildTasks().size() + 1;
         if (outline.equals("0"))
         {
            outline = Integer.toString(childTaskCount);
         }
         else
         {
            outline += ("." + childTaskCount);
         }
      }

      setOutlineNumber(outline);
   }

   /**
    * This method is used to add notes to the current task.
    *
    * @param notes notes to be added
    */
   public void setNotes(String notes)
   {
      set(TaskField.NOTES, notes);
   }

   /**
    * This method allows nested tasks to be added, with the WBS being
    * completed automatically.
    *
    * @return new task
    */
   @Override public Task addTask()
   {
      ProjectFile parent = getParentFile();

      Task task = new Task(parent, this);

      m_children.add(task);

      parent.getTasks().add(task);

      setSummary(true);

      return (task);
   }

   /**
    * This method is used to associate a child task with the current
    * task instance. It has package access, and has been designed to
    * allow the hierarchical outline structure of tasks in an MPX
    * file to be constructed as the file is read in.
    *
    * @param child Child task.
    * @param childOutlineLevel Outline level of the child task.
    */
   public void addChildTask(Task child, int childOutlineLevel)
   {
      int outlineLevel = NumberHelper.getInt(getOutlineLevel());

      if ((outlineLevel + 1) == childOutlineLevel)
      {
         m_children.add(child);
         setSummary(true);
      }
      else
      {
         if (m_children.isEmpty() == false)
         {
            (m_children.get(m_children.size() - 1)).addChildTask(child, childOutlineLevel);
         }
      }
   }

   /**
    * This method is used to associate a child task with the current
    * task instance. It has been designed to
    * allow the hierarchical outline structure of tasks in an MPX
    * file to be updated once all of the task data has been read.
    *
    * @param child child task
    */
   public void addChildTask(Task child)
   {
      child.m_parent = this;
      m_children.add(child);
      setSummary(true);

      if (getParentFile().getProjectConfig().getAutoOutlineLevel() == true)
      {
         child.setOutlineLevel(Integer.valueOf(NumberHelper.getInt(getOutlineLevel()) + 1));
      }
   }

   /**
    * Inserts a child task prior to a given sibling task.
    *
    * @param child new child task
    * @param previousSibling sibling task
    */
   public void addChildTaskBefore(Task child, Task previousSibling)
   {
      int index = m_children.indexOf(previousSibling);
      if (index == -1)
      {
         m_children.add(child);
      }
      else
      {
         m_children.add(index, child);
      }

      child.m_parent = this;
      setSummary(true);

      if (getParentFile().getProjectConfig().getAutoOutlineLevel() == true)
      {
         child.setOutlineLevel(Integer.valueOf(NumberHelper.getInt(getOutlineLevel()) + 1));
      }
   }

   /**
    * Removes a child task.
    *
    * @param child child task instance
    */
   public void removeChildTask(Task child)
   {
      if (m_children.remove(child))
      {
         child.m_parent = null;
      }
      setSummary(!m_children.isEmpty());
   }

   /**
    * This method allows the list of child tasks to be cleared in preparation
    * for the hierarchical task structure to be built.
    */
   public void clearChildTasks()
   {
      // Only take action if the child list is populated. This ensures that
      // the summary flag value is preserved. This is important when identifying
      // WBS entries which have no child activities.
      if (!m_children.isEmpty())
      {
         m_children.clear();
         setSummary(false);
      }
   }

   /**
    * This method allows recurring task details to be added to the
    * current task.
    *
    * @return RecurringTask object
    */
   public RecurringTask addRecurringTask()
   {
      if (m_recurringTask == null)
      {
         m_recurringTask = new RecurringTask();
      }

      return (m_recurringTask);
   }

   /**
    * This method retrieves the recurring task record. If the current
    * task is not a recurring task, then this method will return null.
    *
    * @return Recurring task record.
    */
   public RecurringTask getRecurringTask()
   {
      return (m_recurringTask);
   }

   /**
    * Retrieve the activity codes associated with this task.
    *
    * @return list of activity codes
    */
   public List getActivityCodes()
   {
      return m_activityCodes;
   }

   /**
    * Assign an activity code to this task.
    *
    * @param value activity coe value
    */
   public void addActivityCode(ActivityCodeValue value)
   {
      m_activityCodes.add(value);
   }

   /**
    * This method allows a resource assignment to be added to the
    * current task.
    *
    * @param resource the resource to assign
    * @return ResourceAssignment object
    */
   public ResourceAssignment addResourceAssignment(Resource resource)
   {
      ResourceAssignment assignment = getExistingResourceAssignment(resource);

      if (assignment == null)
      {
         assignment = new ResourceAssignment(getParentFile(), this);
         m_assignments.add(assignment);
         getParentFile().getResourceAssignments().add(assignment);

         assignment.setTaskUniqueID(getUniqueID());
         assignment.setWork(getDuration());
         assignment.setUnits(ResourceAssignment.DEFAULT_UNITS);

         if (resource != null)
         {
            assignment.setResourceUniqueID(resource.getUniqueID());
            resource.addResourceAssignment(assignment);
         }
      }

      return (assignment);
   }

   /**
    * Add a resource assignment which has been populated elsewhere.
    *
    * @param assignment resource assignment
    */
   public void addResourceAssignment(ResourceAssignment assignment)
   {
      if (getExistingResourceAssignment(assignment.getResource()) == null)
      {
         m_assignments.add(assignment);
         getParentFile().getResourceAssignments().add(assignment);

         Resource resource = assignment.getResource();
         if (resource != null)
         {
            resource.addResourceAssignment(assignment);
         }
      }
   }

   /**
    * Retrieves an existing resource assignment if one is present,
    * to prevent duplicate resource assignments being added.
    *
    * @param resource resource to test for
    * @return existing resource assignment
    */
   private ResourceAssignment getExistingResourceAssignment(Resource resource)
   {
      ResourceAssignment assignment = null;
      Integer resourceUniqueID = null;

      if (resource != null)
      {
         Iterator iter = m_assignments.iterator();
         resourceUniqueID = resource.getUniqueID();

         while (iter.hasNext() == true)
         {
            assignment = iter.next();
            Integer uniqueID = assignment.getResourceUniqueID();
            if (uniqueID != null && uniqueID.equals(resourceUniqueID) == true)
            {
               break;
            }
            assignment = null;
         }
      }

      return assignment;
   }

   /**
    * This method allows the list of resource assignments for this
    * task to be retrieved.
    *
    * @return list of resource assignments
    */
   public List getResourceAssignments()
   {
      return (m_assignments);
   }

   /**
    * Internal method used as part of the process of removing a
    * resource assignment.
    *
    * @param assignment resource assignment to be removed
    */
   void removeResourceAssignment(ResourceAssignment assignment)
   {
      m_assignments.remove(assignment);
   }

   /**
    * This method allows a predecessor relationship to be added to this
    * task instance.
    *
    * @param targetTask the predecessor task
    * @param type relation type
    * @param lag relation lag
    * @return relationship
    */
   @SuppressWarnings("unchecked") public Relation addPredecessor(Task targetTask, RelationType type, Duration lag)
   {
      //
      // Ensure that we have a valid lag duration
      //
      if (lag == null)
      {
         lag = Duration.getInstance(0, TimeUnit.DAYS);
      }

      //
      // Retrieve the list of predecessors
      //
      List predecessorList = (List) getCachedValue(TaskField.PREDECESSORS);

      //
      // Ensure that there is only one predecessor relationship between
      // these two tasks.
      //
      Relation predecessorRelation = null;
      Iterator iter = predecessorList.iterator();
      while (iter.hasNext() == true)
      {
         predecessorRelation = iter.next();
         if (predecessorRelation.getTargetTask() == targetTask)
         {
            if (predecessorRelation.getType() != type || predecessorRelation.getLag().compareTo(lag) != 0)
            {
               predecessorRelation = null;
            }
            break;
         }
         predecessorRelation = null;
      }

      //
      // If necessary, create a new predecessor relationship
      //
      if (predecessorRelation == null)
      {
         predecessorRelation = new Relation(this, targetTask, type, lag);
         predecessorList.add(predecessorRelation);
      }

      //
      // Retrieve the list of successors
      //
      List successorList = (List) targetTask.getCachedValue(TaskField.SUCCESSORS);

      //
      // Ensure that there is only one successor relationship between
      // these two tasks.
      //
      Relation successorRelation = null;
      iter = successorList.iterator();
      while (iter.hasNext() == true)
      {
         successorRelation = iter.next();
         if (successorRelation.getTargetTask() == this)
         {
            if (successorRelation.getType() != type || successorRelation.getLag().compareTo(lag) != 0)
            {
               successorRelation = null;
            }
            break;
         }
         successorRelation = null;
      }

      //
      // If necessary, create a new successor relationship
      //
      if (successorRelation == null)
      {
         successorRelation = new Relation(targetTask, this, type, lag);
         successorList.add(successorRelation);
      }

      return (predecessorRelation);
   }

   /**
    * The % Complete field contains the current status of a task, expressed
    * as the percentage of the
    * task's duration that has been completed. You can enter percent complete,
    * or you can have
    * Microsoft Project calculate it for you based on actual duration.
    *
    * @param val value to be set
    */
   public void setPercentageComplete(Number val)
   {
      set(TaskField.PERCENT_COMPLETE, val);
   }

   /**
    * The % Work Complete field contains the current status of a task,
    * expressed as the
    * percentage of the task's work that has been completed. You can enter
    * percent work
    * complete, or you can have Microsoft Project calculate it for you
    * based on actual
    * work on the task.
    *
    * @param val value to be set
    */
   public void setPercentageWorkComplete(Number val)
   {
      set(TaskField.PERCENT_WORK_COMPLETE, val);
   }

   /**
    * The Actual Cost field shows costs incurred for work already performed
    * by all resources
    * on a task, along with any other recorded costs associated with the task.
    * You can enter
    * all the actual costs or have Microsoft Project calculate them for you.
    *
    * @param val value to be set
    */
   public void setActualCost(Number val)
   {
      set(TaskField.ACTUAL_COST, val);
   }

   /**
    * The Actual Duration field shows the span of actual working time for a
    * task so far,
    * based on the scheduled duration and current remaining work or
    * completion percentage.
    *
    * @param val value to be set
    */
   public void setActualDuration(Duration val)
   {
      set(TaskField.ACTUAL_DURATION, val);
   }

   /**
    * The Actual Finish field shows the date and time that a task actually
    * finished.
    * Microsoft Project sets the Actual Finish field to the scheduled finish
    * date if
    * the completion percentage is 100. This field contains "NA" until you
    * enter actual
    * information or set the completion percentage to 100.
    *
    * @param val value to be set
    */
   public void setActualFinish(Date val)
   {
      set(TaskField.ACTUAL_FINISH, val);
   }

   /**
    * The Actual Start field shows the date and time that a task actually began.
    * When a task is first created, the Actual Start field contains "NA." Once you
    * enter the first actual work or a completion percentage for a task, Microsoft
    * Project sets the actual start date to the scheduled start date.
    * @param val value to be set
    */
   public void setActualStart(Date val)
   {
      set(TaskField.ACTUAL_START, val);
   }

   /**
    * The Actual Work field shows the amount of work that has already been
    * done by the
    * resources assigned to a task.
    * @param val value to be set
    */
   public void setActualWork(Duration val)
   {
      set(TaskField.ACTUAL_WORK, val);
   }

   /**
    * The Baseline Cost field shows the total planned cost for a task.
    * Baseline cost is also referred to as budget at completion (BAC).
    *
    * @param val the amount to be set
    */
   public void setBaselineCost(Number val)
   {
      set(TaskField.BASELINE_COST, val);
   }

   /**
    * The Baseline Duration field shows the original span of time planned to
    * complete a task.
    *
    * @param val duration
    */
   public void setBaselineDuration(Duration val)
   {
      set(TaskField.BASELINE_DURATION, val);
   }

   /**
    * The Baseline Finish field shows the planned completion date for a
    * task at the time
    * you saved a baseline. Information in this field becomes available
    * when you set a
    * baseline for a task.
    *
    * @param val Date to be set
    */
   public void setBaselineFinish(Date val)
   {
      set(TaskField.BASELINE_FINISH, val);
   }

   /**
    * The Baseline Start field shows the planned beginning date for a task at
    * the time
    * you saved a baseline. Information in this field becomes available when you
    * set a baseline.
    *
    * @param val Date to be set
    */
   public void setBaselineStart(Date val)
   {
      set(TaskField.BASELINE_START, val);
   }

   /**
    * The Baseline Work field shows the originally planned amount of work to
    * be performed
    * by all resources assigned to a task. This field shows the planned
    * person-hours
    * scheduled for a task. Information in the Baseline Work field
    * becomes available
    * when you set a baseline for the project.
    *
    * @param val the duration to be set.
    */
   public void setBaselineWork(Duration val)
   {
      set(TaskField.BASELINE_WORK, val);
   }

   /**
    * The BCWP (budgeted cost of work performed) field contains the
    * cumulative value
    * of the assignment's timephased percent complete multiplied by
    * the assignments
    * timephased baseline cost. BCWP is calculated up to the status
    * date or todays
    * date. This information is also known as earned value.
    *
    * @param val the amount to be set
    */
   public void setBCWP(Number val)
   {
      set(TaskField.BCWP, val);
   }

   /**
    * The BCWS (budgeted cost of work scheduled) field contains the cumulative
    * timephased baseline costs up to the status date or today's date.
    *
    * @param val the amount to set
    */
   public void setBCWS(Number val)
   {
      set(TaskField.BCWS, val);
   }

   /**
    * The Confirmed field indicates whether all resources assigned to a task have
    * accepted or rejected the task assignment in response to a TeamAssign message
    * regarding their assignments.
    *
    * @param val boolean value
    */
   public void setConfirmed(boolean val)
   {
      set(TaskField.CONFIRMED, val);
   }

   /**
    * The Constraint Date field shows the specific date associated with certain
    * constraint types,
    *  such as Must Start On, Must Finish On, Start No Earlier Than,
    *  Start No Later Than,
    *  Finish No Earlier Than, and Finish No Later Than.
    *  SEE class constants
    *
    * @param val Date to be set
    */
   public void setConstraintDate(Date val)
   {
      set(TaskField.CONSTRAINT_DATE, val);
   }

   /**
    * Set the secondary constraint date.
    *
    * @param date secondary constraint date
    */
   public void setSecondaryConstraintDate(Date date)
   {
      set(TaskField.SECONDARY_CONSTRAINT_DATE, date);
   }

   /**
    * Private method for dealing with string parameters from File.
    *
    * @param type string constraint type
    */
   public void setConstraintType(ConstraintType type)
   {
      set(TaskField.CONSTRAINT_TYPE, type);
   }

   /**
    * Set the secondary constraint type.
    *
    * @param type secondary constraint type
    */
   public void setSecondaryConstraintType(ConstraintType type)
   {
      set(TaskField.SECONDARY_CONSTRAINT_TYPE, type);
   }

   /**
    * The Contact field contains the name of an individual
    * responsible for a task.
    *
    * @param val value to be set
    */
   public void setContact(String val)
   {
      set(TaskField.CONTACT, val);
   }

   /**
    * The Cost field shows the total scheduled, or projected, cost for a task,
    * based on costs already incurred for work performed by all resources assigned
    * to the task, in addition to the costs planned for the remaining work for the
    * assignment. This can also be referred to as estimate at completion (EAC).
    *
    * @param val amount
    */
   public void setCost(Number val)
   {
      set(TaskField.COST, val);
   }

   /**
    * Set a cost value.
    *
    * @param index cost index (1-10)
    * @param value cost value
    */
   public void setCost(int index, Number value)
   {
      set(selectField(TaskFieldLists.CUSTOM_COST, index), value);
   }

   /**
    * Retrieve a cost value.
    *
    * @param index cost index (1-10)
    * @return cost value
    */
   public Number getCost(int index)
   {
      return (Number) getCachedValue(selectField(TaskFieldLists.CUSTOM_COST, index));
   }

   /**
    * The Cost Variance field shows the difference between the
    * baseline cost and total cost for a task. The total cost is the
    * current estimate of costs based on actual costs and remaining costs.
    *
    * @param val amount
    */
   public void setCostVariance(Number val)
   {
      set(TaskField.COST_VARIANCE, val);
   }

   /**
    * The Created field contains the date and time when a task was
    * added to the project.
    *
    * @param val date
    */
   public void setCreateDate(Date val)
   {
      set(TaskField.CREATED, val);
   }

   /**
    * The Critical field indicates whether a task has any room in the
    * schedule to slip,
    * or if a task is on the critical path. The Critical field contains
    * Yes if the task
    * is critical and No if the task is not critical.
    *
    * @param val whether task is critical or not
    */
   public void setCritical(boolean val)
   {
      set(TaskField.CRITICAL, val);
   }

   /**
    * The CV (earned value cost variance) field shows the difference
    * between how much it should have cost to achieve the current level of
    * completion on the task, and how much it has actually cost to achieve the
    * current level of completion up to the status date or today's date.
    *
    * @param val value to set
    */
   public void setCV(Number val)
   {
      set(TaskField.CV, val);
   }

   /**
    * Set amount of delay as elapsed real time.
    *
    * @param val elapsed time
    */
   public void setLevelingDelay(Duration val)
   {
      set(TaskField.LEVELING_DELAY, val);
   }

   /**
    * The Duration field is the total span of active working time for a task.
    * This is generally the amount of time from the start to the finish of a task.
    * The default for new tasks is 1 day (1d).
    *
    * @param val duration
    */
   public void setDuration(Duration val)
   {
      set(TaskField.DURATION, val);
   }

   /**
    * Set the duration text used for a manually scheduled task.
    *
    * @param val text
    */
   public void setDurationText(String val)
   {
      set(TaskField.DURATION_TEXT, val);
   }

   /**
    * Set the manual duration attribute.
    *
    * @param dur manual duration
    */
   public void setManualDuration(Duration dur)
   {
      set(TaskField.MANUAL_DURATION, dur);
   }

   /**
    * Read the manual duration attribute.
    *
    * @return manual duration
    */
   public Duration getManualDuration()
   {
      return (Duration) getCachedValue(TaskField.MANUAL_DURATION);
   }

   /**
    * The Duration Variance field contains the difference between the
    * baseline duration of a task and the forecast or actual duration
    * of the task.
    *
    * @param duration duration value
    */
   public void setDurationVariance(Duration duration)
   {
      set(TaskField.DURATION_VARIANCE, duration);
   }

   /**
    * The Early Finish field contains the earliest date that a task
    * could possibly finish, based on early finish dates of predecessor
    * and successor tasks, other constraints, and any leveling delay.
    *
    * @param date Date value
    */
   public void setEarlyFinish(Date date)
   {
      set(TaskField.EARLY_FINISH, date);
   }

   /**
   * The date the resource is scheduled to finish the remaining work for the activity.
   *
   * @param date Date value
   */
   public void setRemainingEarlyFinish(Date date)
   {
      set(TaskField.REMAINING_EARLY_FINISH, date);
   }

   /**
    * The Early Start field contains the earliest date that a task could
    * possibly begin, based on the early start dates of predecessor and
    * successor tasks, and other constraints.
    *
    * @param date Date value
    */
   public void setEarlyStart(Date date)
   {
      set(TaskField.EARLY_START, date);
   }

   /**
   * The date the resource is scheduled to begin the remaining work for the activity.
   *
   * @param date Date value
   */
   public void setRemainingEarlyStart(Date date)
   {
      set(TaskField.REMAINING_EARLY_START, date);
   }

   /**
    * The Finish field shows the date and time that a task is scheduled to be
    * completed. MS project allows a finish date to be entered, and will
    * calculate the duration, or a duration can be supplied and MS Project
    * will calculate the finish date.
    *
    * @param date Date value
    */
   public void setFinish(Date date)
   {
      set(TaskField.FINISH, date);
   }

   /**
    * Set the finish text used for a manually scheduled task.
    *
    * @param val text
    */
   public void setFinishText(String val)
   {
      set(TaskField.FINISH_TEXT, val);
   }

   /**
    * The Finish Variance field contains the amount of time that represents the
    * difference between a task's baseline finish date and its forecast
    * or actual finish date.
    *
    * @param duration duration value
    */
   public void setFinishVariance(Duration duration)
   {
      set(TaskField.FINISH_VARIANCE, duration);
   }

   /**
    * The Fixed Cost field shows any task expense that is not associated
    * with a resource cost.
    *
    * @param val amount
    */
   public void setFixedCost(Number val)
   {
      set(TaskField.FIXED_COST, val);
   }

   /**
    * The Free Slack field contains the amount of time that a task can be
    * delayed without delaying any successor tasks. If the task has no
    * successors, free slack is the amount of time that a task can be delayed
    * without delaying the entire project's finish date.
    *
    * @param duration duration value
    */
   public void setFreeSlack(Duration duration)
   {
      set(TaskField.FREE_SLACK, duration);
   }

   /**
    * The Hide Bar flag indicates whether the Gantt bars and Calendar bars
    * for a task are hidden when this project's data is displayed in MS Project.
    *
    * @param flag boolean value
    */
   public void setHideBar(boolean flag)
   {
      set(TaskField.HIDE_BAR, flag);
   }

   /**
    * The ID field contains the identifier number that Microsoft Project
    * automatically assigns to each task as you add it to the project.
    * The ID indicates the position of a task with respect to the other tasks.
    *
    * @param val ID
    */
   @Override public void setID(Integer val)
   {
      ProjectFile parent = getParentFile();
      Integer previous = getID();

      if (previous != null)
      {
         parent.getTasks().unmapID(previous);
      }

      parent.getTasks().mapID(val, this);

      set(TaskField.ID, val);
   }

   /**
    * The Late Finish field contains the latest date that a task can finish
    * without delaying the finish of the project. This date is based on the
    * task's late start date, as well as the late start and late finish dates
    * of predecessor and successor tasks, and other constraints.
    *
    * @param date date value
    */
   public void setLateFinish(Date date)
   {
      set(TaskField.LATE_FINISH, date);
   }

   /**
    * The Late Start field contains the latest date that a task can start
    * without delaying the finish of the project. This date is based on the
    * task's start date, as well as the late start and late finish dates of
    * predecessor and successor tasks, and other constraints.
    *
    * @param date date value
    */
   public void setLateStart(Date date)
   {
      set(TaskField.LATE_START, date);
   }

   /**
    * The Linked Fields field indicates whether there are OLE links to the task,
    * either from elsewhere in the active project, another Microsoft Project
    * file, or from another program.
    *
    * @param flag boolean value
    */
   public void setLinkedFields(boolean flag)
   {
      set(TaskField.LINKED_FIELDS, flag);
   }

   /**
    * This is a user defined field used to mark a task for some form of
    * additional action.
    *
    * @param flag boolean value
    */
   public void setMarked(boolean flag)
   {
      set(TaskField.MARKED, flag);
   }

   /**
    * The Milestone field indicates whether a task is a milestone.
    *
    * @param flag boolean value
    */
   public void setMilestone(boolean flag)
   {
      set(TaskField.MILESTONE, flag);
   }

   /**
    * The Name field contains the name of a task.
    *
    * @param name task name
    */
   public void setName(String name)
   {
      set(TaskField.NAME, name);
   }

   /**
    * The Objects field contains the number of objects attached to a task.
    *
    * @param val - integer value
    */
   public void setObjects(Integer val)
   {
      set(TaskField.OBJECTS, val);
   }

   /**
    * The Outline Level field contains the number that indicates the level of
    * the task in the project outline hierarchy.
    *
    * @param val - int
    */
   public void setOutlineLevel(Integer val)
   {
      set(TaskField.OUTLINE_LEVEL, val);
   }

   /**
    * The Outline Number field contains the number of the task in the structure
    * of an outline. This number indicates the task's position within the
    * hierarchical structure of the project outline. The outline number is
    * similar to a WBS (work breakdown structure) number, except that the
    * outline number is automatically entered by Microsoft Project.
    *
    * @param val - text
    */
   public void setOutlineNumber(String val)
   {
      set(TaskField.OUTLINE_NUMBER, val);
   }

   /**
    * The Priority field provides choices for the level of importance
    * assigned to a task, which in turn indicates how readily a task can be
    * delayed or split during resource leveling.
    * The default priority is Medium. Those tasks with a priority
    * of Do Not Level are never delayed or split when Microsoft Project levels
    * tasks that have overallocated resources assigned.
    *
    * @param priority the priority value
    */
   public void setPriority(Priority priority)
   {
      set(TaskField.PRIORITY, priority);
   }

   /**
    * The Project field shows the name of the project from which a
    * task originated.
    * This can be the name of the active project file. If there are
    * other projects
    * inserted into the active project file, the name of the
    * inserted project appears
    * in this field for the task.
    *
    * @param val - text
    */
   public void setProject(String val)
   {
      set(TaskField.PROJECT, val);
   }

   /**
    * The Remaining Cost field shows the remaining scheduled expense of a task that
    * will be incurred in completing the remaining scheduled work by all resources
    * assigned to the task.
    *
    * @param val - currency amount
    */
   public void setRemainingCost(Number val)
   {
      set(TaskField.REMAINING_COST, val);
   }

   /**
    * The Remaining Duration field shows the amount of time required to complete
    * the unfinished portion of a task.
    *
    * @param val - duration.
    */
   public void setRemainingDuration(Duration val)
   {
      set(TaskField.REMAINING_DURATION, val);
   }

   /**
    * The Remaining Work field shows the amount of time, or person-hours,
    * still required by all assigned resources to complete a task.
    * @param val  - duration
    */
   public void setRemainingWork(Duration val)
   {
      set(TaskField.REMAINING_WORK, val);
   }

   /**
    * The Resource Group field contains the list of resource groups to which the
    * resources assigned to a task belong.
    *
    * @param val - String list
    */
   public void setResourceGroup(String val)
   {
      set(TaskField.RESOURCE_GROUP, val);
   }

   /**
    * The Resource Initials field lists the abbreviations for the names of
    * resources assigned to a task. These initials can serve as substitutes
    * for the names.
    *
    * Note that MS Project 98 does no normally populate this field when
    * it generates an MPX file, and will therefore not expect to see values
    * in this field when it reads an MPX file. Supplying values for this
    * field will cause MS Project 98, 2000, and 2002 to create new resources
    * and ignore any other resource assignments that have been defined
    * in the MPX file.
    *
    * @param val String containing a comma separated list of initials
    */
   public void setResourceInitials(String val)
   {
      set(TaskField.RESOURCE_INITIALS, val);
   }

   /**
    * The Resource Names field lists the names of all resources
    * assigned to a task.
    *
    * Note that MS Project 98 does not normally populate this field when
    * it generates an MPX file, and will therefore not expect to see values
    * in this field when it reads an MPX file. Supplying values for this
    * field when writing an MPX file will cause MS Project 98, 2000, and 2002
    * to create new resources and ignore any other resource assignments
    * that have been defined in the MPX file.
    *
    * @param val String containing a comma separated list of names
    */
   public void setResourceNames(String val)
   {
      set(TaskField.RESOURCE_NAMES, val);
   }

   /**
    * The Resume field shows the date that the remaining portion of a task is
    * scheduled to resume after you enter a new value for the % Complete field.
    * The Resume field is also recalculated when the remaining portion of a task
    * is moved to a new date.
    *
    * @param val - Date
    */
   public void setResume(Date val)
   {
      set(TaskField.RESUME, val);
   }

   /**
    * For subtasks, the Rollup field indicates whether information on the subtask
    * Gantt bars will be rolled up to the summary task bar. For summary tasks, the
    * Rollup field indicates whether the summary task bar displays rolled up bars.
    * You must have the Rollup field for summary tasks set to Yes for any subtasks
    * to roll up to them.
    *
    * @param val - boolean
    */
   public void setRollup(boolean val)
   {
      set(TaskField.ROLLUP, val);
   }

   /**
    * The Start field shows the date and time that a task is scheduled to begin.
    * You can enter the start date you want, to indicate the date when the task
    * should begin. Or, you can have Microsoft Project calculate the start date.
    * @param val - Date
    */
   public void setStart(Date val)
   {
      set(TaskField.START, val);
   }

   /**
    * Set the start text used for a manually scheduled task.
    *
    * @param val text
    */
   public void setStartText(String val)
   {
      set(TaskField.START_TEXT, val);
   }

   /**
    * The Start Variance field contains the amount of time that represents the
    * difference between a task's baseline start date and its currently
    * scheduled start date.
    *
    * @param val - duration
    */
   public void setStartVariance(Duration val)
   {
      set(TaskField.START_VARIANCE, val);
   }

   /**
    * The Stop field shows the date that represents the end of the actual
    * portion of a task. Typically, Microsoft Project calculates the stop date.
    * However, you can edit this date as well.
    *
    * @param val - Date
    */
   public void setStop(Date val)
   {
      set(TaskField.STOP, val);
   }

   /**
    * The Subproject File field contains the name of a project inserted into
    * the active project file. The Subproject File field contains the inserted
    * project's path and file name.
    *
    * @param val - String
    */
   public void setSubprojectName(String val)
   {
      set(TaskField.SUBPROJECT_FILE, val);
   }

   /**
    * The Summary field indicates whether a task is a summary task.
    *
    * @param val - boolean
    */
   public void setSummary(boolean val)
   {
      set(TaskField.SUMMARY, val);
   }

   /**
    * The SV (earned value schedule variance) field shows the difference
    * in cost terms between the current progress and the baseline plan
    * of the task up to the status date or today's date. You can use SV
    * to check costs to determine whether tasks are on schedule.
    * @param val - currency amount
    */
   public void setSV(Number val)
   {
      set(TaskField.SV, val);
   }

   /**
    * The Total Slack field contains the amount of time a task can be delayed
    * without delaying the project's finish date.
    *
    * @param val - duration
    */
   public void setTotalSlack(Duration val)
   {
      set(TaskField.TOTAL_SLACK, val);
   }

   /**
    * The Unique ID field contains the number that Microsoft Project
    * automatically designates whenever a new task is created.
    * This number indicates the sequence in which the task was created,
    * regardless of placement in the schedule.
    *
    * @param val unique ID
    */
   @Override public void setUniqueID(Integer val)
   {
      set(TaskField.UNIQUE_ID, val);
   }

   /**
    * The Update Needed field indicates whether a TeamUpdate message should
    * be sent to the assigned resources because of changes to the start date,
    * finish date, or resource reassignments of the task.
    *
    * @param val - boolean
    */
   public void setUpdateNeeded(boolean val)
   {
      set(TaskField.UPDATE_NEEDED, val);
   }

   /**
    * The work breakdown structure code. The WBS field contains an alphanumeric
    * code you can use to represent the task's position within the hierarchical
    * structure of the project. This field is similar to the outline number,
    * except that you can edit it.
    *
    * @param val - String
    */
   public void setWBS(String val)
   {
      set(TaskField.WBS, val);
   }

   /**
    * The Work field shows the total amount of work scheduled to be performed
    * on a task by all assigned resources. This field shows the total work,
    * or person-hours, for a task.
    *
    * @param val - duration
    */
   public void setWork(Duration val)
   {
      set(TaskField.WORK, val);
   }

   /**
    * The Work Variance field contains the difference between a task's baseline
    * work and the currently scheduled work.
    *
    * @param val - duration
    */
   public void setWorkVariance(Duration val)
   {
      set(TaskField.WORK_VARIANCE, val);
   }

   /**
    * The % Complete field contains the current status of a task,
    * expressed as the percentage of the task's duration that has been completed.
    * You can enter percent complete, or you can have Microsoft Project calculate
    * it for you based on actual duration.
    * @return percentage as float
    */
   public Number getPercentageComplete()
   {
      return ((Number) getCachedValue(TaskField.PERCENT_COMPLETE));
   }

   /**
    * The % Work Complete field contains the current status of a task,
    * expressed as the percentage of the task's work that has been completed.
    * You can enter percent work complete, or you can have Microsoft Project
    * calculate it for you based on actual work on the task.
    *
    * @return percentage as float
    */
   public Number getPercentageWorkComplete()
   {
      return ((Number) getCachedValue(TaskField.PERCENT_WORK_COMPLETE));
   }

   /**
    * The Actual Cost field shows costs incurred for work already performed
    * by all resources on a task, along with any other recorded costs associated
    * with the task. You can enter all the actual costs or have Microsoft Project
    * calculate them for you.
    *
    * @return currency amount as float
    */
   public Number getActualCost()
   {
      return ((Number) getCachedValue(TaskField.ACTUAL_COST));
   }

   /**
    * The Actual Duration field shows the span of actual working time for a
    * task so far, based on the scheduled duration and current remaining work
    * or completion percentage.
    *
    * @return duration string
    */
   public Duration getActualDuration()
   {
      return ((Duration) getCachedValue(TaskField.ACTUAL_DURATION));
   }

   /**
    * The Actual Finish field shows the date and time that a task actually
    * finished. Microsoft Project sets the Actual Finish field to the scheduled
    * finish date if the completion percentage is 100. This field contains "NA"
    * until you enter actual information or set the completion percentage to 100.
    * If "NA" is entered as value, arbitrary year zero Date is used. Date(0);
    *
    * @return Date
    */
   public Date getActualFinish()
   {
      return ((Date) getCachedValue(TaskField.ACTUAL_FINISH));
   }

   /**
    * The Actual Start field shows the date and time that a task actually began.
    * When a task is first created, the Actual Start field contains "NA." Once
    * you enter the first actual work or a completion percentage for a task,
    * Microsoft Project sets the actual start date to the scheduled start date.
    * If "NA" is entered as value, arbitrary year zero Date is used. Date(0);
    *
    * @return Date
    */
   public Date getActualStart()
   {
      return ((Date) getCachedValue(TaskField.ACTUAL_START));
   }

   /**
    * The Actual Work field shows the amount of work that has already been done
    * by the resources assigned to a task.
    *
    * @return duration string
    */
   public Duration getActualWork()
   {
      return ((Duration) getCachedValue(TaskField.ACTUAL_WORK));
   }

   /**
    * The Baseline Cost field shows the total planned cost for a task.
    * Baseline cost is also referred to as budget at completion (BAC).
    * @return currency amount as float
    */
   public Number getBaselineCost()
   {
      return ((Number) getCachedValue(TaskField.BASELINE_COST));
   }

   /**
    * The Baseline Duration field shows the original span of time planned
    * to complete a task.
    *
    * @return  - duration string
    */
   public Duration getBaselineDuration()
   {
      Object result = getCachedValue(TaskField.BASELINE_DURATION);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_DURATION);
      }

      if (!(result instanceof Duration))
      {
         result = null;
      }
      return (Duration) result;
   }

   /**
    * Retrieves the text value for the baseline duration.
    *
    * @return baseline duration text
    */
   public String getBaselineDurationText()
   {
      Object result = getCachedValue(TaskField.BASELINE_DURATION);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_DURATION);
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline duration text value.
    *
    * @param value baseline duration text
    */
   public void setBaselineDurationText(String value)
   {
      set(TaskField.BASELINE_DURATION, value);
   }

   /**
    * The Baseline Finish field shows the planned completion date for a task
    * at the time you saved a baseline. Information in this field becomes
    * available when you set a baseline for a task.
    *
    * @return Date
    */
   public Date getBaselineFinish()
   {
      Object result = getCachedValue(TaskField.BASELINE_FINISH);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_FINISH);
      }

      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Retrieves the baseline finish text value.
    *
    * @return baseline finish text
    */
   public String getBaselineFinishText()
   {
      Object result = getCachedValue(TaskField.BASELINE_FINISH);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_FINISH);
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline finish text value.
    *
    * @param value baseline finish text
    */
   public void setBaselineFinishText(String value)
   {
      set(TaskField.BASELINE_FINISH, value);
   }

   /**
    * The Baseline Start field shows the planned beginning date for a task at
    * the time you saved a baseline. Information in this field becomes available
    * when you set a baseline.
    *
    * @return Date
    */
   public Date getBaselineStart()
   {
      Object result = getCachedValue(TaskField.BASELINE_START);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_START);
      }

      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Retrieves the baseline start text value.
    *
    * @return baseline start value
    */
   public String getBaselineStartText()
   {
      Object result = getCachedValue(TaskField.BASELINE_START);
      if (result == null)
      {
         result = getCachedValue(TaskField.BASELINE_ESTIMATED_START);
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline start text value.
    *
    * @param value baseline start text
    */
   public void setBaselineStartText(String value)
   {
      set(TaskField.BASELINE_START, value);
   }

   /**
    * The Baseline Work field shows the originally planned amount of work to be
    * performed by all resources assigned to a task. This field shows the planned
    * person-hours scheduled for a task. Information in the Baseline Work field
    * becomes available when you set a baseline for the project.
    *
    * @return Duration
    */
   public Duration getBaselineWork()
   {
      return ((Duration) getCachedValue(TaskField.BASELINE_WORK));
   }

   /**
    * The BCWP (budgeted cost of work performed) field contains
    * the cumulative value of the assignment's timephased percent complete
    * multiplied by the assignment's timephased baseline cost.
    * BCWP is calculated up to the status date or today's date.
    * This information is also known as earned value.
    *
    * @return currency amount as float
    */
   public Number getBCWP()
   {
      return ((Number) getCachedValue(TaskField.BCWP));
   }

   /**
    * The BCWS (budgeted cost of work scheduled) field contains the cumulative
    * timephased baseline costs up to the status date or today's date.
    *
    * @return currency amount as float
    */
   public Number getBCWS()
   {
      return ((Number) getCachedValue(TaskField.BCWS));
   }

   /**
    * The Confirmed field indicates whether all resources assigned to a task
    * have accepted or rejected the task assignment in response to a TeamAssign
    * message regarding their assignments.
    *
    * @return boolean
    */
   public boolean getConfirmed()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.CONFIRMED)));
   }

   /**
    * The Constraint Date field shows the specific date associated with certain
    * constraint types, such as Must Start On, Must Finish On,
    * Start No Earlier Than,
    * Start No Later Than, Finish No Earlier Than, and Finish No Later Than.
    *
    * @return Date
    */
   public Date getConstraintDate()
   {
      return ((Date) getCachedValue(TaskField.CONSTRAINT_DATE));
   }

   /**
    * Retrieve the secondary constraint date.
    *
    * @return secondary constraint date
    */
   public Date getSecondaryConstraintDate()
   {
      return ((Date) getCachedValue(TaskField.SECONDARY_CONSTRAINT_DATE));
   }

   /**
    * The Constraint Type field provides choices for the type of constraint you
    * can apply for scheduling a task.
    *
    * @return constraint type
    */
   public ConstraintType getConstraintType()
   {
      return ((ConstraintType) getCachedValue(TaskField.CONSTRAINT_TYPE));
   }

   /**
    * Retrieve the secondary constraint type.
    *
    * @return secondary constraint type
    */
   public ConstraintType getSecondaryConstraintType()
   {
      return ((ConstraintType) getCachedValue(TaskField.SECONDARY_CONSTRAINT_TYPE));
   }

   /**
    * The Contact field contains the name of an individual
    * responsible for a task.
    *
    * @return String
    */
   public String getContact()
   {
      return ((String) getCachedValue(TaskField.CONTACT));
   }

   /**
    * The Cost field shows the total scheduled, or projected, cost for a task,
    * based on costs already incurred for work performed by all resources assigned
    * to the task, in addition to the costs planned for the remaining work for the
    * assignment. This can also be referred to as estimate at completion (EAC).
    *
    * @return cost amount
    */
   public Number getCost()
   {
      return ((Number) getCachedValue(TaskField.COST));
   }

   /**
    * The Cost Variance field shows the difference between the baseline cost
    * and total cost for a task. The total cost is the current estimate of costs
    * based on actual costs and remaining costs.
    *
    * @return amount
    */
   public Number getCostVariance()
   {
      Number variance = (Number) getCachedValue(TaskField.COST_VARIANCE);
      if (variance == null)
      {
         Number cost = getCost();
         Number baselineCost = getBaselineCost();
         if (cost != null && baselineCost != null)
         {
            variance = NumberHelper.getDouble(cost.doubleValue() - baselineCost.doubleValue());
            set(TaskField.COST_VARIANCE, variance);
         }
      }
      return (variance);
   }

   /**
    * The Created field contains the date and time when a task was added
    * to the project.
    *
    * @return Date
    */
   public Date getCreateDate()
   {
      return ((Date) getCachedValue(TaskField.CREATED));
   }

   /**
    * The Critical field indicates whether a task has any room in the schedule
    * to slip, or if a task is on the critical path. The Critical field contains
    * Yes if the task is critical and No if the task is not critical.
    *
    * @return boolean
    */
   public boolean getCritical()
   {
      Boolean critical = (Boolean) getCachedValue(TaskField.CRITICAL);
      if (critical == null)
      {
         Duration totalSlack = getTotalSlack();
         ProjectProperties props = getParentFile().getProjectProperties();
         int criticalSlackLimit = NumberHelper.getInt(props.getCriticalSlackLimit());
         if (criticalSlackLimit != 0 && totalSlack.getDuration() != 0 && totalSlack.getUnits() != TimeUnit.DAYS)
         {
            totalSlack = totalSlack.convertUnits(TimeUnit.DAYS, props);
         }
         critical = Boolean.valueOf(totalSlack.getDuration() <= criticalSlackLimit && NumberHelper.getInt(getPercentageComplete()) != 100 && ((getTaskMode() == TaskMode.AUTO_SCHEDULED) || (getDurationText() == null && getStartText() == null && getFinishText() == null)));
         set(TaskField.CRITICAL, critical);
      }
      return (BooleanHelper.getBoolean(critical));
   }

   /**
    * The CV (earned value cost variance) field shows the difference between
    * how much it should have cost to achieve the current level of completion
    * on the task, and how much it has actually cost to achieve the current
    * level of completion up to the status date or today's date.
    * How Calculated   CV is the difference between BCWP
    * (budgeted cost of work performed) and ACWP
    * (actual cost of work performed). Microsoft Project calculates
    * the CV as follows: CV = BCWP - ACWP
    *
    * @return sum of earned value cost variance
    */
   public Number getCV()
   {
      Number variance = (Number) getCachedValue(TaskField.CV);
      if (variance == null)
      {
         variance = Double.valueOf(NumberHelper.getDouble(getBCWP()) - NumberHelper.getDouble(getACWP()));
         set(TaskField.CV, variance);
      }
      return (variance);
   }

   /**
    * Delay , in MPX files as eg '0ed'. Use duration
    *
    * @return Duration
    */
   public Duration getLevelingDelay()
   {
      return ((Duration) getCachedValue(TaskField.LEVELING_DELAY));
   }

   /**
    * The Duration field is the total span of active working time for a task.
    * This is generally the amount of time from the start to the finish of a task.
    * The default for new tasks is 1 day (1d).
    *
    * @return Duration
    */
   public Duration getDuration()
   {
      return (Duration) getCachedValue(TaskField.DURATION);
   }

   /**
    * Retrieves the duration text of a manually scheduled task.
    *
    * @return duration text
    */
   public String getDurationText()
   {
      return (String) getCachedValue(TaskField.DURATION_TEXT);
   }

   /**
    * Set a duration value.
    *
    * @param index duration index (1-10)
    * @param value duration value
    */
   public void setDuration(int index, Duration value)
   {
      set(selectField(TaskFieldLists.CUSTOM_DURATION, index), value);
   }

   /**
    * Retrieve a duration value.
    *
    * @param index duration index (1-10)
    * @return duration value
    */
   public Duration getDuration(int index)
   {
      return (Duration) getCachedValue(selectField(TaskFieldLists.CUSTOM_DURATION, index));
   }

   /**
    * The Duration Variance field contains the difference between the
    * baseline duration of a task and the total duration (current estimate)
    * of a task.
    *
    * @return Duration
    */
   public Duration getDurationVariance()
   {
      Duration variance = (Duration) getCachedValue(TaskField.DURATION_VARIANCE);
      if (variance == null)
      {
         Duration duration = getDuration();
         Duration baselineDuration = getBaselineDuration();

         if (duration != null && baselineDuration != null)
         {
            variance = Duration.getInstance(duration.getDuration() - baselineDuration.convertUnits(duration.getUnits(), getParentFile().getProjectProperties()).getDuration(), duration.getUnits());
            set(TaskField.DURATION_VARIANCE, variance);
         }
      }
      return (variance);
   }

   /**
    * The Early Finish field contains the earliest date that a task could
    * possibly finish, based on early finish dates of predecessor and
    * successor tasks, other constraints, and any leveling delay.
    *
    * @return Date
    */
   public Date getEarlyFinish()
   {
      return ((Date) getCachedValue(TaskField.EARLY_FINISH));
   }

   /**
   * The date the resource is scheduled to finish the remaining work for the activity.
   *
   * @return Date
   */
   public Date getRemainingEarlyFinish()
   {
      return ((Date) getCachedValue(TaskField.REMAINING_EARLY_FINISH));
   }

   /**
    * The Early Start field contains the earliest date that a task could
    * possibly begin, based on the early start dates of predecessor and
    * successor tasks, and other constraints.
    *
    * @return Date
    */
   public Date getEarlyStart()
   {
      return ((Date) getCachedValue(TaskField.EARLY_START));
   }

   /**
   * The date the resource is scheduled to start the remaining work for the activity.
   *
   * @return Date
   */
   public Date getRemainingEarlyStart()
   {
      return ((Date) getCachedValue(TaskField.REMAINING_EARLY_START));
   }

   /**
    * The Finish field shows the date and time that a task is scheduled to
    * be completed. You can enter the finish date you want, to indicate the
    * date when the task should be completed. Or, you can have Microsoft
    * Project calculate the finish date.
    *
    * @return Date
    */
   public Date getFinish()
   {
      return (Date) getCachedValue(TaskField.FINISH);
   }

   /**
    * Retrieves the finish text of a manually scheduled task.
    *
    * @return finish text
    */
   public String getFinishText()
   {
      return (String) getCachedValue(TaskField.FINISH_TEXT);
   }

   /**
    * Set a finish value.
    *
    * @param index finish index (1-10)
    * @param value finish value
    */
   public void setFinish(int index, Date value)
   {
      set(selectField(TaskFieldLists.CUSTOM_FINISH, index), value);
   }

   /**
    * Retrieve a finish value.
    *
    * @param index finish index (1-10)
    * @return finish value
    */
   public Date getFinish(int index)
   {
      return (Date) getCachedValue(selectField(TaskFieldLists.CUSTOM_FINISH, index));
   }

   /**
    * Calculate the finish variance.
    *
    * @return finish variance
    */
   public Duration getFinishVariance()
   {
      Duration variance = (Duration) getCachedValue(TaskField.FINISH_VARIANCE);
      if (variance == null)
      {
         TimeUnit format = getParentFile().getProjectProperties().getDefaultDurationUnits();
         variance = DateHelper.getVariance(this, getBaselineFinish(), getFinish(), format);
         set(TaskField.FINISH_VARIANCE, variance);
      }
      return (variance);
   }

   /**
    * The Fixed Cost field shows any task expense that is not associated
    * with a resource cost.
    *
    * @return currency amount
    */
   public Number getFixedCost()
   {
      return ((Number) getCachedValue(TaskField.FIXED_COST));
   }

   /**
    * Set a flag value.
    *
    * @param index flag index (1-20)
    * @param value flag value
    */
   public void setFlag(int index, boolean value)
   {
      set(selectField(TaskFieldLists.CUSTOM_FLAG, index), value);
   }

   /**
    * Retrieve a flag value.
    *
    * @param index flag index (1-20)
    * @return flag value
    */
   public boolean getFlag(int index)
   {
      return BooleanHelper.getBoolean((Boolean) getCachedValue(selectField(TaskFieldLists.CUSTOM_FLAG, index)));
   }

   /**
    * The Free Slack field contains the amount of time that a task can be
    * delayed without delaying any successor tasks. If the task has no
    * successors, free slack is the amount of time that a task can be
    * delayed without delaying the entire project's finish date.
    *
    * @return Duration
    */
   public Duration getFreeSlack()
   {
      return ((Duration) getCachedValue(TaskField.FREE_SLACK));
   }

   /**
    * The Hide Bar field indicates whether the Gantt bars and Calendar bars
    * for a task are hidden. Click Yes in the Hide Bar field to hide the
    * bar for the task. Click No in the Hide Bar field to show the bar
    * for the task.
    *
    * @return boolean
    */
   public boolean getHideBar()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.HIDE_BAR)));
   }

   /**
    * The ID field contains the identifier number that Microsoft Project
    * automatically assigns to each task as you add it to the project.
    * The ID indicates the position of a task with respect to the other tasks.
    *
    * @return the task ID
    */
   @Override public Integer getID()
   {
      return ((Integer) getCachedValue(TaskField.ID));
   }

   /**
    * The Late Finish field contains the latest date that a task can finish
    * without delaying the finish of the project. This date is based on the
    * task's late start date, as well as the late start and late finish
    * dates of predecessor and successor
    * tasks, and other constraints.
    *
    * @return Date
    */
   public Date getLateFinish()
   {
      return ((Date) getCachedValue(TaskField.LATE_FINISH));
   }

   /**
    * The Late Start field contains the latest date that a task can start
    * without delaying the finish of the project. This date is based on
    * the task's start date, as well as the late start and late finish
    * dates of predecessor and successor tasks, and other constraints.
    *
    * @return Date
    */
   public Date getLateStart()
   {
      return ((Date) getCachedValue(TaskField.LATE_START));
   }

   /**
    * The Linked Fields field indicates whether there are OLE links to the task,
    * either from elsewhere in the active project, another Microsoft Project file,
    * or from another program.
    *
    * @return boolean
    */
   public boolean getLinkedFields()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.LINKED_FIELDS)));
   }

   /**
    * The Marked field indicates whether a task is marked for further action or
    * identification of some kind. To mark a task, click Yes in the Marked field.
    * If you don't want a task marked, click No.
    *
    * @return true for marked
    */
   public boolean getMarked()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.MARKED)));
   }

   /**
    * The Milestone field indicates whether a task is a milestone.
    *
    * @return boolean
    */
   public boolean getMilestone()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.MILESTONE)));
   }

   /**
    * Retrieves the task name.
    *
    * @return task name
    */
   public String getName()
   {
      return ((String) getCachedValue(TaskField.NAME));
   }

   /**
    * The Notes field contains notes that you can enter about a task.
    * You can use task notes to help maintain a history for a task.
    *
    * @return notes
    */
   public String getNotes()
   {
      String notes = (String) getCachedValue(TaskField.NOTES);
      return (notes == null ? "" : notes);
   }

   /**
    * Set a number value.
    *
    * @param index number index (1-20)
    * @param value number value
    */
   public void setNumber(int index, Number value)
   {
      set(selectField(TaskFieldLists.CUSTOM_NUMBER, index), value);
   }

   /**
    * Retrieve a number value.
    *
    * @param index number index (1-20)
    * @return number value
    */
   public Number getNumber(int index)
   {
      return (Number) getCachedValue(selectField(TaskFieldLists.CUSTOM_NUMBER, index));
   }

   /**
    * The Objects field contains the number of objects attached to a task.
    * Microsoft Project counts the number of objects linked or embedded to a task.
    * However, objects in the Notes box in the Resource Form are not included
    * in this count.
    *
    * @return int
    */
   public Integer getObjects()
   {
      return ((Integer) getCachedValue(TaskField.OBJECTS));
   }

   /**
    * The Outline Level field contains the number that indicates the level
    * of the task in the project outline hierarchy.
    *
    * @return int
    */
   public Integer getOutlineLevel()
   {
      return ((Integer) getCachedValue(TaskField.OUTLINE_LEVEL));
   }

   /**
    * The Outline Number field contains the number of the task in the structure
    * of an outline. This number indicates the task's position within the
    * hierarchical structure of the project outline. The outline number is
    * similar to a WBS (work breakdown structure) number,
    * except that the outline number is automatically entered by
    * Microsoft Project.
    *
    * @return String
    */
   public String getOutlineNumber()
   {
      return ((String) getCachedValue(TaskField.OUTLINE_NUMBER));
   }

   /**
    * Retrieves the list of predecessors for this task.
    *
    * @return list of predecessor Relation instances
    */
   @SuppressWarnings("unchecked") public List getPredecessors()
   {
      return ((List) getCachedValue(TaskField.PREDECESSORS));
   }

   /**
    * Retrieves the list of successors for this task.
    *
    * @return list of successor Relation instances
    */
   @SuppressWarnings("unchecked") public List getSuccessors()
   {
      return ((List) getCachedValue(TaskField.SUCCESSORS));
   }

   /**
    * The Priority field provides choices for the level of importance
    * assigned to a task, which in turn indicates how readily a task can be
    * delayed or split during resource leveling.
    * The default priority is Medium. Those tasks with a priority
    * of Do Not Level are never delayed or split when Microsoft Project levels
    * tasks that have overallocated resources assigned.
    *
    * @return priority class instance
    */
   public Priority getPriority()
   {
      return ((Priority) getCachedValue(TaskField.PRIORITY));
   }

   /**
    * The Project field shows the name of the project from which a task
    * originated.
    * This can be the name of the active project file. If there are other
    * projects inserted
    * into the active project file, the name of the inserted project appears
    * in this field
    * for the task.
    *
    * @return name of originating project
    */
   public String getProject()
   {
      return ((String) getCachedValue(TaskField.PROJECT));
   }

   /**
    * The Remaining Cost field shows the remaining scheduled expense of a
    * task that will be incurred in completing the remaining scheduled work
    * by all resources assigned to the task.
    *
    * @return remaining cost
    */
   public Number getRemainingCost()
   {
      return ((Number) getCachedValue(TaskField.REMAINING_COST));
   }

   /**
    * The Remaining Duration field shows the amount of time required
    * to complete the unfinished portion of a task.
    *
    * @return Duration
    */
   public Duration getRemainingDuration()
   {
      return ((Duration) getCachedValue(TaskField.REMAINING_DURATION));
   }

   /**
    * The Remaining Work field shows the amount of time, or person-hours,
    * still required by all assigned resources to complete a task.
    *
    * @return the amount of time still required to complete a task
    */
   public Duration getRemainingWork()
   {
      return ((Duration) getCachedValue(TaskField.REMAINING_WORK));
   }

   /**
    * The Resource Group field contains the list of resource groups to which
    * the resources assigned to a task belong.
    *
    * @return single string list of groups
    */
   public String getResourceGroup()
   {
      return ((String) getCachedValue(TaskField.RESOURCE_GROUP));
   }

   /**
    * The Resource Initials field lists the abbreviations for the names of
    * resources assigned to a task. These initials can serve as substitutes
    * for the names.
    *
    * Note that MS Project 98 does not export values for this field when
    * writing an MPX file, and the field is not currently populated by MPXJ
    * when reading an MPP file.
    *
    * @return String containing a comma separated list of initials
    */
   public String getResourceInitials()
   {
      return ((String) getCachedValue(TaskField.RESOURCE_INITIALS));
   }

   /**
    * The Resource Names field lists the names of all resources assigned
    * to a task.
    *
    * Note that MS Project 98 does not export values for this field when
    * writing an MPX file, and the field is not currently populated by MPXJ
    * when reading an MPP file.
    *
    * @return String containing a comma separated list of names
    */
   public String getResourceNames()
   {
      return ((String) getCachedValue(TaskField.RESOURCE_NAMES));
   }

   /**
    * The Resume field shows the date that the remaining portion of a task
    * is scheduled to resume after you enter a new value for the % Complete
    * field. The Resume field is also recalculated when the remaining portion
    * of a task is moved to a new date.
    *
    * @return Date
    */
   public Date getResume()
   {
      return ((Date) getCachedValue(TaskField.RESUME));
   }

   /**
    * For subtasks, the Rollup field indicates whether information on the
    * subtask Gantt bars
    * will be rolled up to the summary task bar. For summary tasks, the
    * Rollup field indicates
    * whether the summary task bar displays rolled up bars. You must
    * have the Rollup field for
    * summary tasks set to Yes for any subtasks to roll up to them.
    *
    * @return boolean
    */
   public boolean getRollup()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.ROLLUP)));
   }

   /**
    * The Start field shows the date and time that a task is scheduled to begin.
    * You can enter the start date you want, to indicate the date when the task
    * should begin. Or, you can have Microsoft Project calculate the start date.
    *
    * @return Date
    */
   public Date getStart()
   {
      return (Date) getCachedValue(TaskField.START);
   }

   /**
    * Retrieve the start text for a manually scheduled task.
    *
    * @return start text
    */
   public String getStartText()
   {
      return (String) getCachedValue(TaskField.START_TEXT);
   }

   /**
    * Set a start value.
    *
    * @param index start index (1-10)
    * @param value start value
    */
   public void setStart(int index, Date value)
   {
      set(selectField(TaskFieldLists.CUSTOM_START, index), value);
   }

   /**
    * Retrieve a start value.
    *
    * @param index start index (1-10)
    * @return start value
    */
   public Date getStart(int index)
   {
      return (Date) getCachedValue(selectField(TaskFieldLists.CUSTOM_START, index));
   }

   /**
    * Calculate the start variance.
    *
    * @return start variance
    */
   public Duration getStartVariance()
   {
      Duration variance = (Duration) getCachedValue(TaskField.START_VARIANCE);
      if (variance == null)
      {
         TimeUnit format = getParentFile().getProjectProperties().getDefaultDurationUnits();
         variance = DateHelper.getVariance(this, getBaselineStart(), getStart(), format);
         set(TaskField.START_VARIANCE, variance);
      }
      return (variance);
   }

   /**
    * The Stop field shows the date that represents the end of the actual
    * portion of a task. Typically, Microsoft Project calculates the stop date.
    * However, you can edit this date as well.
    *
    * @return Date
    */
   public Date getStop()
   {
      return ((Date) getCachedValue(TaskField.STOP));
   }

   /**
    * Contains the file name and path of the sub project represented by
    * the current task.
    *
    * @return sub project file path
    */
   public String getSubprojectName()
   {
      return ((String) getCachedValue(TaskField.SUBPROJECT_FILE));
   }

   /**
    * The Summary field indicates whether a task is a summary task.
    *
    * @return boolean, true-is summary task
    */
   public boolean getSummary()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.SUMMARY)));
   }

   /**
    * The SV (earned value schedule variance) field shows the difference in
    * cost terms between the current progress and the baseline plan of the
    * task up to the status date or today's date. You can use SV to
    * check costs to determine whether tasks are on schedule.
    *
    * @return -earned value schedule variance
    */
   public Number getSV()
   {
      Number variance = (Number) getCachedValue(TaskField.SV);
      if (variance == null)
      {
         Number bcwp = getBCWP();
         Number bcws = getBCWS();
         if (bcwp != null && bcws != null)
         {
            variance = NumberHelper.getDouble(bcwp.doubleValue() - bcws.doubleValue());
            set(TaskField.SV, variance);
         }
      }
      return (variance);
   }

   /**
    * Set a text value.
    *
    * @param index text index (1-30)
    * @param value text value
    */
   public void setText(int index, String value)
   {
      set(selectField(TaskFieldLists.CUSTOM_TEXT, index), value);
   }

   /**
    * Retrieve a text value.
    *
    * @param index text index (1-30)
    * @return text value
    */
   public String getText(int index)
   {
      return (String) getCachedValue(selectField(TaskFieldLists.CUSTOM_TEXT, index));
   }

   /**
    * Set an outline code value.
    *
    * @param index outline code index (1-10)
    * @param value outline code value
    */
   public void setOutlineCode(int index, String value)
   {
      set(selectField(TaskFieldLists.CUSTOM_OUTLINE_CODE, index), value);
   }

   /**
    * Retrieve an outline code value.
    *
    * @param index outline code index (1-10)
    * @return outline code value
    */
   public String getOutlineCode(int index)
   {
      return (String) getCachedValue(selectField(TaskFieldLists.CUSTOM_OUTLINE_CODE, index));
   }

   /**
    * The Total Slack field contains the amount of time a task can be
    * delayed without delaying the project's finish date.
    *
    * @return string representing duration
    */
   public Duration getTotalSlack()
   {
      Duration totalSlack = (Duration) getCachedValue(TaskField.TOTAL_SLACK);
      if (totalSlack == null)
      {
         Duration duration = getDuration();
         if (duration == null)
         {
            duration = Duration.getInstance(0, TimeUnit.DAYS);
         }

         TimeUnit units = duration.getUnits();

         Duration startSlack = getStartSlack();
         if (startSlack == null)
         {
            startSlack = Duration.getInstance(0, units);
         }
         else
         {
            if (startSlack.getUnits() != units)
            {
               startSlack = startSlack.convertUnits(units, getParentFile().getProjectProperties());
            }
         }

         Duration finishSlack = getFinishSlack();
         if (finishSlack == null)
         {
            finishSlack = Duration.getInstance(0, units);
         }
         else
         {
            if (finishSlack.getUnits() != units)
            {
               finishSlack = finishSlack.convertUnits(units, getParentFile().getProjectProperties());
            }
         }

         double startSlackDuration = startSlack.getDuration();
         double finishSlackDuration = finishSlack.getDuration();

         if (startSlackDuration == 0 || finishSlackDuration == 0)
         {
            if (startSlackDuration != 0)
            {
               totalSlack = startSlack;
            }
            else
            {
               totalSlack = finishSlack;
            }
         }
         else
         {
            if (startSlackDuration < finishSlackDuration)
            {
               totalSlack = startSlack;
            }
            else
            {
               totalSlack = finishSlack;
            }
         }

         set(TaskField.TOTAL_SLACK, totalSlack);
      }

      return (totalSlack);
   }

   /**
    * The Unique ID field contains the number that Microsoft Project
    * automatically designates whenever a new task is created. This number
    * indicates the sequence in which the task was
    * created, regardless of placement in the schedule.
    *
    * @return String
    */
   @Override public Integer getUniqueID()
   {
      return ((Integer) getCachedValue(TaskField.UNIQUE_ID));
   }

   /**
    * The Update Needed field indicates whether a TeamUpdate message
    * should be sent to the assigned resources because of changes to the
    * start date, finish date, or resource reassignments of the task.
    *
    * @return true if needed.
    */
   public boolean getUpdateNeeded()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.UPDATE_NEEDED)));
   }

   /**
    * The work breakdown structure code. The WBS field contains an
    * alphanumeric code you can use to represent the task's position within
    * the hierarchical structure of the project. This field is similar to
    * the outline number, except that you can edit it.
    *
    * @return string
    */
   public String getWBS()
   {
      return ((String) getCachedValue(TaskField.WBS));
   }

   /**
    * The Work field shows the total amount of work scheduled to be performed
    * on a task by all assigned resources. This field shows the total work,
    * or person-hours, for a task.
    *
    * @return Duration representing duration .
    */
   public Duration getWork()
   {
      return ((Duration) getCachedValue(TaskField.WORK));
   }

   /**
    * The Work Variance field contains the difference between a task's
    * baseline work and the currently scheduled work.
    *
    * @return Duration representing duration.
    */
   public Duration getWorkVariance()
   {
      Duration variance = (Duration) getCachedValue(TaskField.WORK_VARIANCE);
      if (variance == null)
      {
         Duration work = getWork();
         Duration baselineWork = getBaselineWork();
         if (work != null && baselineWork != null)
         {
            variance = Duration.getInstance(work.getDuration() - baselineWork.convertUnits(work.getUnits(), getParentFile().getProjectProperties()).getDuration(), work.getUnits());
            set(TaskField.WORK_VARIANCE, variance);
         }
      }
      return (variance);
   }

   /**
    * This method retrieves a reference to the parent of this task, as
    * defined by the outline level. If this task is at the top level,
    * this method will return null.
    *
    * @return parent task
    */
   public Task getParentTask()
   {
      return (m_parent);
   }

   /**
    * This method retrieves a list of child tasks relative to the
    * current task, as defined by the outine level. If there
    * are no child tasks, this method will return an empty list.
    *
    * @return child tasks
    */
   @Override public List getChildTasks()
   {
      return (m_children);
   }

   /**
    * This method implements the only method in the Comparable interface.
    * This allows Tasks to be compared and sorted based on their ID value.
    * Note that if the MPX/MPP file has been generated by MSP, the ID value
    * will always be in the correct sequence. The Unique ID value will not
    * necessarily be in the correct sequence as task insertions and deletions
    * will change the order.
    *
    * @param o object to compare this instance with
    * @return result of comparison
    */
   @Override public int compareTo(Task o)
   {
      int id1 = NumberHelper.getInt(getID());
      int id2 = NumberHelper.getInt(o.getID());
      return ((id1 < id2) ? (-1) : ((id1 == id2) ? 0 : 1));
   }

   /**
    * This method retrieves a flag indicating whether the duration of the
    * task has only been estimated.
    *
    * @return boolean
    */
   public boolean getEstimated()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.ESTIMATED)));
   }

   /**
    * This method retrieves a flag indicating whether the duration of the
    * task has only been estimated.
    *
    * @param estimated Boolean flag
    */
   public void setEstimated(boolean estimated)
   {
      set(TaskField.ESTIMATED, estimated);
   }

   /**
    * This method retrieves the deadline for this task.
    *
    * @return Task deadline
    */
   public Date getDeadline()
   {
      return ((Date) getCachedValue(TaskField.DEADLINE));
   }

   /**
    * This method sets the deadline for this task.
    *
    * @param deadline deadline date
    */
   public void setDeadline(Date deadline)
   {
      set(TaskField.DEADLINE, deadline);
   }

   /**
    * This method retrieves the task type.
    *
    * @return int representing the task type
    */
   public TaskType getType()
   {
      return ((TaskType) getCachedValue(TaskField.TYPE));
   }

   /**
    * This method sets the task type.
    *
    * @param type task type
    */
   public void setType(TaskType type)
   {
      set(TaskField.TYPE, type);
   }

   /**
    * Retrieves the flag indicating if this is a null task.
    *
    * @return boolean flag
    */
   public boolean getNull()
   {
      return (m_null);
   }

   /**
    * Sets the flag indicating if this is a null task.
    *
    * @param isNull boolean flag
    */
   public void setNull(boolean isNull)
   {
      m_null = isNull;
   }

   /**
    * Retrieve the resume valid flag.
    *
    * @return resume valid flag
    */
   public boolean getResumeValid()
   {
      return (m_resumeValid);
   }

   /**
    * Set the resume valid flag.
    *
    * @param resumeValid resume valid flag
    */
   public void setResumeValid(boolean resumeValid)
   {
      m_resumeValid = resumeValid;
   }

   /**
    * Retrieve the recurring flag.
    *
    * @return recurring flag
    */
   public boolean getRecurring()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.RECURRING)));
   }

   /**
    * Set the recurring flag.
    *
    * @param recurring recurring flag
    */
   public void setRecurring(boolean recurring)
   {
      set(TaskField.RECURRING, recurring);
   }

   /**
    * Retrieve the over allocated flag.
    *
    * @return over allocated flag
    */
   public boolean getOverAllocated()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.OVERALLOCATED)));
   }

   /**
    * Set the over allocated flag.
    *
    * @param overAllocated over allocated flag
    */
   public void setOverAllocated(boolean overAllocated)
   {
      set(TaskField.OVERALLOCATED, overAllocated);
   }

   /**
    * Where a task in an MPP file represents a task from a subproject,
    * this value will be non-zero. The value itself is the unique ID
    * value shown in the parent project. To retrieve the value of the
    * task unique ID in the child project, remove the top two bytes:
    *
    * taskID = (subprojectUniqueID & 0xFFFF)
    *
    * @return sub project unique task ID
    */
   public Integer getSubprojectTaskUniqueID()
   {
      return (Integer) getCachedValue(TaskField.SUBPROJECT_UNIQUE_TASK_ID);
   }

   /**
    * Sets the sub project unique task ID.
    *
    * @param subprojectUniqueTaskID subproject unique task ID
    */
   public void setSubprojectTaskUniqueID(Integer subprojectUniqueTaskID)
   {
      set(TaskField.SUBPROJECT_UNIQUE_TASK_ID, subprojectUniqueTaskID);
   }

   /**
    * Where a task in an MPP file represents a task from a subproject,
    * this value will be non-zero. The value itself is the ID
    * value shown in the parent project.
    *
    * @return sub project task ID
    */
   public Integer getSubprojectTaskID()
   {
      return (Integer) getCachedValue(TaskField.SUBPROJECT_TASK_ID);
   }

   /**
    * Sets the sub project task ID.
    *
    * @param subprojectTaskID subproject task ID
    */
   public void setSubprojectTaskID(Integer subprojectTaskID)
   {
      set(TaskField.SUBPROJECT_TASK_ID, subprojectTaskID);
   }

   /**
    * Sets the offset added to unique task IDs from sub projects
    * to generate the task ID shown in the master project.
    *
    * @param offset unique ID offset
    */
   public void setSubprojectTasksUniqueIDOffset(Integer offset)
   {
      set(TaskField.SUBPROJECT_TASKS_UNIQUEID_OFFSET, offset);
   }

   /**
    * Retrieves the offset added to unique task IDs from sub projects
    * to generate the task ID shown in the master project.
    *
    * @return unique ID offset
    */
   public Integer getSubprojectTasksUniqueIDOffset()
   {
      return (Integer) getCachedValue(TaskField.SUBPROJECT_TASKS_UNIQUEID_OFFSET);
   }

   /**
    * Retrieve the subproject read only flag.
    *
    * @return subproject read only flag
    */
   public boolean getSubprojectReadOnly()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.SUBPROJECT_READ_ONLY)));
   }

   /**
    * Set the subproject read only flag.
    *
    * @param subprojectReadOnly subproject read only flag
    */
   public void setSubprojectReadOnly(boolean subprojectReadOnly)
   {
      set(TaskField.SUBPROJECT_READ_ONLY, subprojectReadOnly);
   }

   /**
    * Retrieves the external task flag.
    *
    * @return external task flag
    */
   public boolean getExternalTask()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.EXTERNAL_TASK)));
   }

   /**
    * Sets the external task flag.
    *
    * @param externalTask external task flag
    */
   public void setExternalTask(boolean externalTask)
   {
      set(TaskField.EXTERNAL_TASK, externalTask);
   }

   /**
    * Retrieves the external task project file name.
    *
    * @return external task project file name
    */
   public String getExternalTaskProject()
   {
      return (m_externalTaskProject);
   }

   /**
    * Sets the external task project file name.
    *
    * @param externalTaskProject external task project file name
    */
   public void setExternalTaskProject(String externalTaskProject)
   {
      m_externalTaskProject = externalTaskProject;
   }

   /**
    * Retrieve the ACWP value.
    *
    * @return ACWP value
    */
   public Number getACWP()
   {
      return ((Number) getCachedValue(TaskField.ACWP));
   }

   /**
    * Set the ACWP value.
    *
    * @param acwp ACWP value
    */
   public void setACWP(Number acwp)
   {
      set(TaskField.ACWP, acwp);
   }

   /**
    * Retrieve the leveling delay format.
    *
    * @return leveling delay  format
    */
   public TimeUnit getLevelingDelayFormat()
   {
      return (TimeUnit) getCachedValue(TaskField.LEVELING_DELAY_UNITS);
   }

   /**
    * Set the leveling delay format.
    *
    * @param levelingDelayFormat leveling delay format
    */
   public void setLevelingDelayFormat(TimeUnit levelingDelayFormat)
   {
      set(TaskField.LEVELING_DELAY_UNITS, levelingDelayFormat);
   }

   /**
    * Retrieves the ignore resource calendar flag.
    *
    * @return ignore resource calendar flag
    */
   public boolean getIgnoreResourceCalendar()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.IGNORE_RESOURCE_CALENDAR)));
   }

   /**
    * Sets the ignore resource calendar flag.
    *
    * @param ignoreResourceCalendar ignore resource calendar flag
    */
   public void setIgnoreResourceCalendar(boolean ignoreResourceCalendar)
   {
      set(TaskField.IGNORE_RESOURCE_CALENDAR, ignoreResourceCalendar);
   }

   /**
    * Retrieves the physical percent complete value.
    *
    * @return physical percent complete value
    */
   public Number getPhysicalPercentComplete()
   {
      return (Number) getCachedValue(TaskField.PHYSICAL_PERCENT_COMPLETE);
   }

   /**
    * Sets the physical percent complete value.
    *
    * @param physicalPercentComplete physical percent complete value
    */
   public void setPhysicalPercentComplete(Number physicalPercentComplete)
   {
      set(TaskField.PHYSICAL_PERCENT_COMPLETE, physicalPercentComplete);
   }

   /**
    * Retrieves the earned value method.
    *
    * @return earned value method
    */
   public EarnedValueMethod getEarnedValueMethod()
   {
      return (EarnedValueMethod) getCachedValue(TaskField.EARNED_VALUE_METHOD);
   }

   /**
    * Sets the earned value method.
    *
    * @param earnedValueMethod earned value method
    */
   public void setEarnedValueMethod(EarnedValueMethod earnedValueMethod)
   {
      set(TaskField.EARNED_VALUE_METHOD, earnedValueMethod);
   }

   /**
    * Retrieves the actual work protected value.
    *
    * @return actual work protected value
    */
   public Duration getActualWorkProtected()
   {
      return (Duration) getCachedValue(TaskField.ACTUAL_WORK_PROTECTED);
   }

   /**
    * Sets the actual work protected value.
    *
    * @param actualWorkProtected actual work protected value
    */
   public void setActualWorkProtected(Duration actualWorkProtected)
   {
      set(TaskField.ACTUAL_WORK_PROTECTED, actualWorkProtected);
   }

   /**
    * Retrieves the actual overtime work protected value.
    *
    * @return actual overtime work protected value
    */
   public Duration getActualOvertimeWorkProtected()
   {
      return (Duration) getCachedValue(TaskField.ACTUAL_OVERTIME_WORK_PROTECTED);
   }

   /**
    * Sets the actual overtime work protected value.
    *
    * @param actualOvertimeWorkProtected actual overtime work protected value
    */
   public void setActualOvertimeWorkProtected(Duration actualOvertimeWorkProtected)
   {
      set(TaskField.ACTUAL_OVERTIME_WORK_PROTECTED, actualOvertimeWorkProtected);
   }

   /**
    * Retrieve the amount of regular work.
    *
    * @return amount of regular work
    */
   public Duration getRegularWork()
   {
      return ((Duration) getCachedValue(TaskField.REGULAR_WORK));
   }

   /**
    * Set the amount of regular work.
    *
    * @param regularWork amount of regular work
    */
   public void setRegularWork(Duration regularWork)
   {
      set(TaskField.REGULAR_WORK, regularWork);
   }

   /**
    * Sets the effort driven flag.
    *
    * @param flag value
    */
   public void setEffortDriven(boolean flag)
   {
      set(TaskField.EFFORT_DRIVEN, flag);
   }

   /**
    * Retrieves the effort driven flag.
    *
    * @return Flag value
    */
   public boolean getEffortDriven()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.EFFORT_DRIVEN)));
   }

   /**
    * Set a date value.
    *
    * @param index date index (1-10)
    * @param value date value
    */
   public void setDate(int index, Date value)
   {
      set(selectField(TaskFieldLists.CUSTOM_DATE, index), value);
   }

   /**
    * Retrieve a date value.
    *
    * @param index date index (1-10)
    * @return date value
    */
   public Date getDate(int index)
   {
      return (Date) getCachedValue(selectField(TaskFieldLists.CUSTOM_DATE, index));
   }

   /**
    * Retrieves the overtime cost.
    *
    * @return Cost value
    */
   public Number getOvertimeCost()
   {
      return ((Number) getCachedValue(TaskField.OVERTIME_COST));
   }

   /**
    * Sets the overtime cost value.
    *
    * @param number Cost value
    */
   public void setOvertimeCost(Number number)
   {
      set(TaskField.OVERTIME_COST, number);
   }

   /**
    * Retrieves the actual overtime cost for this task.
    *
    * @return actual overtime cost
    */
   public Number getActualOvertimeCost()
   {
      return ((Number) getCachedValue(TaskField.ACTUAL_OVERTIME_COST));
   }

   /**
    * Sets the actual overtime cost for this task.
    *
    * @param cost actual overtime cost
    */
   public void setActualOvertimeCost(Number cost)
   {
      set(TaskField.ACTUAL_OVERTIME_COST, cost);
   }

   /**
    * Retrieves the actual overtime work value.
    *
    * @return actual overtime work value
    */
   public Duration getActualOvertimeWork()
   {
      return ((Duration) getCachedValue(TaskField.ACTUAL_OVERTIME_WORK));
   }

   /**
    * Sets the actual overtime work value.
    *
    * @param work actual overtime work value
    */
   public void setActualOvertimeWork(Duration work)
   {
      set(TaskField.ACTUAL_OVERTIME_WORK, work);
   }

   /**
    * Retrieves the fixed cost accrual flag value.
    *
    * @return fixed cost accrual flag
    */
   public AccrueType getFixedCostAccrual()
   {
      return ((AccrueType) getCachedValue(TaskField.FIXED_COST_ACCRUAL));
   }

   /**
    * Sets the fixed cost accrual flag value.
    *
    * @param type fixed cost accrual type
    */
   public void setFixedCostAccrual(AccrueType type)
   {
      set(TaskField.FIXED_COST_ACCRUAL, type);
   }

   /**
    * Retrieves the task hyperlink attribute.
    *
    * @return hyperlink attribute
    */
   public String getHyperlink()
   {
      return ((String) getCachedValue(TaskField.HYPERLINK));
   }

   /**
    * Retrieves the task hyperlink address attribute.
    *
    * @return hyperlink address attribute
    */
   public String getHyperlinkAddress()
   {
      return ((String) getCachedValue(TaskField.HYPERLINK_ADDRESS));
   }

   /**
    * Retrieves the task hyperlink sub-address attribute.
    *
    * @return hyperlink sub address attribute
    */
   public String getHyperlinkSubAddress()
   {
      return ((String) getCachedValue(TaskField.HYPERLINK_SUBADDRESS));
   }

   /**
    * Sets the task hyperlink attribute.
    *
    * @param text hyperlink attribute
    */
   public void setHyperlink(String text)
   {
      set(TaskField.HYPERLINK, text);
   }

   /**
    * Sets the task hyperlink address attribute.
    *
    * @param text hyperlink address attribute
    */
   public void setHyperlinkAddress(String text)
   {
      set(TaskField.HYPERLINK_ADDRESS, text);
   }

   /**
    * Sets the task hyperlink sub address attribute.
    *
    * @param text hyperlink sub address attribute
    */
   public void setHyperlinkSubAddress(String text)
   {
      set(TaskField.HYPERLINK_SUBADDRESS, text);
   }

   /**
    * Retrieves the level assignments flag.
    *
    * @return level assignments flag
    */
   public boolean getLevelAssignments()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.LEVEL_ASSIGNMENTS)));
   }

   /**
    * Sets the level assignments flag.
    *
    * @param flag level assignments flag
    */
   public void setLevelAssignments(boolean flag)
   {
      set(TaskField.LEVEL_ASSIGNMENTS, flag);
   }

   /**
    * Retrieves the leveling can split flag.
    *
    * @return leveling can split flag
    */
   public boolean getLevelingCanSplit()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.LEVELING_CAN_SPLIT)));
   }

   /**
    * Sets the leveling can split flag.
    *
    * @param flag leveling can split flag
    */
   public void setLevelingCanSplit(boolean flag)
   {
      set(TaskField.LEVELING_CAN_SPLIT, flag);
   }

   /**
    * Retrieves the overtime work attribute.
    *
    * @return overtime work value
    */
   public Duration getOvertimeWork()
   {
      return ((Duration) getCachedValue(TaskField.OVERTIME_WORK));
   }

   /**
    * Sets the overtime work attribute.
    *
    * @param work overtime work value
    */
   public void setOvertimeWork(Duration work)
   {
      set(TaskField.OVERTIME_WORK, work);
   }

   /**
    * Retrieves the preleveled start attribute.
    *
    * @return preleveled start
    */
   public Date getPreleveledStart()
   {
      return ((Date) getCachedValue(TaskField.PRELEVELED_START));
   }

   /**
    * Retrieves the preleveled finish attribute.
    *
    * @return preleveled finish
    */
   public Date getPreleveledFinish()
   {
      return ((Date) getCachedValue(TaskField.PRELEVELED_FINISH));
   }

   /**
    * Sets the preleveled start attribute.
    *
    * @param date preleveled start attribute
    */
   public void setPreleveledStart(Date date)
   {
      set(TaskField.PRELEVELED_START, date);
   }

   /**
    * Sets the preleveled finish attribute.
    *
    * @param date preleveled finish attribute
    */
   public void setPreleveledFinish(Date date)
   {
      set(TaskField.PRELEVELED_FINISH, date);
   }

   /**
    * Retrieves the remaining overtime work attribute.
    *
    * @return remaining overtime work
    */
   public Duration getRemainingOvertimeWork()
   {
      return ((Duration) getCachedValue(TaskField.REMAINING_OVERTIME_WORK));
   }

   /**
    * Sets the remaining overtime work attribute.
    *
    * @param work remaining overtime work
    */
   public void setRemainingOvertimeWork(Duration work)
   {
      set(TaskField.REMAINING_OVERTIME_WORK, work);
   }

   /**
    * Retrieves the remaining overtime cost.
    *
    * @return remaining overtime cost value
    */
   public Number getRemainingOvertimeCost()
   {
      return ((Number) getCachedValue(TaskField.REMAINING_OVERTIME_COST));
   }

   /**
    * Sets the remaining overtime cost value.
    *
    * @param cost overtime cost value
    */
   public void setRemainingOvertimeCost(Number cost)
   {
      set(TaskField.REMAINING_OVERTIME_COST, cost);
   }

   /**
    * Retrieves the base calendar instance associated with this task.
    * Note that this attribute appears in MPP9 and MSPDI files.
    *
    * @return ProjectCalendar instance
    */
   public ProjectCalendar getCalendar()
   {
      return ((ProjectCalendar) getCachedValue(TaskField.CALENDAR));
   }

   /**
    * Set the calendar unique ID.
    *
    * @param id calendar unique ID
    */
   public void setCalendarUniqueID(Integer id)
   {
      set(TaskField.CALENDAR_UNIQUE_ID, id);
   }

   /**
    * Retrieve the calendar unique ID.
    *
    * @return calendar unique ID
    */
   public Integer getCalendarUniqueID()
   {
      return (Integer) getCachedValue(TaskField.CALENDAR_UNIQUE_ID);
   }

   /**
    * Sets the name of the base calendar associated with this task.
    * Note that this attribute appears in MPP9 and MSPDI files.
    *
    * @param calendar calendar instance
    */
   public void setCalendar(ProjectCalendar calendar)
   {
      set(TaskField.CALENDAR, calendar);
      setCalendarUniqueID(calendar == null ? null : calendar.getUniqueID());
   }

   /**
    * Retrieve a flag indicating if the task is shown as expanded
    * in MS Project. If this flag is set to true, any sub tasks
    * for this current task will be visible. If this is false,
    * any sub tasks will be hidden.
    *
    * @return boolean flag
    */
   public boolean getExpanded()
   {
      return (m_expanded);
   }

   /**
    * Set a flag indicating if the task is shown as expanded
    * in MS Project. If this flag is set to true, any sub tasks
    * for this current task will be visible. If this is false,
    * any sub tasks will be hidden.
    *
    * @param expanded boolean flag
    */
   public void setExpanded(boolean expanded)
   {
      m_expanded = expanded;
   }

   /**
    * Set the start slack.
    *
    * @param duration start slack
    */
   public void setStartSlack(Duration duration)
   {
      set(TaskField.START_SLACK, duration);
   }

   /**
    * Set the finish slack.
    *
    * @param duration finish slack
    */
   public void setFinishSlack(Duration duration)
   {
      set(TaskField.FINISH_SLACK, duration);
   }

   /**
    * Retrieve the start slack.
    *
    * @return start slack
    */
   public Duration getStartSlack()
   {
      Duration startSlack = (Duration) getCachedValue(TaskField.START_SLACK);
      if (startSlack == null)
      {
         Duration duration = getDuration();
         if (duration != null)
         {
            startSlack = DateHelper.getVariance(this, getEarlyStart(), getLateStart(), duration.getUnits());
            set(TaskField.START_SLACK, startSlack);
         }
      }
      return (startSlack);
   }

   /**
    * Retrieve the finish slack.
    *
    * @return finish slack
    */
   public Duration getFinishSlack()
   {
      Duration finishSlack = (Duration) getCachedValue(TaskField.FINISH_SLACK);
      if (finishSlack == null)
      {
         Duration duration = getDuration();
         if (duration != null)
         {
            finishSlack = DateHelper.getVariance(this, getEarlyFinish(), getLateFinish(), duration.getUnits());
            set(TaskField.FINISH_SLACK, finishSlack);
         }
      }
      return (finishSlack);
   }

   /**
    * Retrieve the value of a field using its alias.
    *
    * @param alias field alias
    * @return field value
    */
   public Object getFieldByAlias(String alias)
   {
      return getCachedValue(getParentFile().getCustomFields().getFieldByAlias(FieldTypeClass.TASK, alias));
   }

   /**
    * Set the value of a field using its alias.
    *
    * @param alias field alias
    * @param value field value
    */
   public void setFieldByAlias(String alias, Object value)
   {
      set(getParentFile().getCustomFields().getFieldByAlias(FieldTypeClass.TASK, alias), value);
   }

   /**
    * This method retrieves a list of task splits. Each split is represented
    * by a DateRange instance. The list will always follow the pattern
    * task range, split range, task range and so on.
    *
    * Note that this method will return null if the task is not split.
    *
    * @return list of split times
    */
   @SuppressWarnings("unchecked") public List getSplits()
   {
      return (List) getCachedValue(TaskField.SPLITS);
   }

   /**
    * Internal method used to set the list of splits.
    *
    * @param splits list of split times
    */
   public void setSplits(List splits)
   {
      set(TaskField.SPLITS, splits);
   }

   /**
    * Task splits contain the time up to which the splits are completed.
    *
    * @return Duration of completed time for the splits.
    */
   public Date getSplitCompleteDuration()
   {
      return (Date) getCachedValue(TaskField.SPLITS_COMPLETE);
   }

   /**
    * Set the time up to which the splits are completed.
    *
    * @param splitsComplete Duration of completed time for the splits.
    */
   public void setSplitCompleteDuration(Date splitsComplete)
   {
      set(TaskField.SPLITS_COMPLETE, splitsComplete);
   }

   /**
    * Removes this task from the project.
    */
   public void remove()
   {
      getParentFile().removeTask(this);
   }

   /**
    * Retrieve the sub project represented by this task.
    *
    * @return sub project
    */
   public SubProject getSubProject()
   {
      return (SubProject) getCachedValue(TaskField.SUBPROJECT);
   }

   /**
    * Set the sub project represented by this task.
    *
    * @param subProject sub project
    */
   public void setSubProject(SubProject subProject)
   {
      set(TaskField.SUBPROJECT, subProject);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public Number getEnterpriseCost(int index)
   {
      return ((Number) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_COST, index)));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseCost(int index, Number value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_COST, index), value);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public Date getEnterpriseDate(int index)
   {
      return ((Date) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_DATE, index)));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseDate(int index, Date value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_DATE, index), value);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public Duration getEnterpriseDuration(int index)
   {
      return ((Duration) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_DURATION, index)));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseDuration(int index, Duration value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_DURATION, index), value);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public boolean getEnterpriseFlag(int index)
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_FLAG, index))));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseFlag(int index, boolean value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_FLAG, index), value);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public Number getEnterpriseNumber(int index)
   {
      return ((Number) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_NUMBER, index)));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseNumber(int index, Number value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_NUMBER, index), value);
   }

   /**
    * Retrieve an enterprise field value.
    *
    * @param index field index
    * @return field value
    */
   public String getEnterpriseText(int index)
   {
      return ((String) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_TEXT, index)));
   }

   /**
    * Set an enterprise field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseText(int index, String value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_TEXT, index), value);
   }

   /**
    * Retrieve an enterprise custom field value.
    *
    * @param index field index
    * @return field value
    */
   public String getEnterpriseCustomField(int index)
   {
      return ((String) getCachedValue(selectField(TaskFieldLists.ENTERPRISE_CUSTOM_FIELD, index)));
   }

   /**
    * Set an enterprise custom field value.
    *
    * @param index field index
    * @param value field value
    */
   public void setEnterpriseCustomField(int index, String value)
   {
      set(selectField(TaskFieldLists.ENTERPRISE_CUSTOM_FIELD, index), value);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineCost(int baselineNumber, Number value)
   {
      set(selectField(TaskFieldLists.BASELINE_COSTS, baselineNumber), value);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineDuration(int baselineNumber, Duration value)
   {
      set(selectField(TaskFieldLists.BASELINE_DURATIONS, baselineNumber), value);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineFinish(int baselineNumber, Date value)
   {
      set(selectField(TaskFieldLists.BASELINE_FINISHES, baselineNumber), value);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineStart(int baselineNumber, Date value)
   {
      set(selectField(TaskFieldLists.BASELINE_STARTS, baselineNumber), value);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineWork(int baselineNumber, Duration value)
   {
      set(selectField(TaskFieldLists.BASELINE_WORKS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Number getBaselineCost(int baselineNumber)
   {
      return ((Number) getCachedValue(selectField(TaskFieldLists.BASELINE_COSTS, baselineNumber)));
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Duration getBaselineDuration(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_DURATIONS, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_DURATIONS, baselineNumber));
      }

      if (!(result instanceof Duration))
      {
         result = null;
      }
      return (Duration) result;
   }

   /**
    * Retrieves the baseline duration text value.
    *
    * @param baselineNumber baseline number
    * @return baseline duration text value
    */
   public String getBaselineDurationText(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_DURATIONS, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_DURATIONS, baselineNumber));
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline duration text value.
    *
    * @param baselineNumber baseline number
    * @param value baseline duration text value
    */
   public void setBaselineDurationText(int baselineNumber, String value)
   {
      set(selectField(TaskFieldLists.BASELINE_DURATIONS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Date getBaselineFinish(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_FINISHES, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_FINISHES, baselineNumber));
      }

      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Retrieves the baseline finish text value.
    *
    * @param baselineNumber baseline number
    * @return baseline finish text value
    */
   public String getBaselineFinishText(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_FINISHES, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_FINISHES, baselineNumber));
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline finish text value.
    *
    * @param baselineNumber baseline number
    * @param value baseline finish text value
    */
   public void setBaselineFinishText(int baselineNumber, String value)
   {
      set(selectField(TaskFieldLists.BASELINE_FINISHES, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Date getBaselineStart(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_STARTS, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_STARTS, baselineNumber));
      }

      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Retrieves the baseline start text value.
    *
    * @param baselineNumber baseline number
    * @return baseline start text value
    */
   public String getBaselineStartText(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_STARTS, baselineNumber));
      if (result == null)
      {
         result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_STARTS, baselineNumber));
      }

      if (!(result instanceof String))
      {
         result = null;
      }
      return (String) result;
   }

   /**
    * Sets the baseline start text value.
    *
    * @param baselineNumber baseline number
    * @param value baseline start text value
    */
   public void setBaselineStartText(int baselineNumber, String value)
   {
      set(selectField(TaskFieldLists.BASELINE_STARTS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Duration getBaselineWork(int baselineNumber)
   {
      return ((Duration) getCachedValue(selectField(TaskFieldLists.BASELINE_WORKS, baselineNumber)));
   }

   /**
    * Retrieve the "complete through" date.
    *
    * @return complete through date
    */
   public Date getCompleteThrough()
   {
      Date value = (Date) getCachedValue(TaskField.COMPLETE_THROUGH);
      if (value == null)
      {
         int percentComplete = NumberHelper.getInt(getPercentageComplete());
         switch (percentComplete)
         {
            case 0:
            {
               break;
            }

            case 100:
            {
               value = getActualFinish();
               break;
            }

            default:
            {
               Date actualStart = getActualStart();
               Duration duration = getDuration();
               if (actualStart != null && duration != null)
               {
                  double durationValue = (duration.getDuration() * percentComplete) / 100d;
                  duration = Duration.getInstance(durationValue, duration.getUnits());
                  ProjectCalendar calendar = getEffectiveCalendar();
                  value = calendar.getDate(actualStart, duration, true);
               }
               break;
            }
         }

         set(TaskField.COMPLETE_THROUGH, value);
      }
      return value;
   }

   /**
    * Retrieve the summary progress date.
    *
    * @return summary progress date
    */
   public Date getSummaryProgress()
   {
      Date value = (Date) getCachedValue(TaskField.SUMMARY_PROGRESS);
      return value;
   }

   /**
    * Set the summary progress date.
    *
    * @param value summary progress date
    */
   public void setSummaryProgress(Date value)
   {
      set(TaskField.SUMMARY_PROGRESS, value);
   }

   /**
    * Retrieve the task GUID.
    *
    * @return task GUID
    */
   public UUID getGUID()
   {
      return (UUID) getCachedValue(TaskField.GUID);
   }

   /**
    * Set the task GUID.
    *
    * @param value task GUID
    */
   public void setGUID(UUID value)
   {
      set(TaskField.GUID, value);
   }

   /**
    * Retrieves the task mode.
    *
    * @return task mode
    */
   public TaskMode getTaskMode()
   {
      return BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.TASK_MODE)) ? TaskMode.MANUALLY_SCHEDULED : TaskMode.AUTO_SCHEDULED;
   }

   /**
    * Sets the task mode.
    *
    * @param mode task mode
    */
   public void setTaskMode(TaskMode mode)
   {
      set(TaskField.TASK_MODE, mode == TaskMode.MANUALLY_SCHEDULED);
   }

   /**
    * Retrieves the active flag.
    *
    * @return active flag value
    */
   public boolean getActive()
   {
      return (BooleanHelper.getBoolean((Boolean) getCachedValue(TaskField.ACTIVE)));
   }

   /**
    * Sets the active flag.
    *
    * @param active active flag value
    */
   public void setActive(boolean active)
   {
      set(TaskField.ACTIVE, active);
   }

   /**
    * Retrieve the baseline estimated duration.
    *
    * @return baseline estimated duration
    */
   public Duration getBaselineEstimatedDuration()
   {
      return (Duration) getCachedValue(TaskField.BASELINE_ESTIMATED_DURATION);
   }

   /**
    * Set the baseline estimated duration.
    *
    * @param duration baseline estimated duration
    */
   public void setBaselineEstimatedDuration(Duration duration)
   {
      set(TaskField.BASELINE_ESTIMATED_DURATION, duration);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineEstimatedDuration(int baselineNumber, Duration value)
   {
      set(selectField(TaskFieldLists.BASELINE_ESTIMATED_DURATIONS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Duration getBaselineEstimatedDuration(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_DURATIONS, baselineNumber));
      if (!(result instanceof Duration))
      {
         result = null;
      }
      return (Duration) result;
   }

   /**
    * Retrieve the baseline estimated start.
    *
    * @return baseline estimated start
    */
   public Date getBaselineEstimatedStart()
   {
      return (Date) getCachedValue(TaskField.BASELINE_ESTIMATED_START);
   }

   /**
    * Set the baseline estimated start.
    *
    * @param date baseline estimated start
    */
   public void setBaselineEstimatedStart(Date date)
   {
      set(TaskField.BASELINE_ESTIMATED_START, date);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Date getBaselineEstimatedStart(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_STARTS, baselineNumber));
      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineEstimatedStart(int baselineNumber, Date value)
   {
      set(selectField(TaskFieldLists.BASELINE_ESTIMATED_STARTS, baselineNumber), value);
   }

   /**
    * Retrieve the baseline estimated finish.
    *
    * @return baseline estimated finish
    */
   public Date getBaselineEstimatedFinish()
   {
      return (Date) getCachedValue(TaskField.BASELINE_ESTIMATED_FINISH);
   }

   /**
    * Set the baseline estimated finish.
    *
    * @param date baseline estimated finish
    */
   public void setBaselineEstimatedFinish(Date date)
   {
      set(TaskField.BASELINE_ESTIMATED_FINISH, date);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Date getBaselineEstimatedFinish(int baselineNumber)
   {
      Object result = getCachedValue(selectField(TaskFieldLists.BASELINE_ESTIMATED_FINISHES, baselineNumber));
      if (!(result instanceof Date))
      {
         result = null;
      }
      return (Date) result;
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineEstimatedFinish(int baselineNumber, Date value)
   {
      set(selectField(TaskFieldLists.BASELINE_ESTIMATED_FINISHES, baselineNumber), value);
   }

   /**
    * The Fixed Cost field shows any task expense that is not associated
    * with a resource cost.
    *
    * @param val amount
    */
   public void setBaselineFixedCost(Number val)
   {
      set(TaskField.BASELINE_FIXED_COST, val);
   }

   /**
    * The Fixed Cost field shows any task expense that is not associated
    * with a resource cost.
    *
    * @return currency amount
    */
   public Number getBaselineFixedCost()
   {
      return ((Number) getCachedValue(TaskField.BASELINE_FIXED_COST));
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineFixedCost(int baselineNumber, Number value)
   {
      set(selectField(TaskFieldLists.BASELINE_FIXED_COSTS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public Number getBaselineFixedCost(int baselineNumber)
   {
      return ((Number) getCachedValue(selectField(TaskFieldLists.BASELINE_FIXED_COSTS, baselineNumber)));
   }

   /**
    * Retrieves the baseline fixed cost accrual.
    *
    * @return fixed cost accrual flag
    */
   public AccrueType getBaselineFixedCostAccrual()
   {
      return ((AccrueType) getCachedValue(TaskField.BASELINE_FIXED_COST_ACCRUAL));
   }

   /**
    * Sets the baseline fixed cost accrual.
    *
    * @param type fixed cost accrual type
    */
   public void setBaselineFixedCostAccrual(AccrueType type)
   {
      set(TaskField.BASELINE_FIXED_COST_ACCRUAL, type);
   }

   /**
    * Set a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @param value baseline value
    */
   public void setBaselineFixedCostAccrual(int baselineNumber, AccrueType value)
   {
      set(selectField(TaskFieldLists.BASELINE_FIXED_COST_ACCRUALS, baselineNumber), value);
   }

   /**
    * Retrieve a baseline value.
    *
    * @param baselineNumber baseline index (1-10)
    * @return baseline value
    */
   public AccrueType getBaselineFixedCostAccrual(int baselineNumber)
   {
      return ((AccrueType) getCachedValue(selectField(TaskFieldLists.BASELINE_FIXED_COST_ACCRUALS, baselineNumber)));
   }

   /**
    * Retrieve expense items for this task.
    *
    * @return list of expense items
    */
   @SuppressWarnings("unchecked") public List getExpenseItems()
   {
      return (List) getCachedValue(TaskField.EXPENSE_ITEMS);
   }

   /**
    * Set the expense items for this task.
    *
    * @param items list of expense items
    */
   public void setExpenseItems(List items)
   {
      set(TaskField.EXPENSE_ITEMS, items);
   }

   /**
    * Retrieve the effective calendar for this task. If the task does not have
    * a specific calendar associated with it, fall back to using the default calendar
    * for the project.
    *
    * @return ProjectCalendar instance
    */
   public ProjectCalendar getEffectiveCalendar()
   {
      ProjectCalendar result = getCalendar();
      if (result == null)
      {
         result = getParentFile().getDefaultCalendar();
      }
      return result;
   }

   /**
    * This method allows a predecessor relationship to be removed from this
    * task instance.  It will only delete relationships that exactly match the
    * given targetTask, type and lag time.
    *
    * @param targetTask the predecessor task
    * @param type relation type
    * @param lag relation lag
    * @return returns true if the relation is found and removed
    */
   public boolean removePredecessor(Task targetTask, RelationType type, Duration lag)
   {
      boolean matchFound = false;

      //
      // Retrieve the list of predecessors
      //
      List predecessorList = getPredecessors();
      if (!predecessorList.isEmpty())
      {
         //
         // Ensure that we have a valid lag duration
         //
         if (lag == null)
         {
            lag = Duration.getInstance(0, TimeUnit.DAYS);
         }

         //
         // Ensure that there is a predecessor relationship between
         // these two tasks, and remove it.
         //
         matchFound = removeRelation(predecessorList, targetTask, type, lag);

         //
         // If we have removed a predecessor, then we must remove the
         // corresponding successor entry from the target task list
         //
         if (matchFound)
         {
            //
            // Retrieve the list of successors
            //
            List successorList = targetTask.getSuccessors();
            if (!successorList.isEmpty())
            {
               //
               // Ensure that there is a successor relationship between
               // these two tasks, and remove it.
               //
               removeRelation(successorList, this, type, lag);
            }
         }
      }

      return matchFound;
   }

   /**
    * Internal method used to locate an remove an item from a list Relations.
    *
    * @param relationList list of Relation instances
    * @param targetTask target relationship task
    * @param type target relationship type
    * @param lag target relationship lag
    * @return true if a relationship was removed
    */
   private boolean removeRelation(List relationList, Task targetTask, RelationType type, Duration lag)
   {
      boolean matchFound = false;
      for (Relation relation : relationList)
      {
         if (relation.getTargetTask() == targetTask)
         {
            if (relation.getType() == type && relation.getLag().compareTo(lag) == 0)
            {
               matchFound = relationList.remove(relation);
               break;
            }
         }
      }
      return matchFound;
   }

   /**
    * Maps a field index to a TaskField instance.
    *
    * @param fields array of fields used as the basis for the mapping.
    * @param index required field index
    * @return TaskField instance
    */
   private TaskField selectField(TaskField[] fields, int index)
   {
      if (index < 1 || index > fields.length)
      {
         throw new IllegalArgumentException(index + " is not a valid field index");
      }
      return (fields[index - 1]);
   }

   /**
    * {@inheritDoc}
    */
   @Override public Object getCachedValue(FieldType field)
   {
      return (field == null ? null : m_array[field.getValue()]);
   }

   /**
    * {@inheritDoc}
    */
   @Override public Object getCurrentValue(FieldType field)
   {
      Object result = null;

      if (field != null)
      {
         switch ((TaskField) field)
         {
            case PARENT_TASK_UNIQUE_ID:
            {
               result = m_parent == null ? Integer.valueOf(-1) : m_parent.getUniqueID();
               break;
            }

            case START_VARIANCE:
            {
               result = getStartVariance();
               break;
            }

            case FINISH_VARIANCE:
            {
               result = getFinishVariance();
               break;
            }

            case START_SLACK:
            {
               result = getStartSlack();
               break;
            }

            case FINISH_SLACK:
            {
               result = getFinishSlack();
               break;
            }

            case COST_VARIANCE:
            {
               result = getCostVariance();
               break;
            }

            case DURATION_VARIANCE:
            {
               result = getDurationVariance();
               break;
            }

            case WORK_VARIANCE:
            {
               result = getWorkVariance();
               break;
            }

            case CV:
            {
               result = getCV();
               break;
            }

            case SV:
            {
               result = getSV();
               break;
            }

            case TOTAL_SLACK:
            {
               result = getTotalSlack();
               break;
            }

            case CRITICAL:
            {
               result = Boolean.valueOf(getCritical());
               break;
            }

            case COMPLETE_THROUGH:
            {
               result = getCompleteThrough();
               break;
            }

            default:
            {
               result = m_array[field.getValue()];
               break;
            }
         }
      }

      return (result);
   }

   /**
    * {@inheritDoc}
    */
   @Override public void set(FieldType field, Object value)
   {
      if (field != null)
      {
         int index = field.getValue();
         if (m_eventsEnabled)
         {
            fireFieldChangeEvent((TaskField) field, m_array[index], value);
         }
         m_array[index] = value;
      }
   }

   /**
    * Handle the change in a field value. Reset any cached calculated
    * values affected by this change, pass on the event to any external
    * listeners.
    *
    * @param field field changed
    * @param oldValue old field value
    * @param newValue new field value
    */
   private void fireFieldChangeEvent(TaskField field, Object oldValue, Object newValue)
   {
      //
      // Internal event handling
      //
      switch (field)
      {
         case UNIQUE_ID:
         {
            ProjectFile parent = getParentFile();
            if (oldValue != null)
            {
               parent.getTasks().unmapUniqueID((Integer) oldValue);
            }
            parent.getTasks().mapUniqueID((Integer) newValue, this);
            break;
         }

         case START:
         case BASELINE_START:
         {
            m_array[TaskField.START_VARIANCE.getValue()] = null;
            break;
         }

         case FINISH:
         case BASELINE_FINISH:
         {
            m_array[TaskField.FINISH_VARIANCE.getValue()] = null;
            break;
         }

         case COST:
         case BASELINE_COST:
         {
            m_array[TaskField.COST_VARIANCE.getValue()] = null;
            break;
         }

         case DURATION:
         {
            m_array[TaskField.DURATION_VARIANCE.getValue()] = null;
            m_array[TaskField.COMPLETE_THROUGH.getValue()] = null;
            break;
         }

         case BASELINE_DURATION:
         {
            m_array[TaskField.DURATION_VARIANCE.getValue()] = null;
            break;
         }

         case WORK:
         case BASELINE_WORK:
         {
            m_array[TaskField.WORK_VARIANCE.getValue()] = null;
            break;
         }

         case BCWP:
         case ACWP:
         {
            m_array[TaskField.CV.getValue()] = null;
            m_array[TaskField.SV.getValue()] = null;
            break;
         }

         case BCWS:
         {
            m_array[TaskField.SV.getValue()] = null;
            break;
         }

         case START_SLACK:
         case FINISH_SLACK:
         {
            m_array[TaskField.TOTAL_SLACK.getValue()] = null;
            m_array[TaskField.CRITICAL.getValue()] = null;
            break;
         }

         case EARLY_FINISH:
         case LATE_FINISH:
         {
            m_array[TaskField.FINISH_SLACK.getValue()] = null;
            m_array[TaskField.TOTAL_SLACK.getValue()] = null;
            m_array[TaskField.CRITICAL.getValue()] = null;
            break;
         }

         case EARLY_START:
         case LATE_START:
         {
            m_array[TaskField.START_SLACK.getValue()] = null;
            m_array[TaskField.TOTAL_SLACK.getValue()] = null;
            m_array[TaskField.CRITICAL.getValue()] = null;
            break;
         }

         case ACTUAL_START:
         case PERCENT_COMPLETE:
         {
            m_array[TaskField.COMPLETE_THROUGH.getValue()] = null;
            break;
         }

         default:
         {
            break;
         }
      }

      //
      // External event handling
      //
      if (m_listeners != null)
      {
         for (FieldListener listener : m_listeners)
         {
            listener.fieldChange(this, field, oldValue, newValue);
         }
      }
   }

   /**
    * {@inheritDoc}
    */
   @Override public void addFieldListener(FieldListener listener)
   {
      if (m_listeners == null)
      {
         m_listeners = new ArrayList<>();
      }
      m_listeners.add(listener);
   }

   /**
    * {@inheritDoc}
    */
   @Override public void removeFieldListener(FieldListener listener)
   {
      if (m_listeners != null)
      {
         m_listeners.remove(listener);
      }
   }

   /**
    * This method inserts a name value pair into internal storage.
    *
    * @param field task field
    * @param value attribute value
    */
   private void set(FieldType field, boolean value)
   {
      set(field, (value ? Boolean.TRUE : Boolean.FALSE));
   }

   /**
    * {@inheritDoc}
    */
   @Override public String toString()
   {
      return ("[Task id=" + getID() + " uniqueID=" + getUniqueID() + " name=" + getName() + (getExternalTask() ? " [EXTERNAL uid=" + getSubprojectTaskUniqueID() + " id=" + getSubprojectTaskID() + "]" : "]") + (getSubProject() == null ? "" : (" project=" + getSubProject())));
   }

   /**
    * Utility method used to determine if the supplied task
    * is a predecessor of the current task.
    *
    * @param task potential predecessor task
    * @return Boolean flag
    */
   public boolean isPredecessor(Task task)
   {
      return isRelated(task, getPredecessors());
   }

   /**
    * Utility method used to determine if the supplied task
    * is a successor of the current task.
    *
    * @param task potential successor task
    * @return Boolean flag
    */
   public boolean isSucessor(Task task)
   {
      return isRelated(task, getSuccessors());
   }

   /**
    * Used to determine if a task has child tasks.
    *
    * @return true if the task has child tasks
    */
   public boolean hasChildTasks()
   {
      return !m_children.isEmpty();
   }

   /**
    * Internal method used to test for the existence of a relationship
    * with a task.
    *
    * @param task target task
    * @param list list of relationships
    * @return boolean flag
    */
   private boolean isRelated(Task task, List list)
   {
      boolean result = false;
      for (Relation relation : list)
      {
         if (relation.getTargetTask().getUniqueID().intValue() == task.getUniqueID().intValue())
         {
            result = true;
            break;
         }
      }
      return result;
   }

   /**
    * Disable events firing when fields are updated.
    */
   public void disableEvents()
   {
      m_eventsEnabled = false;
   }

   /**
    * Enable events firing when fields are updated. This is the default state.
    */
   public void enableEvents()
   {
      m_eventsEnabled = true;
   }

   /**
    * Array of field values.
    */
   private Object[] m_array = new Object[TaskField.MAX_VALUE];

   /**
    * This is a reference to the parent task, as specified by the
    * outline level.
    */
   private Task m_parent;

   /**
    * This list holds references to all tasks that are children of the
    * current task as specified by the outline level.
    */
   private List m_children = new ArrayList<>();

   /**
    * List of resource assignments for this task.
    */
   private List m_assignments = new ArrayList<>();

   /**
    * List of activity codes for this task.
    */
   private List m_activityCodes = new ArrayList<>();

   /**
    * Recurring task details associated with this task.
    */
   private RecurringTask m_recurringTask;

   private boolean m_eventsEnabled = true;
   private boolean m_null;
   private boolean m_resumeValid;
   private String m_externalTaskProject;
   private boolean m_expanded = true;
   private List m_listeners;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy