/**
  * Creates the nested deltas resulting from an move operation. Convenience method for creating the
  * "move to" delta. The constructor should be used to create the root delta and then the move
  * operation should call this method.
  */
 public void movedTo(IModelElement movedToElement, IModelElement movedFromElement) {
   ModelElementDelta addedDelta = new ModelElementDelta(movedToElement);
   addedDelta.kind = ADDED;
   addedDelta.changeFlags |= F_MOVED_FROM;
   addedDelta.movedFromHandle = movedFromElement;
   insertDeltaTree(movedToElement, addedDelta);
 }
 /**
  * Creates the nested deltas resulting from an move operation. Convenience method for creating the
  * "move from" delta. The constructor should be used to create the root delta and then the move
  * operation should call this method.
  */
 public void movedFrom(IModelElement movedFromElement, IModelElement movedToElement) {
   ModelElementDelta removedDelta = new ModelElementDelta(movedFromElement);
   removedDelta.kind = REMOVED;
   removedDelta.changeFlags |= F_MOVED_TO;
   removedDelta.movedToHandle = movedToElement;
   insertDeltaTree(movedFromElement, removedDelta);
 }
 /**
  * Creates the nested delta deltas based on the affected element its delta, and the root of this
  * delta tree. Returns the root of the created delta tree.
  */
 @SuppressWarnings("unchecked")
 protected ModelElementDelta createDeltaTree(IModelElement element, ModelElementDelta delta) {
   ModelElementDelta childDelta = delta;
   ArrayList ancestors = getAncestors(element);
   if (ancestors == null) {
     if (this.equalsAndSameParent(
         delta.getElement(),
         getElement())) { // handle case of two archives that can be equals but not in the same
       // project
       // the element being changed is the root element
       this.kind = delta.kind;
       this.changeFlags = delta.changeFlags;
       this.movedToHandle = delta.movedToHandle;
       this.movedFromHandle = delta.movedFromHandle;
     }
   } else {
     for (int i = 0, size = ancestors.size(); i < size; i++) {
       IModelElement ancestor = (IModelElement) ancestors.get(i);
       ModelElementDelta ancestorDelta = new ModelElementDelta(ancestor);
       ancestorDelta.addAffectedChild(childDelta);
       childDelta = ancestorDelta;
     }
   }
   return childDelta;
 }
 public void removed(IModelElement element, int flags) {
   ModelElementDelta removedDelta = new ModelElementDelta(element);
   insertDeltaTree(element, removedDelta);
   ModelElementDelta actualDelta = getDeltaFor(element);
   if (actualDelta != null) {
     actualDelta.removed();
     actualDelta.changeFlags |= flags;
     actualDelta.affectedChildren = EMPTY_DELTA;
   }
 }
 /** Returns the delta for a given element. Only looks below this delta. */
 protected ModelElementDelta getDeltaFor(IModelElement element) {
   if (this.equalsAndSameParent(
       getElement(), element)) // handle case of two archives that can be equals but not
     // in the same project
     return this;
   if (this.affectedChildren.length == 0) return null;
   int childrenCount = this.affectedChildren.length;
   for (int i = 0; i < childrenCount; i++) {
     ModelElementDelta delta = (ModelElementDelta) this.affectedChildren[i];
     if (this.equalsAndSameParent(
         delta.getElement(),
         element)) { // handle case of two archives that can be equals but not in the same project
       return delta;
     } else {
       delta = delta.getDeltaFor(element);
       if (delta != null) return delta;
     }
   }
   return null;
 }
 /** Removes the child delta from the collection of affected children. */
 public void removeAffectedChild(ModelElementDelta child) {
   int index = -1;
   if (this.affectedChildren != null) {
     for (int i = 0; i < this.affectedChildren.length; i++) {
       if (this.equalsAndSameParent(
           this.affectedChildren[i].getElement(),
           child.getElement())) { // handle case of two archives that can be equals but not in the
         // same project
         index = i;
         break;
       }
     }
   }
   if (index >= 0) {
     this.affectedChildren = removeAndShrinkArray(this.affectedChildren, index);
   }
 }
 public void added(IModelElement element, int flags) {
   ModelElementDelta addedDelta = new ModelElementDelta(element);
   addedDelta.added();
   addedDelta.changeFlags |= flags;
   insertDeltaTree(element, addedDelta);
 }
 /** Creates the nested deltas for an opened element. */
 public void opened(IModelElement element) {
   ModelElementDelta delta = new ModelElementDelta(element);
   delta.changed(F_OPENED);
   insertDeltaTree(element, delta);
 }
 /** Creates the nested deltas for a closed element. */
 public void closed(IModelElement element) {
   ModelElementDelta delta = new ModelElementDelta(element);
   delta.changed(F_CLOSED);
   insertDeltaTree(element, delta);
 }
 /**
  * Creates the nested deltas resulting from a change operation. Convenience method for creating
  * change deltas. The constructor should be used to create the root delta and then a change
  * operation should call this method.
  */
 public ModelElementDelta changed(IModelElement element, int changeFlag) {
   ModelElementDelta changedDelta = new ModelElementDelta(element);
   changedDelta.changed(changeFlag);
   insertDeltaTree(element, changedDelta);
   return changedDelta;
 }
  /**
   * Adds the child delta to the collection of affected children. If the child is already in the
   * collection, walk down the hierarchy.
   */
  protected void addAffectedChild(ModelElementDelta child) {
    switch (this.kind) {
      case ADDED:
      case REMOVED:
        // no need to add a child if this parent is added or removed
        return;
      case CHANGED:
        this.changeFlags |= F_CHILDREN;
        break;
      default:
        this.kind = CHANGED;
        this.changeFlags |= F_CHILDREN;
    }

    // if a child delta is added to a compilation unit delta or below,
    // it's a fine grained delta
    if (this.changedElement.getElementType() >= IModelElement.MODULE) {
      this.fineGrained();
    }

    if (this.affectedChildren == null || this.affectedChildren.length == 0) {
      this.affectedChildren = new IModelElementDelta[] {child};
      return;
    }
    ModelElementDelta existingChild = null;
    int existingChildIndex = -1;
    if (this.affectedChildren != null) {
      for (int i = 0; i < this.affectedChildren.length; i++) {
        if (this.equalsAndSameParent(
            this.affectedChildren[i].getElement(),
            child.getElement())) { // handle case of two archives that can be equals but not in the
          // same project
          existingChild = (ModelElementDelta) this.affectedChildren[i];
          existingChildIndex = i;
          break;
        }
      }
    }
    if (existingChild == null) { // new affected child
      this.affectedChildren = growAndAddToArray(this.affectedChildren, child);
    } else {
      switch (existingChild.getKind()) {
        case ADDED:
          switch (child.getKind()) {
            case ADDED: // child was added then added -> it is added
            case CHANGED: // child was added then changed -> it is added
              return;
            case REMOVED: // child was added then removed -> noop
              this.affectedChildren =
                  this.removeAndShrinkArray(this.affectedChildren, existingChildIndex);
              return;
          }
          break;
        case REMOVED:
          switch (child.getKind()) {
            case ADDED: // child was removed then added -> it is changed
              child.kind = CHANGED;
              this.affectedChildren[existingChildIndex] = child;
              return;
            case CHANGED: // child was removed then changed -> it is removed
            case REMOVED: // child was removed then removed -> it is removed
              return;
          }
          break;
        case CHANGED:
          switch (child.getKind()) {
            case ADDED: // child was changed then added -> it is added
            case REMOVED: // child was changed then removed -> it is removed
              this.affectedChildren[existingChildIndex] = child;
              return;
            case CHANGED: // child was changed then changed -> it is changed
              IModelElementDelta[] children = child.getAffectedChildren();
              for (int i = 0; i < children.length; i++) {
                ModelElementDelta childsChild = (ModelElementDelta) children[i];
                existingChild.addAffectedChild(childsChild);
              }

              // update flags
              boolean childHadContentFlag = (child.changeFlags & F_CONTENT) != 0;
              boolean existingChildHadChildrenFlag = (existingChild.changeFlags & F_CHILDREN) != 0;
              existingChild.changeFlags |= child.changeFlags;

              // remove F_CONTENT flag if existing child had F_CHILDREN flag set
              // (case of fine grained delta (existing child) and delta coming from
              // DeltaProcessor (child))
              if (childHadContentFlag && existingChildHadChildrenFlag) {
                existingChild.changeFlags &= ~F_CONTENT;
              }

              // add the non-java resource deltas if needed
              // note that the child delta always takes precedence over this existing child delta
              // as non-java resource deltas are always created last (by the DeltaProcessor)
              IResourceDelta[] resDeltas = child.getResourceDeltas();
              if (resDeltas != null) {
                existingChild.resourceDeltas = resDeltas;
                existingChild.resourceDeltasCounter = child.resourceDeltasCounter;
              }

              return;
          }
          break;
        default:
          // unknown -> existing child becomes the child with the existing child's flags
          int flags = existingChild.getFlags();
          this.affectedChildren[existingChildIndex] = child;
          child.changeFlags |= flags;
      }
    }
  }