package com.whatstodo.models; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Random; import com.whatstodo.dtos.ListDTO; import com.whatstodo.dtos.TaskDTO; /** * The list class represents a list of tasks. It is ordered in the natural order * of the tasks or with an optional comparator * * @author alex * */ public class List implements Serializable, java.util.List<Task> { private static final long serialVersionUID = -2889639373188534039L; private int size; private Task[] orderedTasks; private Comparator<Task> comparator; private long id; private String name; public List() { id = Math.abs(new Random().nextLong()); orderedTasks = new Task[1]; } public List(String name) { this(); this.name = name; } public List(String name, Comparator<Task> comparator) { this(name); this.comparator = comparator; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public Task addTask(String name) { Task task = new Task(name); add(task); //adding the task should give it the list id return task; } public Task getTask(long taskId) { for (Task task : this) { if (task.getId() == taskId) { return task; } } throw new NoSuchElementException("Cannot find task with ID: " + taskId); } // Insertion sort public void sort() { int N = size; for (int i = 0; i < N; i++) { for (int j = i; j > 0 && less(orderedTasks[j], orderedTasks[j - 1]); j--) { exch(orderedTasks, j, j - 1); } } } private void exch(Object[] a, int i, int j) { Object swap = a[i]; a[i] = a[j]; a[j] = swap; } @Override public boolean isEmpty() { return size == 0; } @Override public int size() { return size; } @Override public Iterator<Task> iterator() { return new ListIterator(); } @Override public void add(int location, Task task) { // TODO Maybe call add(Task) throw new UnsupportedOperationException("List.add(int, Task)"); } @Override public boolean add(Task task) { task.setListId(id); // double size of array if necessary if (size == orderedTasks.length - 1) resize(2 * orderedTasks.length); // Add item int i = size - 1; while (i >= 0 && less(task, orderedTasks[i])) { orderedTasks[i + 1] = orderedTasks[i]; i--; } orderedTasks[i + 1] = task; size++; return true; } @Override public boolean addAll(int location, Collection<? extends Task> collection) { // TODO Maybe call addAll(Collection) throw new UnsupportedOperationException("List.addAll(int, Collection)"); } @Override public boolean addAll(Collection<? extends Task> collection) { for (Task newTask : collection) { add(newTask); } return true; } @Override public void clear() { for (int i = 0; i < size; i++) { orderedTasks[i] = null; } size = 0; } @Override public boolean contains(Object object) { return indexOf(object) >= 0; } @Override public boolean containsAll(Collection<?> collection) { for (Object object : collection) { if (!contains(object)) return false; } return true; } @Override public Task get(int location) { checkBound(location); return orderedTasks[location]; } @Override public int indexOf(Object object) { for (int i = 0; i < size; i++) { if (orderedTasks[i].equals(object)) { return i; } } return -1; } @Override public int lastIndexOf(Object object) { for (int i = size; i >= 0; i++) { if (orderedTasks[i].equals(object)) { return i; } } return -1; } @Override public java.util.ListIterator<Task> listIterator() { throw new UnsupportedOperationException("List.listIterator"); } @Override public java.util.ListIterator<Task> listIterator(int location) { throw new UnsupportedOperationException("List.listIterator(int)"); } @Override public Task remove(int location) { if (isEmpty()) throw new NoSuchElementException("Underflow"); Task toReturn = orderedTasks[location]; size--; for (int i = location; i < size; i++) { orderedTasks[i] = orderedTasks[i + 1]; } orderedTasks[size + 1] = null; // avoid loitering and help with garbage // collection // resize array if ((size > 0) && (size == (orderedTasks.length - 1) / 4)) resize(orderedTasks.length / 2); return toReturn; } @Override public boolean remove(Object object) { int indexOf = indexOf(object); if (indexOf >= 0) { remove(indexOf); return true; } else return false; } @Override public boolean removeAll(Collection<?> collection) { boolean changed = false; for (Object object : collection) { if (remove(object)) { changed = true; } } return changed; } @Override public boolean retainAll(Collection<?> collection) { throw new UnsupportedOperationException( "List.retainAll((Collection<?>)"); } @Override public Task set(int location, Task object) { throw new UnsupportedOperationException("List.set(int, Task)"); } @Override public java.util.List<Task> subList(int start, int end) { throw new UnsupportedOperationException("List.subList(int, int)"); } @Override public Object[] toArray() { return orderedTasks; } @SuppressWarnings("unchecked") @Override public <T> T[] toArray(T[] array) { T[] toReturn = null; if (array.length >= size) { toReturn = array; } else { toReturn = (T[]) new Object[size]; } int i = 0; for (Task task : this) { toReturn[i++] = (T) task; } for (; i < toReturn.length; i++) { toReturn[i] = null; } return toReturn; } private boolean less(Task i, Task j) { if (comparator == null) { return i.compareTo(j) < 0; } else { return comparator.compare(i, j) < 0; } } private void checkBound(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index " + index + ", Size" + size); } private void resize(int capacity) { assert capacity > size; Task[] temp = new Task[capacity]; for (int i = 0; i <= size; i++) temp[i] = orderedTasks[i]; orderedTasks = temp; } private class ListIterator implements Iterator<Task> { private int i; public ListIterator() { i = 0; } @Override public boolean hasNext() { return i < size; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public Task next() { if (!hasNext()) throw new NoSuchElementException(); return orderedTasks[i++]; } } /** * Serializes this object to the given stream. * * @param s * the stream to write to * @throws IOException * if the underlying stream fails * @serialData the size of the list (int), followed by all the elements * (Object) in proper order */ private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); s.writeInt(size); for (int i = size - 1; i >= 0; i--) { s.writeObject(orderedTasks[i]); } } /** * Deserializes this object from the given stream. * * @param s * the stream to read from * @throws ClassNotFoundException * if the underlying stream fails * @throws IOException * if the underlying stream fails * @serialData the size of the list (int), followed by all the elements * (Object) in proper order */ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); int i = s.readInt(); size = i; if (size < 1) { orderedTasks = new Task[1]; } else { orderedTasks = new Task[i + 1]; } while (--i >= 0) orderedTasks[i] = ((Task) s.readObject()); } public static ListDTO toDTO(List list){ ListDTO listDTO = new ListDTO(); listDTO.setId(list.id); listDTO.setName(list.name); listDTO.setSize(list.size); TaskDTO[] tasks = new TaskDTO[list.size]; for (int i = 0; i < list.size; i++){ tasks[i] = Task.toDTO(list.orderedTasks[i]); } listDTO.setTasks(tasks); return listDTO; } public static List fromDTO(ListDTO listDTO){ List list = new List(); list.id = listDTO.getId(); list.name = listDTO.getName(); TaskDTO[] tasksDTO = listDTO.getTasks(); //list.orderedTasks = new Task[list.size]; for (int i = 0; i < listDTO.getSize(); i++){ list.add(Task.fromDTO(tasksDTO[i])); } list.sort(); return list; } public void setSize(int size) { this.size = size; } }