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);
95 reverse = () ->
new ReverseIterator<>(contents);
108 return new Iterator<G>() {
114 private final Iterator<G> delegate = contents.iterator();
124 public boolean hasNext() {
125 return delegate.hasNext();
130 current = delegate.next();
131 assert current !=
null;
136 public void remove() {
137 final G tmp = current;
139 throw new IllegalStateException(
"no game object available to remove");
145 if (contents.size() >= 2 && contents.get(0) == tmp) {
146 contents.get(1).propagateElevation(tmp);
149 tmp.setContainer(
null, 0, 0);
183 return contents.isEmpty();
193 return contents.isEmpty() ? null : contents.get(0);
203 public G
getPrev(@NotNull
final G gameObject) {
204 final Iterator<G>
it = contents.iterator();
205 while (
it.hasNext()) {
206 if (
it.next() == gameObject) {
207 return it.hasNext() ?
it.next() :
null;
220 public G
getNext(@NotNull
final G gameObject) {
221 G prevGameObject =
null;
222 for (
final G tmpGameObject : contents) {
223 if (tmpGameObject == gameObject) {
224 return prevGameObject;
226 prevGameObject = tmpGameObject;
240 return contents.isEmpty() ? null : contents.get(contents.size() - 1);
250 public void remove(@NotNull
final G gameObject) {
254 if (contents.size() >= 2 && contents.get(0) == gameObject) {
255 contents.get(1).propagateElevation(gameObject);
257 if (!contents.remove(gameObject)) {
260 gameObject.setContainer(
null, 0, 0);
271 if (contents.size() <= 0) {
278 gameObject.setContainer(
null, 0, 0);
293 public boolean isTop(@NotNull
final G gameObject) {
294 return !contents.isEmpty() && contents.get(contents.size() - 1) == gameObject;
304 public boolean isBottom(@NotNull
final G gameObject) {
305 return !contents.isEmpty() && contents.get(0) == gameObject;
314 public void moveTop(@NotNull
final G gameObject) {
315 final int oldIndex = contents.indexOf(gameObject);
316 if (oldIndex != contents.size() - 1) {
319 if (!contents.remove(gameObject)) {
323 assert contents.size() >= 1;
324 contents.get(0).propagateElevation(gameObject);
326 contents.add(gameObject);
339 public void moveUp(@NotNull
final G gameObject) {
340 final int oldIndex = contents.indexOf(gameObject);
341 if (oldIndex < contents.size() - 1) {
344 if (!contents.remove(gameObject)) {
348 assert contents.size() >= 1;
349 contents.get(0).propagateElevation(gameObject);
351 contents.add(oldIndex + 1, gameObject);
364 public void moveDown(@NotNull
final G gameObject) {
365 final int oldIndex = contents.indexOf(gameObject);
369 if (!contents.remove(gameObject)) {
373 assert contents.size() >= 1;
374 gameObject.propagateElevation(contents.get(0));
376 contents.add(oldIndex - 1, gameObject);
390 final int oldIndex = contents.indexOf(gameObject);
394 if (!contents.remove(gameObject)) {
397 assert contents.size() >= 1;
398 gameObject.propagateElevation(contents.get(0));
399 contents.add(0, gameObject);
413 public void addLast(@NotNull
final G gameObject) {
414 if (gameObject.isInContainer()) {
415 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
420 contents.add(gameObject);
421 setThisContainer(gameObject);
422 gameObject.markModified();
435 public void addFirst(@NotNull
final G gameObject) {
436 if (gameObject.isInContainer()) {
437 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
442 if (!contents.isEmpty()) {
443 gameObject.propagateElevation(contents.get(0));
445 contents.add(0, gameObject);
446 setThisContainer(gameObject);
447 gameObject.markModified();
461 public void insertAfter(@Nullable
final G previousGameObject, @NotNull
final G gameObject) {
462 if (gameObject.isInContainer()) {
463 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
466 if (previousGameObject ==
null) {
471 if (!previousGameObject.isHead()) {
472 throw new IllegalArgumentException(
"game object must be the head part: " + previousGameObject);
477 boolean added =
false;
479 for (
final G tmpGameObject : contents) {
480 if (tmpGameObject.getHead() == previousGameObject) {
482 gameObject.propagateElevation(contents.get(0));
484 contents.add(index, gameObject);
491 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because " + previousGameObject +
" is not inside");
493 setThisContainer(gameObject);
494 gameObject.markModified();
507 public void insertBefore(@NotNull
final G gameObject, @Nullable
final G nextGameObject) {
508 if (gameObject.isInContainer()) {
509 throw new IllegalArgumentException(
"Can't add " + gameObject +
" to " +
this +
" because it's already inside " + gameObject.getContainer());
512 if (nextGameObject ==
null) {
513 addFirst(gameObject);
517 if (!nextGameObject.isHead()) {
518 throw new IllegalArgumentException(
"game object must be the head part: " + nextGameObject);
523 final int insertIndex = contents.indexOf(nextGameObject);
524 if (insertIndex == -1) {
525 throw new IllegalArgumentException(
"Can't insert " + gameObject +
" before " + nextGameObject +
" because that isn't inside " +
this);
527 contents.add(insertIndex + 1, gameObject);
528 setThisContainer(gameObject);
529 gameObject.markModified();
542 public void replace(@NotNull
final G oldGameObject, @NotNull
final G newGameObject) {
543 if (oldGameObject.isMulti()) {
544 throw new IllegalArgumentException(
"cannot replace multi-part game object: " + oldGameObject);
549 final int insertIndex = contents.indexOf(oldGameObject);
550 if (insertIndex == -1) {
553 if (insertIndex == 0) {
554 newGameObject.propagateElevation(oldGameObject);
556 contents.remove(oldGameObject);
557 oldGameObject.setContainer(
null, 0, 0);
558 contents.add(insertIndex, newGameObject);
559 setThisContainer(newGameObject);
560 newGameObject.markModified();
585 protected abstract void notifyBeginChange();
590 protected abstract void notifyEndChange();
594 @SuppressWarnings(
"unchecked")
595 protected Object clone() {
600 final G clonedGameObject = gameObject.clone();
601 clone.
contents.add(clonedGameObject);
605 }
catch (
final CloneNotSupportedException e) {
606 assert false :
"This class must be cloneable" + e;
607 throw new AssertionError(e);
613 private void readObject(@NotNull
final ObjectInputStream stream)
throws IOException, ClassNotFoundException {
614 stream.defaultReadObject();
625 if (gameObjectContainer.contents.size() != contents.size()) {
629 for (
int i = 0; i < contents.size(); i++) {
630 if (!gameObjectContainer.contents.get(i).isEqual(contents.get(i))) {
642 protected abstract void setThisContainer(@NotNull G gameObject);
650 public abstract G asGameObject();
655 final StringBuilder sb =
new StringBuilder();
657 final Iterator<G>
it = contents.iterator();
659 sb.append(
it.next());
660 while (
it.hasNext()) {
662 sb.append(
it.next());
666 return sb.toString();
693 delegate =
list.listIterator(
list.size());
698 return delegate.hasPrevious();
705 return delegate.previous();
709 public void remove() {
710 if (delegate.nextIndex() == 0 &&
list.size() >= 2) {
711 list.get(1).propagateElevation(
list.get(0));