/**
  * Computes the random amount of objects to add to a feature.
  *
  * @param feature the feature to compute the amount of objects for
  * @param random the Random object used to obtain random values
  * @return 1 if the feature is single valued,<br>
  *     a random value from 0 to 10 if the feature is many-valued and has no upper bound,<br>
  *     a random value between the feature's lower and upper bound otherwise
  */
 private static int computeFeatureAmount(EStructuralFeature feature, Random random) {
   if (!feature.isMany()) {
     return 1;
   }
   if (feature.getUpperBound() < feature.getLowerBound()) {
     return random.nextInt(10);
   }
   return feature.getLowerBound()
       + random.nextInt(feature.getUpperBound() - feature.getLowerBound() + 1);
 }
  @SuppressWarnings("unchecked")
  private void writeTable(PrintWriter out, EObject eObject) {
    out.println("<h1>" + eObject.eClass().getName() + "</h1>");
    out.println("<table>");
    for (EStructuralFeature eStructuralFeature : eObject.eClass().getEAllStructuralFeatures()) {
      if (eStructuralFeature.getEAnnotation("hidden") == null) {
        out.println("<tr>");
        out.println("<td>" + eStructuralFeature.getName() + "</td>");
        Object eGet = eObject.eGet(eStructuralFeature);
        if (eStructuralFeature instanceof EAttribute) {
          if (eStructuralFeature.getUpperBound() == 1) {
            out.println("<td>" + eGet + "</td>");
          } else {
            List<Object> list = (List<Object>) eGet;
            out.println("<td>");
            for (Object object : list) {
              out.println(object + " ");
            }
            out.println("</td>");
          }
        } else if (eStructuralFeature instanceof EReference) {
          if (eStructuralFeature.getUpperBound() == 1) {
            if (eStructuralFeature.getEType().getEAnnotation("wrapped") != null) {
              EObject value = (EObject) eGet;
              if (value != null) {
                out.println(
                    "<td>"
                        + value.eGet(value.eClass().getEStructuralFeature("wrappedValue"))
                        + "</td>");
              }
            } else {

            }
          } else {
            if (eStructuralFeature.getEType().getEAnnotation("wrapped") != null) {
              List<EObject> list = (List<EObject>) eGet;
              out.println("<td>");
              for (EObject object : list) {
                out.println(
                    "<td>"
                        + object.eGet(object.eClass().getEStructuralFeature("wrappedValue"))
                        + "</td>");
              }
              out.println("</td>");
            } else {

            }
          }
        }
      }
      out.println("</tr>");
    }
    out.println("</table>");
  }
 /**
  * Returns whether an EStructuralFeature is valid for an EObject or not. A reference is valid, if
  * it can be set or added to.
  *
  * @param feature the EStructuralFeature in question
  * @param eObject the EObject to check the feature for
  * @param exceptionLog the current log of exceptions
  * @param ignoreAndLog should exceptions be ignored and added to <code>exceptionLog</code>?
  * @return if the feature can be set or added to
  */
 public static boolean isValid(
     EStructuralFeature feature,
     EObject eObject,
     Set<RuntimeException> exceptionLog,
     boolean ignoreAndLog) {
   boolean result = false;
   try {
     if (feature.isMany()) {
       // has the maximum amount of referenced objects been reached?
       Collection<?> referencedItems = (Collection<?>) eObject.eGet(feature);
       if (feature.getUpperBound() >= 0 && referencedItems.size() >= feature.getUpperBound()) {
         return false;
       }
     }
     // can the feature be changed reflectively?
     result = feature.isChangeable() && !feature.isVolatile() && !feature.isDerived();
   } catch (RuntimeException e) {
     handle(e, exceptionLog, ignoreAndLog);
   }
   return result;
 }
  protected IStrategoTerm convert(EObject object, EStructuralFeature feature) {
    IStrategoTerm result = null;

    if (feature instanceof EAttribute) {
      result = convert(object, (EAttribute) feature);
    } else {
      result = convert(object, (EReference) feature);
    }

    if (feature.getLowerBound() == 0 && feature.getUpperBound() == 1) {
      return someOrNone(result);
    } else if (result == null) {
      return createDefaultValue(feature);
    } else {
      return result;
    }
  }
  /**
   * @param realEditedObject the real edited object : the stereotype application or the edited
   *     Element
   * @param realFeature the real edited feature : the feature of the stereotype application or the
   *     the feature of the edited Element
   * @param stereotype the stereotype if we are are editing a stereotype application
   * @param resourceSet the resourceset
   * @return the dialog to edit the property
   */
  protected Object createDialog(
      EObject realEditedObject,
      EStructuralFeature realFeature,
      Stereotype stereotype,
      ResourceSet resourceSet) {
    final UMLContentProvider p =
        new UMLContentProvider(realEditedObject, realFeature, stereotype, resourceSet);
    final String title = realFeature.getName();
    final boolean unique = realFeature.isUnique();
    final boolean ordered = realFeature.isOrdered();
    final int upperBound = realFeature.getUpperBound();
    final Object value = realEditedObject.eGet(realFeature);
    IElementSelector selector = getElementSelector(unique, new UMLLabelProvider(), p);
    final MultipleValueSelectorDialog dialog =
        new MultipleValueSelectorDialog(
            Display.getCurrent().getActiveShell(), selector, title, unique, ordered, upperBound) {

          @Override
          protected void okPressed() {
            super.okPressed();
            Collection<Object> newValue = new ArrayList<Object>();
            Object[] result = this.getResult();
            for (Object object : result) {
              newValue.add(object);
            }
            AbstractUMLMultiValueCellEditor.this.returnedValue = newValue;
            AbstractUMLMultiValueCellEditor.this.editHandler.commit(
                newValue, MoveDirectionEnum.NONE);
          }
        };
    dialog.setLabelProvider(new UMLLabelProvider());
    if (value != null && value instanceof Collection) {
      Collection<?> coll = (Collection<?>) value;
      if (!coll.isEmpty()) {
        dialog.setInitialSelections(coll.toArray());
      }
    }

    ReferenceValueFactory factory = getFactory();
    if (factory != null) {
      dialog.setFactory(factory);
    }

    return dialog;
  }
  @Override
  public void resolve(IFragSubHolder fragmentHolderCurrent) throws BasicBVREngineException {
    IAdjacentFragment aFrag = this.adjacentFinder.getAdjacentMap().get(fragmentHolderCurrent);
    if (aFrag == null) return;

    HashSet<IAdjacentFragment> adjacentFragments = aFrag.getAdjacentFragments();
    if (adjacentFragments.isEmpty())
      throw new GeneralBVREngineException(
          "can not find any adjacent fragments to the fragment that seems to be adjacent"
              + fragmentHolderCurrent);

    HashSet<IAdjacentFragment> twinAFrag = aFrag.getTwinFragments();
    for (IAdjacentFragment adjacentFragment : adjacentFragments) {
      IFragSubHolder fragHolderAdjacent = adjacentFragment.getFragmentHolder();
      HashMap<FromBinding, ToBinding> adjacentBindingsToCurrent =
          EngineUtility.reverseMap(aFrag.getAdjacentToBindings(adjacentFragment));
      adjacentBindingsToCurrent =
          (adjacentBindingsToCurrent != null)
              ? adjacentBindingsToCurrent
              : new HashMap<FromBinding, ToBinding>();
      for (Map.Entry<FromBinding, ToBinding> entry : adjacentBindingsToCurrent.entrySet()) {
        FromBinding fromBinding = entry.getKey();
        ToBinding toBinding = entry.getValue();

        EList<ObjectHandle> outsideBOHElmtsPlc =
            fromBinding.getFromPlacement().getOutsideBoundaryElement();
        EList<ObjectHandle> insideBOHElmtsPlcReplaced =
            calculateInsideBoundaryElements(twinAFrag, adjacentFragment, fromBinding, toBinding);

        HashMap<FromPlacement, HashSet<ObjectHandle>> insideBoundaryElementsFromPlacementMap =
            ((FragmentSubstitutionHolder) fragHolderAdjacent)
                .getFromPlacementInsideBoundaryElementMap();
        HashSet<ObjectHandle> insideBoundaryElementsFromPlacement =
            insideBoundaryElementsFromPlacementMap.get(fromBinding.getFromPlacement());
        if (insideBoundaryElementsFromPlacement == null)
          throw new GeneralBVREngineException(
              "failed to find insideBoundaryElements in the map for a given fromPlacement "
                  + fromBinding.getFromPlacement()
                  + " of the fromBinding "
                  + fromBinding);

        HashSet<ObjectHandle> validOutsideOHFromPlacementBElements = new HashSet<ObjectHandle>();

        for (ObjectHandle objectHandle : insideBoundaryElementsFromPlacement) {
          EObject insideBoundaryElementPlc = EngineUtility.resolveProxies(objectHandle);
          String propertyName = fromBinding.getFromReplacement().getPropertyName();
          EStructuralFeature property =
              insideBoundaryElementPlc.eClass().getEStructuralFeature(propertyName);
          if (property == null)
            throw new GeneralBVREngineException(
                "failed to find property to adjust, property name : " + propertyName);

          validOutsideOHFromPlacementBElements.clear();
          validOutsideOHFromPlacementBElements.addAll(insideBOHElmtsPlcReplaced);

          int upperBound = property.getUpperBound();
          if (upperBound == -1 || upperBound > 1) {
            EList<EObject> values =
                EngineUtility.getListPropertyValue(insideBoundaryElementPlc, property);

            SetView<EObject> invalidOutsideBEFromPlacement =
                Sets.difference(
                    new HashSet<EObject>(EngineUtility.resolveProxies(outsideBOHElmtsPlc)),
                    new HashSet<EObject>(values));
            EList<EObject> elementsToRemove =
                new BasicEList<EObject>(invalidOutsideBEFromPlacement);

            EList<ObjectHandle> invalidObjectHandles =
                findObjectHandlesByEObjects(
                    new BasicEList<EObject>(invalidOutsideBEFromPlacement), outsideBOHElmtsPlc);
            validOutsideOHFromPlacementBElements.addAll(
                Sets.difference(
                    new HashSet<ObjectHandle>(outsideBOHElmtsPlc),
                    new HashSet<ObjectHandle>(invalidObjectHandles)));

            EList<EObject> elementsToAdd = EngineUtility.resolveProxies(insideBOHElmtsPlcReplaced);
            EList<EObject> propertyValueNew =
                EngineUtility.subtractAugmentList(values, elementsToRemove, elementsToAdd);

            if (upperBound != -1 && propertyValueNew.size() > upperBound)
              throw new IllegalBVROperation(
                  "cardinality does not correspond for property : "
                      + propertyName
                      + "of"
                      + fragHolderAdjacent.getFragment());

            EngineUtility.setProperty(values, elementsToRemove, elementsToAdd);

            EList<EObject> propertyValueSet =
                EngineUtility.getListPropertyValue(insideBoundaryElementPlc, property);
            if (!propertyValueNew.equals(propertyValueSet))
              throw new UnexpectedOperationFailure(
                  "EPIC FAIL: property has not been adjusted : '"
                      + propertyName
                      + "' of "
                      + fragHolderAdjacent.getFragment());
          } else {
            // property.getUpperBound() == 0 || == 1
            if (upperBound == 0)
              throw new IncorrectBVRModel(
                  "model is incorrect, cardianlity for reference is set to 0, but something is there "
                      + insideBoundaryElementPlc.eGet(property));

            if (insideBOHElmtsPlcReplaced.size() != upperBound)
              throw new IllegalBVROperation(
                  "cardinality does not match for property : '"
                      + propertyName
                      + "' of "
                      + fragHolderAdjacent.getFragment()
                      + " objects: "
                      + EngineUtility.resolveProxies(insideBOHElmtsPlcReplaced));

            EObject propertyValueNew =
                EngineUtility.resolveProxies(insideBOHElmtsPlcReplaced).get(0);
            EngineUtility.setProperty(insideBoundaryElementPlc, property, propertyValueNew);

            Object propertyValueSet = insideBoundaryElementPlc.eGet(property);
            if (!propertyValueNew.equals(propertyValueSet))
              throw new UnexpectedOperationFailure(
                  "EPIC FAIL: property has not been adjusted : "
                      + propertyName
                      + "of"
                      + fragHolderAdjacent.getFragment());
          }
        }

        // update variability model : boundaries so the point to the correct elements
        fromBinding.getFromPlacement().getOutsideBoundaryElement().clear();
        fromBinding
            .getFromPlacement()
            .getOutsideBoundaryElement()
            .addAll(validOutsideOHFromPlacementBElements);

        HashMap<ToPlacement, HashSet<ObjectHandle>> outsideBoundaryElementsToPlacementMap =
            ((FragmentSubstitutionHolder) fragmentHolderCurrent)
                .getToPlacementOutsideBoundaryElementMap();
        HashSet<ObjectHandle> outsideBoundaryElementsToPlacement =
            outsideBoundaryElementsToPlacementMap.get(toBinding.getToPlacement());
        outsideBoundaryElementsToPlacement.clear();
        outsideBoundaryElementsToPlacement.addAll(insideBoundaryElementsFromPlacement);
      }

      HashMap<FromBinding, ToBinding> adjacentBindingsFromCurrent =
          aFrag.getAdjacentFromBindings(adjacentFragment);
      adjacentBindingsFromCurrent =
          (adjacentBindingsFromCurrent != null)
              ? adjacentBindingsFromCurrent
              : new HashMap<FromBinding, ToBinding>();
      for (Map.Entry<FromBinding, ToBinding> entry : adjacentBindingsFromCurrent.entrySet()) {
        FromBinding fromBinding = entry.getKey();
        ToBinding toBinding = entry.getValue();

        ObjectHandle insideBOHElmtsPlcReplaced =
            fromBinding.getFromPlacement().getInsideBoundaryElement();
        toBinding.getToPlacement().setOutsideBoundaryElement(insideBOHElmtsPlcReplaced);

        HashSet<ObjectHandle> insideBoundaryElementsFromPlacement =
            calculateOutsideBoundaryElementsToPlacementAdjacentToCurrent(
                aFrag, fromBinding.getFromPlacement());
        HashMap<ToPlacement, HashSet<ObjectHandle>> outsideBoundaryElementsToPlacementMap =
            ((FragmentSubstitutionHolder) fragHolderAdjacent)
                .getToPlacementOutsideBoundaryElementMap();
        HashSet<ObjectHandle> outsideBoundaryElementsToPlacement =
            outsideBoundaryElementsToPlacementMap.get(toBinding.getToPlacement());
        outsideBoundaryElementsToPlacement.clear();
        outsideBoundaryElementsToPlacement.addAll(insideBoundaryElementsFromPlacement);
      }
      ((FragmentSubstitutionHolder) fragHolderAdjacent).refresh();
    }
    ((FragmentSubstitutionHolder) fragmentHolderCurrent).refresh();
  }