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;
  }
  @Override
  protected void adjustLocationAndSize(IAddContext context, int width, int height) {

    if (context.getTargetConnection() != null) {
      adjustLocationForDropOnConnection(context);
    }

    super.adjustLocationAndSize(context, width, height);

    if (isImport(context)) {
      return;
    }

    // for backward compatibility with older files that included
    // the label height in the figure height
    if (width != height) {
      width = height = Math.min(width, height);
    }

    if (context instanceof AddContext) {
      AddContext addContext = (AddContext) context;

      addContext.setSize(width, height);
    }
  }
  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);
    }
  }
  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);
        }
      }
    }
  }