import java.util.*;
import org.aspectj.lang.annotation.*;

class Blob {}

public aspect TheBigOne extends ParentChildRelationship<Blob,Blob> {

  public static void main(String []argv) {
    Blob a = new Blob();
    Blob b = new Blob();
    Blob c = new Blob();
    Blob d = new Blob();
    Blob e = new Blob();

    // arrange as follows: A contains B,C,D and B contains E

    a.addChild(b);
    a.addChild(c);
    a.addChild(d);
    b.addChild(e);

    // now query the layout

    if (!e.getParent().equals(b)) 
      throw new RuntimeException("why is E not parent of B? "+e.getParent());
    if (!d.getParent().equals(a)) 
      throw new RuntimeException("why is A not parent of D? "+d.getParent());
    if (a.getChildren().size()!=3)
      throw new RuntimeException("A should have 3 children, not:"+a.getChildren().size());
  }

}


abstract aspect ParentChildRelationship<Parent,Child> {

  interface ParentHasChildren<C>{}
  interface ChildHasParent<P>{}

  declare parents: Parent implements ParentHasChildren<Child>;
  declare parents: Child  implements ChildHasParent<Parent>;

  public List<E> ParentHasChildren<E>.children = new ArrayList<E>();
  public P ChildHasParent<P>.parent;

  public List<D> ParentHasChildren<D>.getChildren() {
    return Collections.unmodifiableList(children);
  }

  public P ChildHasParent<P>.getParent() {
    return parent;
  }

  public void ChildHasParent<R>.setParent(R parent) {
    this.parent = parent;
    ParentHasChildren phc = (ParentHasChildren)parent;
    if (phc.getChildren().contains(this))
    phc.addChild(this);
  }

  public void ParentHasChildren<X>.addChild(X child) {
    if (((ChildHasParent)child).parent != null) {
      ((ParentHasChildren)((ChildHasParent)child).parent).removeChild(child);
    } else {
      ((ChildHasParent)child).setParent((ParentHasChildren)this);
    }
    children.add(child);
  }

  public void ParentHasChildren<Y>.removeChild(Y child) {
    if (children.remove(child)) {
      ((ChildHasParent)child).parent = null;
    }
  }

}