View Javadoc
1   package de.fhdw.wtf.context.model.collections;
2   
3   import java.util.Iterator;
4   import java.util.ListIterator;
5   import java.util.Vector;
6   
7   import de.fhdw.wtf.context.exception.FrameworkException;
8   import de.fhdw.wtf.context.model.Anything;
9   import de.fhdw.wtf.context.model.collections.functors.EquivalenceRelation;
10  import de.fhdw.wtf.context.model.collections.functors.Function;
11  import de.fhdw.wtf.context.model.collections.functors.Operator;
12  import de.fhdw.wtf.context.model.collections.functors.Predicate;
13  
14  /**
15   * An ImmutableList represents a List with an immutable list as backend.
16   * 
17   * @param <T>
18   *            The underlying element type.
19   */
20  public class ImmutableList<T extends Anything> implements ImmutableCollection<T> {
21  	
22  	/**
23  	 * The underlying list.
24  	 */
25  	private final java.util.List<T> elements;
26  	
27  	/**
28  	 * Creates an empty ImmutableList.
29  	 */
30  	public ImmutableList() {
31  		this.elements = new Vector<>();
32  	}
33  	
34  	@Override
35  	public Collection<T> union(final Collection<? extends T> otherCollection) {
36  		final ImmutableList<T> result = new ImmutableList<>();
37  		result.elements.addAll(this.elements);
38  		if (otherCollection instanceof ImmutableCollection) {
39  			result.addImmutableCollection((ImmutableCollection<? extends T>) otherCollection);
40  		} else if (otherCollection instanceof MutableCollection) {
41  			result.addMutableCollection(otherCollection);
42  		} else {
43  			throw new FrameworkException("collection not supported");
44  		}
45  		return result;
46  	}
47  	
48  	/**
49  	 * Adds the elements of a MutableCollection to this list.
50  	 * 
51  	 * @param otherCollection
52  	 *            The MutableCollection.
53  	 */
54  	private void addMutableCollection(final Collection<? extends T> otherCollection) {
55  		final Iterator<? extends T> iterator = ((MutableCollection<? extends T>) otherCollection).iterator();
56  		while (iterator.hasNext()) {
57  			final T current = iterator.next();
58  			this.elements.add(current);
59  		}
60  	}
61  	
62  	/**
63  	 * Adds the elements of an ImmutableCollection to this list.
64  	 * 
65  	 * @param otherCollection
66  	 *            The ImmutableCollection.
67  	 */
68  	private void addImmutableCollection(final ImmutableCollection<? extends T> otherCollection) {
69  		if (!otherCollection.isEmpty()) {
70  			this.elements.add(otherCollection.front());
71  			this.addImmutableCollection(otherCollection.tail());
72  		}
73  	}
74  	
75  	@Override
76  	public boolean contains(final T element) {
77  		return this.elements.contains(element);
78  	}
79  	
80  	@Override
81  	public ImmutableCollection<T> add(final T element) {
82  		final ImmutableList<T> result = new ImmutableList<>();
83  		result.elements.addAll(this.elements);
84  		result.elements.add(element);
85  		return result;
86  	}
87  	
88  	@Override
89  	public T front() {
90  		return this.elements.get(0);
91  	}
92  	
93  	@Override
94  	public ImmutableCollection<T> tail() {
95  		final ImmutableList<T> result = new ImmutableList<>();
96  		result.elements.addAll(this.elements);
97  		result.elements.remove(0);
98  		return result;
99  	}
100 	
101 	@Override
102 	public ImmutableCollection<T> reverse() {
103 		final ImmutableList<T> result = new ImmutableList<>();
104 		final ListIterator<T> iterator = this.elements.listIterator(this.elements.size());
105 		while (iterator.hasPrevious()) {
106 			final T current = iterator.previous();
107 			result.elements.add(current);
108 		}
109 		return result;
110 	}
111 	
112 	@Override
113 	public <U extends Anything> ImmutableCollection<U> map(final Function<T, U> function) {
114 		final ImmutableList<U> result = new ImmutableList<>();
115 		final Iterator<T> iterator = this.elements.iterator();
116 		while (iterator.hasNext()) {
117 			final T current = iterator.next();
118 			result.elements.add(function.f(current));
119 		}
120 		return result;
121 	}
122 	
123 	@Override
124 	public <U extends Anything> U reduce(final Operator<T, U> aggregation) {
125 		U result = aggregation.n();
126 		final Iterator<T> iterator = this.elements.iterator();
127 		while (iterator.hasNext()) {
128 			final T current = iterator.next();
129 			result = aggregation.add(result, current);
130 		}
131 		return result;
132 	}
133 	
134 	@Override
135 	public <U extends Anything> ImmutableCollection<U> reduceEquivalent(final EquivalenceRelation<T> equi,
136 			final Operator<T, U> aggregation) {
137 		final Vector<ImmutableList<T>> between = new Vector<>();
138 		final Iterator<T> outerIterator = this.elements.iterator();
139 		while (outerIterator.hasNext()) {
140 			final T current = outerIterator.next();
141 			final ImmutableList<T> currentList = new ImmutableList<>();
142 			final Iterator<T> innerIterator = this.elements.iterator();
143 			while (innerIterator.hasNext()) {
144 				final T innerCurrent = innerIterator.next();
145 				if (equi.equivalent(current, innerCurrent)) {
146 					currentList.add(innerCurrent);
147 				}
148 			}
149 			between.add(currentList);
150 		}
151 		final ImmutableList<U> result = new ImmutableList<>();
152 		while (!between.isEmpty()) {
153 			final ImmutableList<T> current = between.get(0);
154 			between.remove(0);
155 			final Iterator<ImmutableList<T>> iterator = between.iterator();
156 			while (iterator.hasNext()) {
157 				final ImmutableList<T> innerCurrent = iterator.next();
158 				if (innerCurrent.equals(current)) {
159 					iterator.remove();
160 				}
161 			}
162 			result.elements.add(current.reduce(aggregation));
163 		}
164 		return result;
165 	}
166 	
167 	@Override
168 	public ImmutableCollection<T> filter(final Predicate<T> predicate) {
169 		final ImmutableList<T> result = new ImmutableList<>();
170 		final Iterator<T> iterator = this.elements.iterator();
171 		while (iterator.hasNext()) {
172 			final T current = iterator.next();
173 			if (predicate.p(current)) {
174 				result.elements.add(current);
175 			}
176 		}
177 		return result;
178 	}
179 	
180 	@Override
181 	public T find(final Predicate<T> predicate) {
182 		final ImmutableCollection<T> preResult = this.filter(predicate);
183 		if (preResult.isEmpty()) {
184 			return null;
185 		}
186 		return preResult.front();
187 	}
188 	
189 	@Override
190 	public String toString() {
191 		return this.elements.toString();
192 	}
193 	
194 	@Override
195 	public boolean equals(final Object obj) {
196 		if (!(obj instanceof ImmutableList<?>)) {
197 			return false;
198 		}
199 		
200 		final ImmutableList<?> other = (ImmutableList<?>) obj;
201 		
202 		return this.elements.equals(other.elements);
203 	}
204 	
205 	@Override
206 	public int hashCode() {
207 		return this.elements.hashCode();
208 	}
209 	
210 	@Override
211 	public boolean isEmpty() {
212 		return this.elements.isEmpty();
213 	}
214 	
215 }