private PictogramElement addContainerElement(
      BaseElement element, BpmnMemoryModel model, ContainerShape parent) {
    GraphicInfo graphicInfo = model.getBpmnModel().getGraphicInfo(element.getId());
    if (graphicInfo == null) {
      return null;
    }

    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();

    AddContext context = new AddContext(new AreaContext(), element);
    IAddFeature addFeature = featureProvider.getAddFeature(context);
    context.setNewObject(element);
    context.setSize((int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
    context.setTargetContainer(parent);

    int x = (int) graphicInfo.getX();
    int y = (int) graphicInfo.getY();

    if (parent instanceof Diagram == false) {
      x = x - parent.getGraphicsAlgorithm().getX();
      y = y - parent.getGraphicsAlgorithm().getY();
    }

    context.setLocation(x, y);

    PictogramElement pictElement = null;
    if (addFeature.canAdd(context)) {
      pictElement = addFeature.add(context);
      featureProvider.link(pictElement, new Object[] {element});
    }

    return pictElement;
  }
  public void paste(IPasteContext context) {
    // we already verified, that we paste directly in the diagram
    KickstartProcessMemoryModel model =
        ModelHandler.getKickstartProcessModel(EcoreUtil.getURI(getDiagram()));
    List<FlowElement> copyList = model.getClipboard();

    for (FlowElement element : copyList) {
      FlowElement clone = CloneUtil.clone(element, getDiagram());

      AddContext addContext = new AddContext(new AreaContext(), clone);
      IAddFeature addFeature = getFeatureProvider().getAddFeature(addContext);
      PictogramElement pictogram =
          getFeatureProvider().getPictogramElementForBusinessObject(element);
      addContext.setLocation(
          pictogram.getGraphicsAlgorithm().getX() + PASTE_OFFSET,
          pictogram.getGraphicsAlgorithm().getY() + PASTE_OFFSET);
      addContext.setSize(
          pictogram.getGraphicsAlgorithm().getWidth(),
          pictogram.getGraphicsAlgorithm().getHeight());
      addContext.setTargetContainer(getDiagram());
      if (addFeature.canAdd(addContext)) {
        addFeature.add(addContext);
      }
    }
  }
  private void drawArtifacts(
      final Collection<Artifact> artifacts,
      final Map<String, GraphicInfo> locationMap,
      final ContainerShape parent,
      final Process process) {

    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();

    final List<Artifact> artifactsWithoutDI = new ArrayList<Artifact>();
    for (final Artifact artifact : artifacts) {

      if (artifact instanceof Association) {
        continue;
      }

      final AddContext context = new AddContext(new AreaContext(), artifact);
      final IAddFeature addFeature = featureProvider.getAddFeature(context);

      if (addFeature == null) {
        System.out.println("Element not supported: " + artifact);
        return;
      }

      final GraphicInfo gi = locationMap.get(artifact.getId());
      if (gi == null) {
        artifactsWithoutDI.add(artifact);
      } else {
        context.setNewObject(artifact);
        context.setSize((int) gi.getWidth(), (int) gi.getHeight());

        ContainerShape parentContainer = null;
        if (parent instanceof Diagram) {
          parentContainer = getParentContainer(artifact.getId(), process, (Diagram) parent);
        } else {
          parentContainer = parent;
        }

        context.setTargetContainer(parentContainer);
        if (parentContainer instanceof Diagram) {
          context.setLocation((int) gi.getX(), (int) gi.getY());
        } else {
          final Point location = getLocation(parentContainer);

          context.setLocation((int) gi.getX() - location.x, (int) gi.getY() - location.y);
        }

        if (addFeature.canAdd(context)) {
          final PictogramElement newContainer = addFeature.add(context);
          featureProvider.link(newContainer, new Object[] {artifact});
        }
      }
    }

    for (final Artifact artifact : artifactsWithoutDI) {
      artifacts.remove(artifact);
    }
  }
  protected void addEnumToDiagram(
      IFeatureProvider fp, Diagram diagram, int x, int y, String enumName) {

    // create add context
    AreaContext areaContext = new AreaContext();
    areaContext.setLocation(x, y);
    EEnum newEEnum = createEEnum(diagram, enumName);
    AddContext addContext = new AddContext(areaContext, newEEnum);
    addContext.setTargetContainer(diagram);

    // get add class feature
    IAddFeature addFeature = fp.getAddFeature(addContext);
    assertNotNull("add class feature not available", addFeature);

    if (addFeature.canAdd(addContext)) {
      addFeature.execute(addContext);
    }
  }
  private void drawFlowElements(
      Collection<FlowElement> elementList,
      Map<String, GraphicInfo> locationMap,
      ContainerShape parentShape,
      Process process) {

    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();

    List<FlowElement> noDIList = new ArrayList<FlowElement>();
    for (FlowElement flowElement : elementList) {

      if (flowElement instanceof SequenceFlow) {
        continue;
      }

      AddContext context = new AddContext(new AreaContext(), flowElement);
      IAddFeature addFeature = featureProvider.getAddFeature(context);

      if (addFeature == null) {
        System.out.println("Element not supported: " + flowElement);
        return;
      }

      GraphicInfo graphicInfo = locationMap.get(flowElement.getId());
      if (graphicInfo == null) {

        noDIList.add(flowElement);

      } else {

        context.setNewObject(flowElement);
        context.setSize((int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());

        ContainerShape parentContainer = null;
        if (parentShape instanceof Diagram) {
          parentContainer = getParentContainer(flowElement.getId(), process, (Diagram) parentShape);
        } else {
          parentContainer = parentShape;
        }

        context.setTargetContainer(parentContainer);
        if (parentContainer instanceof Diagram == false) {
          Point location = getLocation(parentContainer);
          context.setLocation(
              (int) graphicInfo.getX() - location.x, (int) graphicInfo.getY() - location.y);
        } else {
          context.setLocation((int) graphicInfo.getX(), (int) graphicInfo.getY());
        }

        if (flowElement instanceof ServiceTask) {

          ServiceTask serviceTask = (ServiceTask) flowElement;

          if (serviceTask.isExtended()) {

            CustomServiceTask targetTask = findCustomServiceTask(serviceTask);

            if (targetTask != null) {

              for (FieldExtension field : serviceTask.getFieldExtensions()) {
                CustomProperty customFieldProperty = new CustomProperty();
                customFieldProperty.setName(field.getFieldName());
                if (StringUtils.isNotEmpty(field.getExpression())) {
                  customFieldProperty.setSimpleValue(field.getExpression());
                } else {
                  customFieldProperty.setSimpleValue(field.getStringValue());
                }
                serviceTask.getCustomProperties().add(customFieldProperty);
              }

              serviceTask.getFieldExtensions().clear();
            }
          }
        }

        if (flowElement instanceof BoundaryEvent) {
          BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
          if (boundaryEvent.getAttachedToRef() != null) {
            ContainerShape container =
                (ContainerShape)
                    featureProvider.getPictogramElementForBusinessObject(
                        boundaryEvent.getAttachedToRef());

            if (container != null) {
              AddContext boundaryContext = new AddContext(new AreaContext(), boundaryEvent);
              boundaryContext.setTargetContainer(container);
              Point location = getLocation(container);
              boundaryContext.setLocation(
                  (int) graphicInfo.getX() - location.x, (int) graphicInfo.getY() - location.y);

              if (addFeature.canAdd(boundaryContext)) {
                PictogramElement newBoundaryContainer = addFeature.add(boundaryContext);
                // featureProvider.link(newBoundaryContainer, new Object[] { boundaryEvent });
              }
            }
          }
        } else if (addFeature.canAdd(context)) {
          PictogramElement newContainer = addFeature.add(context);
          featureProvider.link(newContainer, new Object[] {flowElement});

          if (flowElement instanceof SubProcess) {
            drawFlowElements(
                ((SubProcess) flowElement).getFlowElements(),
                locationMap,
                (ContainerShape) newContainer,
                process);
          }
        }
      }
    }

    for (FlowElement flowElement : noDIList) {
      if (flowElement instanceof BoundaryEvent) {
        ((BoundaryEvent) flowElement).getAttachedToRef().getBoundaryEvents().remove(flowElement);
      } else {
        elementList.remove(flowElement);
      }
    }
  }
  protected void drawArtifacts(
      final FlowElementsContainer container,
      final Map<String, GraphicInfo> locationMap,
      final ContainerShape parent,
      final Process process) {

    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();

    final List<Artifact> artifactsWithoutDI = new ArrayList<Artifact>();
    for (final Artifact artifact : container.getArtifacts()) {

      if (artifact instanceof Association) {
        continue;
      }

      final AddContext context = new AddContext(new AreaContext(), artifact);
      final IAddFeature addFeature = featureProvider.getAddFeature(context);

      if (addFeature == null) {
        System.out.println("Element not supported: " + artifact);
        return;
      }

      final GraphicInfo gi = locationMap.get(artifact.getId());
      if (gi == null) {
        artifactsWithoutDI.add(artifact);
      } else {
        context.setNewObject(artifact);
        context.setSize((int) gi.getWidth(), (int) gi.getHeight());

        ContainerShape parentContainer = null;
        if (parent instanceof Diagram) {
          FlowElement connectingElement = null;
          for (final Artifact associationArtifact : container.getArtifacts()) {
            if (associationArtifact instanceof Association) {
              Association association = (Association) associationArtifact;

              if (association.getSourceRef().equals(artifact.getId())) {
                connectingElement = container.getFlowElement(association.getTargetRef());

              } else if (association.getTargetRef().equals(artifact.getId())) {
                connectingElement = container.getFlowElement(association.getSourceRef());
              }
            }
          }

          if (connectingElement != null) {
            parentContainer =
                getParentContainer(connectingElement.getId(), process, (Diagram) parent);
          } else {
            parentContainer = parent;
          }
        } else {
          parentContainer = parent;
        }

        context.setTargetContainer(parentContainer);
        if (parentContainer instanceof Diagram) {
          context.setLocation((int) gi.getX(), (int) gi.getY());
        } else {
          final Point location = getLocation(parentContainer);

          context.setLocation((int) gi.getX() - location.x, (int) gi.getY() - location.y);
        }

        if (addFeature.canAdd(context)) {
          final PictogramElement newContainer = addFeature.add(context);
          featureProvider.link(newContainer, new Object[] {artifact});
        }
      }
    }

    for (final Artifact artifact : artifactsWithoutDI) {
      container.getArtifacts().remove(artifact);
    }

    for (FlowElement flowElement : container.getFlowElements()) {
      if (flowElement instanceof SubProcess) {
        ContainerShape subProcessShape =
            (ContainerShape) featureProvider.getPictogramElementForBusinessObject(flowElement);
        drawArtifacts((SubProcess) flowElement, locationMap, subProcessShape, process);
      }
    }
  }
  @SuppressWarnings({"rawtypes", "unchecked"})
  protected void drawFlowElements(
      Collection<FlowElement> elementList,
      Map<String, GraphicInfo> locationMap,
      ContainerShape parentShape,
      Process process) {

    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();

    List<FlowElement> noDIList = new ArrayList<FlowElement>();
    for (FlowElement flowElement : elementList) {

      if (flowElement instanceof SequenceFlow) {
        continue;
      }

      AddContext context = new AddContext(new AreaContext(), flowElement);
      IAddFeature addFeature = featureProvider.getAddFeature(context);

      if (addFeature == null) {
        System.out.println("Element not supported: " + flowElement);
        return;
      }

      GraphicInfo graphicInfo = locationMap.get(flowElement.getId());
      if (graphicInfo == null) {

        noDIList.add(flowElement);

      } else {

        context.setNewObject(flowElement);
        context.setSize((int) graphicInfo.getWidth(), (int) graphicInfo.getHeight());
        ContainerShape parentContainer = null;
        if (parentShape instanceof Diagram) {
          parentContainer = getParentContainer(flowElement.getId(), process, (Diagram) parentShape);
        } else {
          parentContainer = parentShape;
        }

        context.setTargetContainer(parentContainer);
        if (parentContainer instanceof Diagram == false) {
          Point location = getLocation(parentContainer);
          context.setLocation(
              (int) graphicInfo.getX() - location.x, (int) graphicInfo.getY() - location.y);
        } else {
          context.setLocation((int) graphicInfo.getX(), (int) graphicInfo.getY());
        }

        if (flowElement instanceof ServiceTask) {

          ServiceTask serviceTask = (ServiceTask) flowElement;

          if (serviceTask.isExtended()) {

            CustomServiceTask targetTask = findCustomServiceTask(serviceTask);

            if (targetTask != null) {

              for (FieldExtension field : serviceTask.getFieldExtensions()) {
                CustomProperty customFieldProperty = new CustomProperty();
                customFieldProperty.setName(field.getFieldName());
                if (StringUtils.isNotEmpty(field.getExpression())) {
                  customFieldProperty.setSimpleValue(field.getExpression());
                } else {
                  customFieldProperty.setSimpleValue(field.getStringValue());
                }
                serviceTask.getCustomProperties().add(customFieldProperty);
              }

              serviceTask.getFieldExtensions().clear();
            }
          }

        } else if (flowElement instanceof UserTask) {

          UserTask userTask = (UserTask) flowElement;

          if (userTask.isExtended()) {

            CustomUserTask targetTask = findCustomUserTask(userTask);

            if (targetTask != null) {

              final List<Class<CustomUserTask>> classHierarchy =
                  new ArrayList<Class<CustomUserTask>>();
              final List<String> fieldInfoObjects = new ArrayList<String>();

              Class clazz = targetTask.getClass();
              classHierarchy.add(clazz);

              boolean hierarchyOpen = true;
              while (hierarchyOpen) {
                clazz = clazz.getSuperclass();
                if (CustomUserTask.class.isAssignableFrom(clazz)) {
                  classHierarchy.add(clazz);
                } else {
                  hierarchyOpen = false;
                }
              }

              for (final Class<CustomUserTask> currentClass : classHierarchy) {
                for (final Field field : currentClass.getDeclaredFields()) {
                  if (field.isAnnotationPresent(Property.class)) {
                    fieldInfoObjects.add(field.getName());
                  }
                }
              }

              for (String fieldName : userTask.getExtensionElements().keySet()) {
                if (fieldInfoObjects.contains(fieldName)) {
                  CustomProperty customFieldProperty = new CustomProperty();
                  customFieldProperty.setName(fieldName);
                  customFieldProperty.setSimpleValue(
                      userTask.getExtensionElements().get(fieldName).get(0).getElementText());
                  userTask.getCustomProperties().add(customFieldProperty);
                }
              }

              for (String fieldName : fieldInfoObjects) {
                userTask.getExtensionElements().remove(fieldName);
              }
            }
          }
        }

        if (flowElement instanceof BoundaryEvent) {
          BoundaryEvent boundaryEvent = (BoundaryEvent) flowElement;
          if (boundaryEvent.getAttachedToRef() != null) {
            ContainerShape container =
                (ContainerShape)
                    featureProvider.getPictogramElementForBusinessObject(
                        boundaryEvent.getAttachedToRef());

            if (container != null) {
              AddContext boundaryContext = new AddContext(new AreaContext(), boundaryEvent);
              boundaryContext.setTargetContainer(container);
              Point location = getLocation(container);
              boundaryContext.setLocation(
                  (int) graphicInfo.getX() - location.x, (int) graphicInfo.getY() - location.y);

              if (addFeature.canAdd(boundaryContext)) {
                addFeature.add(boundaryContext);
              }
            }
          }
        } else if (addFeature.canAdd(context)) {
          PictogramElement newContainer = addFeature.add(context);
          featureProvider.link(newContainer, new Object[] {flowElement});

          if (flowElement instanceof SubProcess) {
            drawFlowElements(
                ((SubProcess) flowElement).getFlowElements(),
                locationMap,
                (ContainerShape) newContainer,
                process);
          }
        }
      }
    }

    for (FlowElement flowElement : noDIList) {
      if (flowElement instanceof BoundaryEvent) {
        ((BoundaryEvent) flowElement).getAttachedToRef().getBoundaryEvents().remove(flowElement);
      } else {
        // do not remove Data Objects
        if (flowElement instanceof DataObject == false) {
          elementList.remove(flowElement);
        }
      }
    }
  }
    private void updateConnectionIfNeeded(DataAssociation association, ItemAwareElement value) {
      DiagramEditor diagramEditor = ModelUtil.getDiagramEditor(association);
      if (diagramEditor == null) return;
      boolean hasDoneChanges = false;
      Diagram diagram = diagramEditor.getDiagramTypeProvider().getDiagram();
      IFeatureProvider fp = diagramEditor.getDiagramTypeProvider().getFeatureProvider();
      Shape taskShape = null;
      EObject container = association.eContainer();
      if (container instanceof Activity || container instanceof Event) {
        for (PictogramElement pe :
            Graphiti.getLinkService().getPictogramElements(diagram, container)) {
          if (pe instanceof Shape
              && BusinessObjectUtil.getFirstElementOfType(pe, BPMNShape.class) != null) {
            taskShape = (Shape) pe;
            break;
          }
        }
      }

      Shape dataShape = null;
      if (value instanceof DataObject
          || value instanceof DataObjectReference
          || value instanceof DataStore
          || value instanceof DataStoreReference
          || value instanceof DataInput
          || value instanceof DataOutput) {
        List<PictogramElement> pes =
            Graphiti.getLinkService().getPictogramElements(diagram, (EObject) value);
        for (PictogramElement p : pes) {
          if (BusinessObjectUtil.getFirstElementOfType(p, BPMNShape.class) != null) {
            dataShape = (Shape) p;
            break;
          }
        }
      }

      Connection connection =
          DataAssociationFeatureContainer.findDataAssociation(diagram, association);
      if (connection != null) {
        // There's an existing DataAssociation connection which needs to
        // either be reconnected or deleted, depending on what the combobox
        // selection is.
        if (dataShape != null) {
          // need to reconnect the DataAssociation
          ReconnectionContext rc = null;
          if (association instanceof DataInputAssociation) {
            Point p = GraphicsUtil.createPoint(connection.getStart());
            Anchor a = AnchorUtil.createAnchor((AnchorContainer) dataShape, p);
            rc = new ReconnectionContext(connection, connection.getStart(), a, null);
            rc.setTargetPictogramElement(dataShape);
            rc.setTargetLocation(Graphiti.getPeService().getLocationRelativeToDiagram(a));
            rc.setReconnectType(ReconnectionContext.RECONNECT_SOURCE);
          } else {
            Point p = GraphicsUtil.createPoint(connection.getEnd());
            Anchor a = AnchorUtil.createAnchor(dataShape, p);
            rc = new ReconnectionContext(connection, a, connection.getEnd(), null);
            rc.setTargetPictogramElement(dataShape);
            rc.setTargetLocation(Graphiti.getPeService().getLocationRelativeToDiagram(a));
            rc.setReconnectType(ReconnectionContext.RECONNECT_TARGET);
          }
          IReconnectionFeature rf = fp.getReconnectionFeature(rc);
          if (rf.canReconnect(rc)) {
            rf.reconnect(rc);
            hasDoneChanges = true;
          }
        } else {
          // need to delete the DataAssociation connection
          DeleteContext dc = new DeleteContext(connection);
          connection.getLink().getBusinessObjects().remove(0);
          IDeleteFeature df = fp.getDeleteFeature(dc);
          df.delete(dc);
        }
      } else if (dataShape != null) {
        // There is no existing DataAssociation connection, but the newly selected source or target
        // is some kind of data object shape, so we need to create a connection between the Activity
        // (or Throw/Catch Event) that owns the DataAssociation, and the new data object shape.
        Point p = GraphicsUtil.createPoint((AnchorContainer) dataShape);
        Anchor ownerAnchor = AnchorUtil.createAnchor(taskShape, p);
        p = GraphicsUtil.createPoint(taskShape);
        Anchor peAnchor = AnchorUtil.createAnchor((AnchorContainer) dataShape, p);
        AddConnectionContext ac = null;
        if (association instanceof DataOutputAssociation) {
          ac = new AddConnectionContext(ownerAnchor, peAnchor);
        } else {
          ac = new AddConnectionContext(peAnchor, ownerAnchor);
        }
        ac.putProperty(GraphitiConstants.BUSINESS_OBJECT, association);
        ac.setNewObject(association);
        IAddFeature af = fp.getAddFeature(ac);
        if (af.canAdd(ac)) {
          PictogramElement pe = af.add(ac);
          if (pe instanceof Connection) {
            connection = (Connection) pe;
            hasDoneChanges = true;
          }
        }
      }
      if (hasDoneChanges) {
        FeatureSupport.updateConnection(
            diagramEditor.getDiagramTypeProvider().getFeatureProvider(), connection);
      }
    }