net.chaosserver.timelord.data.TimelordTask.java Source code

Java tutorial

Introduction

Here is the source code for net.chaosserver.timelord.data.TimelordTask.java

Source

/*
This file is part of Timelord.
Copyright 2005-2009 Jordan Reed
    
Timelord is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
Timelord is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with Timelord.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.chaosserver.timelord.data;

import net.chaosserver.timelord.util.DateUtil;
import net.chaosserver.timelord.util.PropertyChangeSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.PropertyChangeListener;

import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Representation of a task inside of timelord. Underneath the task object
 * are individual task days to indicate data for a day. For synchronization
 * purposes, anything that modifies the taskDayList property should be
 * synchronized on the object itself.
 */
public class TimelordTask implements Cloneable {
    /** Logger. */
    private static Log log = LogFactory.getLog(TimelordTask.class);

    /** Max Listeners. */
    private static final int MAX_LISTENERS = 3;

    /** Property Change Support. */
    protected PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this, MAX_LISTENERS);

    /** The name of the task. */
    protected String taskName;

    /** Flags if the task is exportable. */
    protected boolean exportable = true;

    /** Flag if the task has been marked hidden. */
    protected boolean hidden = false;

    /** List of task days associated for this task. */
    protected LinkedList<TimelordTaskDay> taskDayList;

    /** Default constructor. */
    public TimelordTask() {
        taskDayList = new LinkedList<TimelordTaskDay>();

        if (log.isDebugEnabled()) {
            log.debug("Created a new TimelordTask");
        }
    }

    /**
     * Creates a new Task with a given name.
     *
     * @param taskName the name of the new task
     */
    public TimelordTask(String taskName) {
        this();
        setTaskName(taskName);

        if (log.isDebugEnabled()) {
            log.debug("Created a new TimelordTask [" + taskName + "]");
        }
    }

    /**
     * Setter for the name of the task.
     *
     * @param taskName the new name of the task
     */
    public void setTaskName(String taskName) {
        String oldTaskName = this.taskName;
        this.taskName = taskName;
        propertyChangeSupport.firePropertyChange("taskName", oldTaskName, this.taskName);
    }

    /**
     * Getter for the name of the task.
     *
     * @return the name of the task
     */
    public String getTaskName() {
        return this.taskName;
    }

    /**
     * Sets the exportable flag.
     *
     * @param exportable is the item exportable
     */
    public void setExportable(boolean exportable) {
        boolean oldExportable = this.exportable;
        this.exportable = exportable;
        propertyChangeSupport.firePropertyChange("exportable", oldExportable, this.exportable);
    }

    /**
     * Gets the exportable flag. When exporting this object to any non-internal
     * format, this field should not be sent.
     *
     * @return if the item is exportable.
     */
    public boolean isExportable() {
        return this.exportable;
    }

    /**
     * Sets the hidden flag.
     *
     * @param hidden the hidden flag
     */
    public void setHidden(boolean hidden) {
        this.hidden = hidden;
        propertyChangeSupport.firePropertyChange("hidden", !this.hidden, this.hidden);
    }

    /**
     * Gets the hidden flag.
     *
     * @return the hidden flag
     */
    public boolean isHidden() {
        return this.hidden;
    }

    /**
     * Sets the task day list for the object.
     *
     * @param taskDayList the new task day list
     */
    public synchronized void setTaskDayList(List<TimelordTaskDay> taskDayList) {
        if (taskDayList instanceof LinkedList) {
            this.taskDayList = (LinkedList<TimelordTaskDay>) taskDayList;
        } else {
            this.taskDayList = new LinkedList<TimelordTaskDay>(taskDayList);
        }
    }

    /**
     * Gets the list of task days. The list consists of TimelordTaskDay
     * objects. Only one object per day should be in the list and it is sorted
     * so that the most recent item comes at the start of the list.
     * This method is meant for serialization and no direct manipulations of the
     * list should be made.
     *
     * @return the task day list
     */
    public List<TimelordTaskDay> getTaskDayList() {
        return this.taskDayList;
    }

    /**
     * Checks if the task already has some hours tracked for today.
     *
     * @return if there is a task for today
     */
    public boolean isTodayPresent() {
        boolean todayPresent = false;
        List<TimelordTaskDay> taskList = getTaskDayList();

        if ((taskList != null) && !taskList.isEmpty()) {
            Date todayDate = DateUtil.trunc(new Date());

            TimelordTaskDay taskDay = (TimelordTaskDay) taskList.get(0);
            Date taskDayDate = taskDay.getDate();

            if (taskDayDate != null) {
                if (log.isTraceEnabled()) {
                    log.trace("Testing taskDayDate [" + this.getTaskName() + "] [" + taskDayDate.getTime()
                            + "] against today [" + todayDate.getTime() + "]");
                }

                if (taskDayDate.equals(todayDate) || taskDayDate.after(todayDate)) {
                    todayPresent = true;
                }
            } else {
                if (log.isWarnEnabled()) {
                    log.warn("Empty date field.  Removing taskDay.");
                    taskList.remove(taskDay);
                }
            }
        }

        return todayPresent;
    }

    /**
     * Adds a task day for today if one doesn't already exist.
     *
     * @return the newly added task day for today
     */
    public synchronized TimelordTaskDay addToday() {
        if (!isTodayPresent()) {
            TimelordTaskDay timelordTaskDay = new TimelordTaskDay();

            Date todayDate = DateUtil.trunc(new Date());

            timelordTaskDay.setDate(todayDate);
            timelordTaskDay.setHours(0);

            addTaskDay(timelordTaskDay);

            return timelordTaskDay;
        } else {
            return (TimelordTaskDay) taskDayList.getFirst();
        }
    }

    /**
     * Adds a task for particular date.
     *
     * @param date the date to add a task for
     * @return the newly added task day
     */
    public synchronized TimelordTaskDay add(Date date) {
        Date addDate = DateUtil.trunc(date);
        TimelordTaskDay timelordTaskDay = getTaskDay(addDate);

        if (timelordTaskDay == null) {
            timelordTaskDay = new TimelordTaskDay();
            timelordTaskDay.setDate(addDate);
            timelordTaskDay.setHours(0);

            addTaskDay(timelordTaskDay);
        }

        return timelordTaskDay;
    }

    /**
     * Gets the task day for the current date.
     *
     * @return the task day for the current date
     */
    public TimelordTaskDay getToday() {
        addToday();

        return (TimelordTaskDay) taskDayList.getFirst();
    }

    /**
     * Gets the task day for a particular day and returns null if there is no
     * taskDay for that date.
     *
     * @param dateToFind the date to find a taskDay for
     * @return the taskDay for the date given or a null
     */
    public TimelordTaskDay getTaskDay(Date dateToFind) {
        return getTaskDay(dateToFind, false);
    }

    /**
     * Gets the TaskDay object for the date to find.  If the create
     * flag is true, than a new object will be created if there is no
     * existing one.
     *
     * @param dateToFind the date to retrieve the task date object for.
     * @param create should the object be created if one doesn't exist
     * @return the TaskDate for the day, or a null if create is false
     *         and no object currently exists
     */
    public synchronized TimelordTaskDay getTaskDay(Date dateToFind, boolean create) {
        if (log.isDebugEnabled()) {
            log.debug("Searching [" + getTaskName() + "] for date of [" + dateToFind + "]");
        }

        TimelordTaskDay timelordTaskDay = null;

        Iterator<TimelordTaskDay> taskDayListIterator = getTaskDayList().iterator();

        while ((timelordTaskDay == null) && taskDayListIterator.hasNext()) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayListIterator.next();

            if (log.isDebugEnabled()) {
                log.debug("Testing tempTimelordTaskDay.getDate [" + tempTimelordTaskDay.getDate()
                        + "] againt dateToFind of [" + dateToFind + "]");
            }

            if (dateToFind.equals(tempTimelordTaskDay.getDate())) {
                timelordTaskDay = tempTimelordTaskDay;
            } else if (dateToFind.after(tempTimelordTaskDay.getDate())) {
                // If the date to find is after the date we want, then we are
                // DONE.
                break;
            }
        }

        if ((timelordTaskDay == null) && create) {
            if (log.isDebugEnabled()) {
                log.debug("Creating new TimelordTaskDay for [" + dateToFind + "]");
            }

            timelordTaskDay = add(dateToFind);
        }

        return timelordTaskDay;
    }

    /**
     * Adds a new task day object into the proper location in the list.
     *
     * @param timelordTaskDay the day to add
     */
    public synchronized void addTaskDay(TimelordTaskDay timelordTaskDay) {
        Date newTaskDate = timelordTaskDay.getDate();
        boolean added = false;

        for (int i = 0; i < taskDayList.size(); i++) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayList.get(i);

            if (newTaskDate.after(tempTimelordTaskDay.getDate())) {
                taskDayList.add(i, timelordTaskDay);
                added = true;

                break;
            }
        }

        if (!added) {
            taskDayList.addLast(timelordTaskDay);
        }

        propertyChangeSupport.firePropertyChange("taskDayList", null, taskDayList);
    }

    /**
     * Sorts the task list so that newest is always first.
     */
    public synchronized void sort() {
        Collections.sort(getTaskDayList(), new DateTaskComparator());

        if (log.isTraceEnabled()) {
            log.trace("First element of [" + this.getTaskName() + "] is [" + taskDayList.getFirst());
        }
    }

    /**
     * One of the cleanup methods to find any TaskDay that has zero hours and
     * remove it from the list.
     */
    public synchronized void removeEmpty() {
        for (int i = 0; i < taskDayList.size(); i++) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayList.get(i);

            if ((i != 0) && (tempTimelordTaskDay.getHours() == 0)) {
                if (log.isDebugEnabled()) {
                    log.debug("Found a TaskDay with zero hours.  Removing [" + tempTimelordTaskDay + "]");
                }

                taskDayList.remove(i);
                i--;
            }
        }
    }

    /**
     * One of the cleanup methods to find any TaskDay that has zero hours int
     * the future remove it from the list.
     */
    public void removeFuture() {
        for (int i = 0; i < taskDayList.size(); i++) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayList.get(i);

            if (tempTimelordTaskDay.getDate().after(DateUtil.trunc(new Date()))) {

                if (log.isWarnEnabled()) {
                    log.warn("Found a TaskDay that is in the future.  [" + getTaskName() + "] ["
                            + tempTimelordTaskDay + "]");
                }

                taskDayList.remove(i);
                i--;
            }
        }
    }

    /**
     * Removes all task day items in the list that is before
     * the start date.
     *
     * @param startDate the date to remove items before
     * @param endDate the date to remove items after
     */
    public void removeTrackingOutsideRange(Date startDate, Date endDate) {
        for (int i = 0; i < taskDayList.size(); i++) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayList.get(i);

            if (tempTimelordTaskDay.getDate().before(DateUtil.trunc(startDate))) {

                taskDayList.remove(i);
                i--;
            } else if (tempTimelordTaskDay.getDate().after(DateUtil.trunc(endDate))) {

                taskDayList.remove(i);
                i--;
            }
        }
    }

    /**
     * One of the cleanup methods to handle if the time zone is incorrect.
     */
    public synchronized void correctTimeZone() {
        for (int i = 0; i < taskDayList.size(); i++) {
            TimelordTaskDay tempTimelordTaskDay = (TimelordTaskDay) taskDayList.get(i);

            Calendar calendarDate = Calendar.getInstance();

            calendarDate.setTime(tempTimelordTaskDay.getDate());

            if ((calendarDate.get(Calendar.HOUR_OF_DAY) != 0) || (calendarDate.get(Calendar.MINUTE) != 0)
                    || (calendarDate.get(Calendar.SECOND) != 0) || (calendarDate.get(Calendar.MILLISECOND) != 0)) {
                if (log.isWarnEnabled()) {
                    log.warn("Found a TaskDay that is not set a midnight.  [" + getTaskName() + "] ["
                            + tempTimelordTaskDay + "]");
                }

                // taskDayList.remove(i);
                // i--;
            }
        }
    }

    /**
     * Adds a property change listener for a property.
     *
     * @param propertyName property to listen for
     * @param listener listener
     */
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }

    /**
     * Removes a property change listener.
     *
     * @param propertyName the property to listen to
     * @param listener listener
     */
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        if (log.isTraceEnabled()) {
            log.trace("[" + getTaskName() + "] removing PropertyChangeListener [" + listener + "]");
        }

        propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    /**
     * Creates a copy of the object.
     *
     * @return a copy of the object
     */
    public TimelordTask clone() {
        TimelordTask timelordTaskClone = new TimelordTask();

        timelordTaskClone.taskName = this.taskName;
        timelordTaskClone.exportable = this.exportable;
        timelordTaskClone.hidden = this.hidden;

        LinkedList<TimelordTaskDay> taskDayListClone = new LinkedList<TimelordTaskDay>();

        Iterator<TimelordTaskDay> timelordTaskDayIterator = this.taskDayList.iterator();
        while (timelordTaskDayIterator.hasNext()) {
            taskDayListClone.add(timelordTaskDayIterator.next().clone());
        }

        timelordTaskClone.taskDayList = taskDayListClone;
        return timelordTaskClone;
    }

    /**
     * Returns the task name and is used for end-user display.
     *
     * @return the task name
     */
    public String toString() {
        return this.getTaskName();
    }

    /**
     * Date comparator to compare two TimelordTaskDay objects by date.
     */
    protected class DateTaskComparator implements Comparator<TimelordTaskDay> {
        /**
         * Compares two TimelordTaskDay objects by the date property.
         *
         * @param o1 the first
         * @param o2 the second
         * @return if o1's date is less than o2's
         */
        public int compare(TimelordTaskDay o1, TimelordTaskDay o2) {
            TimelordTaskDay t1 = (TimelordTaskDay) o1;
            TimelordTaskDay t2 = (TimelordTaskDay) o2;

            return t2.getDate().compareTo(t1.getDate());
        }
    }
}