aspect Computation {
  syn Alfa SenderRoot.getAlfa() {
    Alfa result = new Alfa();
    for (int i = 0; i < 4; i++) {
      result.addBravo(new Bravo().setID(i));
      result.addCharlie(new Charlie().setID(i));
      result.addDelta(new Delta().setID(i));
    }
    Bravo inputBravo = result.getBravo(getInput());
    Charlie inputCharlie = result.getCharlie(getInput());
    Delta inputDelta = result.getDelta(getInput());

    // rel Alfa.MyBravo -> Bravo ;
    result.setMyBravo(inputBravo);
    // rel Alfa.OptionalBravo? -> Bravo ;
    result.setOptionalBravo(inputBravo);
    // rel Alfa.MultiBravo* -> Bravo ;
    result.addMultiBravo(inputBravo);
    result.addMultiBravo(result.getBravo(getInput() + 1));

    // rel Charlie.MyAlfa? -> Alfa ;
    inputCharlie.setMyAlfa(result);

    // rel Alfa.SingleBi1Delta <-> Delta.SingleBack1Alfa? ;
    result.setSingleBi1Delta(inputDelta);
    // rel Alfa.MultiBi2Delta* <-> Delta.SingleBack2Alfa? ;
    result.addMultiBi2Delta(inputDelta);
    result.addMultiBi2Delta(result.getDelta(getInput() + 1));
    // rel Alfa.MultiBi3Delta* <-> Delta.MultiBack3Alfa* ;
    result.addMultiBi3Delta(inputDelta);
    result.addMultiBi3Delta(result.getDelta(getInput() + 1));

    // rel Alfa.Myself -> Alfa ;
    result.setMyself(result);

    // rel Bravo.MyCharlie -> Charlie ;
    for (int i = 0; i < 4; i++) {
      if (i == getInput()) {
        result.getBravo(i).setMyCharlie(inputCharlie);
      } else {
        result.getBravo(i).setMyCharlie(result.getCharlie(0));
      }
    }
    // rel Bravo.OptionalCharlie? -> Charlie ;
    inputBravo.setOptionalCharlie(inputCharlie);
    // rel Bravo.MultiCharlie* -> Charlie ;
    inputBravo.addMultiCharlie(inputCharlie);
    inputBravo.addMultiCharlie(result.getCharlie(getInput() + 1));

    // rel Bravo.SingleBi1Delta? <-> Delta.SingleBack1Bravo? ;
    inputBravo.setSingleBi1Delta(inputDelta);
    // rel Bravo.MultiBi2Delta* <-> Delta.SingleBack2Bravo? ;
    inputBravo.addMultiBi2Delta(inputDelta);
    inputBravo.addMultiBi2Delta(result.getDelta(getInput() + 1));
    // rel Bravo.MultiBi3Delta* <-> Delta.MultiBack3Bravo* ;
    inputBravo.addMultiBi3Delta(inputDelta);
    inputBravo.addMultiBi3Delta(result.getDelta(getInput() + 1));
    result.getBravo(getInput() + 1).addMultiBi3Delta(inputDelta);
    result.getBravo(getInput() + 1).addMultiBi3Delta(result.getDelta(getInput() + 1));

    return result;
  }

  syn boolean ASTNode.isNameable() = false;
  eq Nameable.isNameable() = true;
}

aspect Testing {
  class ReceiverRoot implements org.jastadd.ragconnect.tests.AbstractTreeTest.TestWrapperReceiverRoot {}
  class Alfa implements org.jastadd.ragconnect.tests.AbstractTreeTest.TestWrapperAlfa {}
  class Bravo implements org.jastadd.ragconnect.tests.AbstractTreeTest.TestWrapperBravo {}
  class Charlie implements org.jastadd.ragconnect.tests.AbstractTreeTest.TestWrapperCharlie {}
  class Delta implements org.jastadd.ragconnect.tests.AbstractTreeTest.TestWrapperDelta {}
}

aspect NameResolution {
  @Override
  protected String Nameable.customID() {
    return getClass().getSimpleName() + getID();
  }
}