20 package net.sf.gridarta.model.baseobject;
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.Serializable;
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.ListIterator;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
49 @SuppressWarnings(
"ClassReferencesSubclass")
55 private static final long serialVersionUID = 1L;
93 contents =
new ArrayList<>(0);
94 recursive =
new Iterable<G>() {
97 public Iterator<G> iterator() {
102 reverse =
new Iterable<G>() {
105 public Iterator<G> iterator() {
106 return new ReverseIterator<>(contents);
122 return new Iterator<G>() {
128 private final Iterator<G> delegate = contents.iterator();
138 public boolean hasNext() {
139 return delegate.hasNext();
144 current = delegate.next();
145 assert current !=
null;
150 public void remove() {
151 final G tmp = current;
153 throw new IllegalStateException(
"no game object available to remove");
159 if (contents.size() >= 2 && contents.get(0) == tmp) {
160 contents.get(1).propagateElevation(tmp);
163 tmp.setContainer(
null, 0, 0);
197 return contents.isEmpty();
207 return contents.isEmpty() ? null : contents.get(0);
217 public G
getPrev(@NotNull
final G gameObject) {
218 final Iterator<G> it = contents.iterator();
219 while (it.hasNext()) {
220 if (it.next() == gameObject) {
221 return it.hasNext() ? it.next() :
null;
234 public G
getNext(@NotNull
final G gameObject) {
235 G prevGameObject =
null;
236 for (
final G tmpGameObject : contents) {
237 if (tmpGameObject == gameObject) {
238 return prevGameObject;
240 prevGameObject = tmpGameObject;
254 return contents.isEmpty() ? null : contents.get(contents.size() - 1);
264 public void remove(@NotNull
final G gameObject) {
268 if (contents.size() >= 2 && contents.get(0) == gameObject) {
269 contents.get(1).propagateElevation(gameObject);
271 if (!contents.remove(gameObject)) {
274 gameObject.setContainer(
null, 0, 0);
285 if (contents.size() <= 0) {
292 gameObject.setContainer(
null, 0, 0);
307 public boolean isTop(@NotNull
final G gameObject) {
308 return !contents.isEmpty() && contents.get(contents.size() - 1) == gameObject;
318 public boolean isBottom(@NotNull
final G gameObject) {
319 return !contents.isEmpty() && contents.get(0) == gameObject;
328 public void moveTop(@NotNull
final G gameObject) {
329 final int oldIndex = contents.indexOf(gameObject);
330 if (oldIndex != contents.size() - 1) {
333 if (!contents.remove(gameObject)) {
337 assert contents.size() >= 1;
338 contents.get(0).propagateElevation(gameObject);
340 contents.add(gameObject);
353 public void moveUp(@NotNull
final G gameObject) {
354 final int oldIndex = contents.indexOf(gameObject);
355 if (oldIndex < contents.size() - 1) {
358 if (!contents.remove(gameObject)) {
362 assert contents.size() >= 1;
363 contents.get(0).propagateElevation(gameObject);
365 contents.add(oldIndex + 1, gameObject);
378 public void moveDown(@NotNull
final G gameObject) {
379 final int oldIndex = contents.indexOf(gameObject);
383 if (!contents.remove(gameObject)) {
387 assert contents.size() >= 1;
388 gameObject.propagateElevation(contents.get(0));
390 contents.add(oldIndex - 1, gameObject);
404 final int oldIndex = contents.indexOf(gameObject);
408 if (!contents.remove(gameObject)) {
411 assert contents.size() >= 1;
412 gameObject.propagateElevation(contents.get(0));
413 contents.add(0, gameObject);
427 public void addLast(@NotNull
final G gameObject) {
428 if (gameObject.isInContainer()) {
429 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
434 contents.add(gameObject);
435 setThisContainer(gameObject);
436 gameObject.markModified();
449 public void addFirst(@NotNull
final G gameObject) {
450 if (gameObject.isInContainer()) {
451 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
456 if (!contents.isEmpty()) {
457 gameObject.propagateElevation(contents.get(0));
459 contents.add(0, gameObject);
460 setThisContainer(gameObject);
461 gameObject.markModified();
475 public void insertAfter(@Nullable
final G previousGameObject, @NotNull
final G gameObject) {
476 if (gameObject.isInContainer()) {
477 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
480 if (previousGameObject ==
null) {
485 if (!previousGameObject.isHead()) {
486 throw new IllegalArgumentException(
"game object must be the head part: " + previousGameObject);
491 boolean added =
false;
493 for (
final G tmpGameObject : contents) {
494 if (tmpGameObject.getHead() == previousGameObject) {
496 gameObject.propagateElevation(contents.get(0));
498 contents.add(index, gameObject);
505 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because " + previousGameObject +
" is not inside");
507 setThisContainer(gameObject);
508 gameObject.markModified();
521 public void insertBefore(@NotNull
final G gameObject, @Nullable
final G nextGameObject) {
522 if (gameObject.isInContainer()) {
523 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
526 if (nextGameObject ==
null) {
527 addFirst(gameObject);
531 if (!nextGameObject.isHead()) {
532 throw new IllegalArgumentException(
"game object must be the head part: " + nextGameObject);
537 final int insertIndex = contents.indexOf(nextGameObject);
538 if (insertIndex == -1) {
539 throw new IllegalArgumentException(
"Can't insert " + gameObject +
" before " + nextGameObject +
" because that isn't inside " +
this);
541 contents.add(insertIndex + 1, gameObject);
542 setThisContainer(gameObject);
543 gameObject.markModified();
556 public void replace(@NotNull
final G oldGameObject, @NotNull
final G newGameObject) {
557 if (oldGameObject.isMulti()) {
558 throw new IllegalArgumentException(
"cannot replace multi-part game object: " + oldGameObject);
563 final int insertIndex = contents.indexOf(oldGameObject);
564 if (insertIndex == -1) {
567 if (insertIndex == 0) {
568 newGameObject.propagateElevation(oldGameObject);
570 contents.remove(oldGameObject);
571 oldGameObject.setContainer(
null, 0, 0);
572 contents.add(insertIndex, newGameObject);
573 setThisContainer(newGameObject);
574 newGameObject.markModified();
599 protected abstract void notifyBeginChange();
604 protected abstract void notifyEndChange();
608 @SuppressWarnings(
"unchecked")
609 protected Object clone() {
614 final G clonedGameObject = gameObject.clone();
615 clone.
contents.add(clonedGameObject);
619 }
catch (
final CloneNotSupportedException e) {
620 assert false :
"This class must be cloneable" + e;
621 throw new AssertionError(e);
627 private void readObject(@NotNull
final ObjectInputStream stream)
throws IOException, ClassNotFoundException {
628 stream.defaultReadObject();
639 if (gameObjectContainer.contents.size() != contents.size()) {
643 for (
int i = 0; i < contents.size(); i++) {
644 if (!gameObjectContainer.contents.get(i).isEqual(contents.get(i))) {
656 protected abstract void setThisContainer(@NotNull G gameObject);
664 public abstract G asGameObject();
669 final StringBuilder sb =
new StringBuilder();
671 final Iterator<G> it = contents.iterator();
673 sb.append(it.next());
674 while (it.hasNext()) {
676 sb.append(it.next());
680 return sb.toString();
707 delegate = list.listIterator(list.size());
712 return delegate.hasPrevious();
719 return delegate.previous();
723 public void remove() {
724 if (delegate.nextIndex() == 0 && list.size() >= 2) {
725 list.get(1).propagateElevation(list.get(0));