/**
  * @param relation
  * @return True if relation is bi-directional
  */
 public static boolean isBidirectionalRelationship(IRelationship relation) {
   // return relation instanceof IAssociationRelationship || relation instanceof
   // IAssignmentRelationship;
   if (relation instanceof IAssignmentRelationship) {
     return (relation.getSource() instanceof IBusinessActor)
         && (relation.getTarget() instanceof IBusinessRole);
   }
   return false;
 }
  /**
   * @param element1
   * @param element2
   * @return True if element1 has a direct Structural relationship to element2
   */
  public static boolean hasDirectStructuralRelationship(
      IArchimateElement element1, IArchimateElement element2) {
    for (IRelationship relation : ArchimateModelUtils.getSourceRelationships(element1)) {
      if (relation.getTarget() == element2 && isStructuralRelationship(relation)) {
        return true;
      }
    }

    return false;
  }
  /**
   * @param chain
   * @return The weakest type of relationship in a chain of relationships
   */
  public static EClass getWeakestType(List<IRelationship> chain) {
    int weakest = weaklist.size() - 1;

    for (IRelationship rel : chain) {
      int index = weaklist.indexOf(rel.eClass());
      if (index < weakest) {
        weakest = index;
      }
    }

    return weaklist.get(weakest);
  }
  /**
   * Create a derived relation between two elements
   *
   * @param element1
   * @param element2
   * @return the derived relationship or null
   * @throws TooComplicatedException
   */
  public static IRelationship createDerivedRelationship(
      IArchimateElement element1, IArchimateElement element2) throws TooComplicatedException {
    if (element1 == null || element2 == null) {
      return null;
    }

    // System.out.println("-----------------------------------");
    // System.out.println("Starting hunt from " + element1.getName() + " --> " +
    // element2.getName());
    // System.out.println("-----------------------------------");

    // Traverse from element1 to element2
    List<List<IRelationship>> chains = findChains(element1, element2);

    if (chains.isEmpty()) {
      return null;
    }

    int weakest = weaklist.size() - 1;

    // You are the weakest link...goodbye.
    for (List<IRelationship> chain : chains) {
      for (IRelationship rel : chain) {
        // printChain(chain);
        int index = weaklist.indexOf(rel.eClass());
        if (index < weakest) {
          weakest = index;
        }
      }
    }

    EClass relationshipClass = weaklist.get(weakest);
    // System.out.println("Weakest is: " + relationshipClass);

    /*
     * Check the validity of the relationship.
     */
    boolean isValid =
        ArchimateModelUtils.isValidRelationship(element1, element2, relationshipClass);
    if (!isValid) {
      return null;
    }

    return (IRelationship) IArchimateFactory.eINSTANCE.create(relationshipClass);
  }
  private static void _addRelationshipToTempChain(IRelationship relation, boolean forwards)
      throws TooComplicatedException {
    // Reached the same relationship so go back one (this guards against a loop)
    if (temp_chain.contains(relation)) {
      // System.out.println("Reached same relationship in chain: " + relation.getName());
      return;
    }

    // If we get the target element we are traversing fowards, otherwise backwards from a
    // bi-directional check
    IArchimateElement element = forwards ? relation.getTarget() : relation.getSource();

    // Arrived at target
    if (finalTarget == element) {
      if (temp_chain.size() > 0) { // Only chains of length 2 or greater
        // System.out.println("Reached target from: " + element.getName());
        List<IRelationship> chain =
            new ArrayList<IRelationship>(
                temp_chain); // make a copy because temp_chain will have relation removed, below
        chain.add(relation);

        // Duplicate check - there must be a loop?
        if (_containsChain(chain, chains)) {
          System.err.println("Duplicate chain:"); // $NON-NLS-1$
          _printChain(chain, finalTarget);
        }

        EClass weakest = getWeakestType(chain);
        int index = weaklist.indexOf(weakest);
        if (index < weakestFound) {
          weakestFound = index;
        }

        chains.add(chain);
      }
    }
    // Move onto next element in chain
    else {
      // System.out.println("Adding to temp chain: " + relation.getName());
      temp_chain.add(relation);
      _traverse(element);
      temp_chain.remove(relation); // back up
    }
  }
 private static String _getRelationshipText(List<IRelationship> chain, IRelationship relation) {
   if (isBidirectionalRelationship(relation)) {
     int index = chain.indexOf(relation);
     if (index > 0) {
       IRelationship previous = chain.get(index - 1);
       if (relation.getTarget() == previous.getTarget()) {
         return relation.getTarget().getName();
       }
     }
     return relation.getSource().getName();
   } else {
     return relation.getSource().getName();
   }
 }
  /**
   * @param relation
   * @return true if relation is in a derived chain of relationships
   */
  public static boolean isInDerivedChain(IRelationship relation) {
    if (!isStructuralRelationship(relation)) {
      return false;
    }

    // Get relations from source element
    IArchimateElement source = relation.getSource();
    if (source != null
        && source.getArchimateModel()
            != null) { // An important guard because the element might have been deleted
      // Source has structural target relations
      for (IRelationship rel : ArchimateModelUtils.getTargetRelationships(source)) {
        if (rel != relation) {
          if (isStructuralRelationship(rel) && rel.getSource() != relation.getTarget()) {
            return true;
          }
        }
      }

      // Bi-directional relations
      for (IRelationship rel : ArchimateModelUtils.getSourceRelationships(source)) {
        if (rel != relation) {
          if (isBidirectionalRelationship(rel)) {
            return true;
          }
          if (isStructuralRelationship(rel) && isBidirectionalRelationship(relation)) {
            return true;
          }
        }
      }
    }

    // Get relations from target element
    IArchimateElement target = relation.getTarget();
    if (target != null
        && target.getArchimateModel()
            != null) { // An important guard because the element might have been deleted
      // Target has structural source relations
      for (IRelationship rel : ArchimateModelUtils.getSourceRelationships(target)) {
        if (rel != relation) {
          if (isStructuralRelationship(rel) && rel.getTarget() != relation.getSource()) {
            return true;
          }
        }
      }

      // Bi-directional relations
      for (IRelationship rel : ArchimateModelUtils.getTargetRelationships(target)) {
        if (rel != relation) {
          if (isBidirectionalRelationship(rel)) {
            return true;
          }
          if (isStructuralRelationship(rel) && isBidirectionalRelationship(relation)) {
            return true;
          }
        }
      }
    }

    return false;
  }