/**
   * Convenience method to add a relatio and its transpose at the same time.
   *
   * @param pElement1 The domain of the relation. Should not be null.
   * @param pRelation The Relation relating the domain to the range. Should not be null.
   * @param pElement2 The range of the relation. Should not be null.
   * @throws ElementNotFoundException if either of pElement1 or pElement2 are not indexed in the
   *     database.
   */
  public void addRelationAndTranspose(
      final IElement pElement1, final Relation pRelation, final IElement pElement2)
      throws ElementNotFoundException {
    //		assert (pElement1 != null);
    //		assert (pElement2 != null);
    //		assert (pRelation != null);

    if (!this.contains(pElement1)) throw new ElementNotFoundException(pElement1.getId());
    if (!this.contains(pElement2)) throw new ElementNotFoundException(pElement2.getId());

    this.addRelation(pElement1, pRelation, pElement2);
    this.addRelation(pElement2, pRelation.getInverseRelation(), pElement1);
  }
  /**
   * Removes a relation from an element. Does not automatically remove the transpose relation.
   *
   * @param pElement1 The element to remove the relation from. Must not be null and must exist in
   *     the program database.
   * @param pRelation The relation linking pElement1 with pElement2. Must not be null.
   * @param pElement2 The range element of the relation. Must not be null and must exist in the
   *     program database.
   * @throws ElementNotFoundException If either pFrom or pTo is not indexed in the database.
   */
  @SuppressWarnings("unchecked")
  private void removeRelation(
      final IElement pElement1, final Relation pRelation, final IElement pElement2)
      throws ElementNotFoundException {
    //		assert (pElement1 != null);
    //		assert (pElement2 != null);
    //		assert (pRelation != null);

    if (!this.contains(pElement1)) throw new ElementNotFoundException(pElement1.getId());
    if (!this.contains(pElement2)) throw new ElementNotFoundException(pElement2.getId());

    final Map lRelations = this.aElements.get(pElement1).getRelationMap();
    if (!lRelations.containsKey(pRelation)) return;
    final Set lElements = (Set) lRelations.get(pRelation);
    lElements.remove(pElement2);
  }
  /**
   * Returns whether pElements has any associated relations.
   *
   * @param pElement The element to check. Must not be null and exist in the database.
   * @return True if pElement has any associated relations.
   * @throws ElementNotFoundException If either pFrom or pTo is not indexed in the database.
   */
  @SuppressWarnings("unchecked")
  public boolean hasRelations(final IElement pElement) throws ElementNotFoundException {
    //		assert (pElement != null);
    if (!this.contains(pElement)) throw new ElementNotFoundException(pElement.getId());

    final Map lRelations = this.aElements.get(pElement).getRelationMap();
    return !lRelations.isEmpty();
  }
  /**
   * Copies all the relations associated with pFrom to pTo, including its transposes
   *
   * @param pFrom The source element. Must not be null and must exist in the database.
   * @param pTo The target element. Must not be null and must exist in the database.
   * @throws ElementNotFoundException If either pFrom or pTo is not indexed in the database.
   */
  @SuppressWarnings("unchecked")
  public void copyRelations(final IElement pFrom, final IElement pTo)
      throws ElementNotFoundException {
    //		assert (pFrom != null);
    //		assert (pTo != null);

    if (!this.contains(pFrom)) throw new ElementNotFoundException(pFrom.getId());
    if (!this.contains(pTo)) throw new ElementNotFoundException(pTo.getId());

    final Map lRelations = this.aElements.get(pFrom).getRelationMap();
    for (final Iterator i = lRelations.keySet().iterator(); i.hasNext(); ) {
      final Relation lNext = (Relation) i.next();
      final Set lElements = (Set) lRelations.get(lNext);
      for (final Iterator j = lElements.iterator(); j.hasNext(); )
        this.addRelationAndTranspose(pTo, lNext, (IElement) j.next());
    }
  }
  /**
   * Adds a relation pRelation between pElement1 and pElement2. If pElement1 or pElement2 does not
   * exist in the database, an exception is raised, so these should always be added first.
   *
   * @param pElement1 The first element in the relation, never null.
   * @param pRelation The relation, never null.
   * @param pElement2 The second element in the relation, never null.
   * @throws ElementNotFoundException If pElement1 or pElement2 is not found in the database.
   */
  public void addRelation(
      final IElement pElement1, final Relation pRelation, final IElement pElement2)
      throws ElementNotFoundException {
    //		assert (pElement1 != null);
    //		assert (pElement2 != null);
    //		assert (pRelation != null);

    if (!this.contains(pElement1)) throw new ElementNotFoundException(pElement1.getId());
    if (!this.contains(pElement2)) throw new ElementNotFoundException(pElement2.getId());

    final Map<Relation, Set<IElement>> lRelations = this.aElements.get(pElement1).getRelationMap();
    //		assert (lRelations != null);

    Set<IElement> lElements = lRelations.get(pRelation);
    if (lElements == null) {
      lElements = new HashSet<IElement>();
      lRelations.put(pRelation, lElements);
    }
    lElements.add(pElement2);
  }
  /**
   * Remove an element and all its direct and transpose relations.
   *
   * @param pElement The element to remove. Must not be null and must exist in the database.
   * @throws ElementNotFoundException If pElement is not indexed in the database.
   */
  @SuppressWarnings("unchecked")
  public void removeElement(final IElement pElement) throws ElementNotFoundException {
    //		assert (pElement != null);
    if (!this.contains(pElement)) throw new ElementNotFoundException(pElement.getId());

    final Map lRelations = this.aElements.get(pElement).getRelationMap();
    for (final Iterator i = lRelations.keySet().iterator(); i.hasNext(); ) {
      final Relation lNext = (Relation) i.next();
      final Set lElements = (Set) lRelations.get(lNext);
      for (final Iterator j = lElements.iterator(); j.hasNext(); )
        this.removeRelation((IElement) j.next(), lNext.getInverseRelation(), pElement);
    }

    // Remove the element
    this.aElements.remove(pElement);
  }