@Override
  protected Object getBusinessObject(PictogramElement element) {
    if (element == null) return null;

    BpmnMemoryModel model = getModel(element);
    if (element instanceof Diagram) {

      if (model.getBpmnModel().getMainProcess() != null) {
        return model.getBpmnModel().getMainProcess();
      }
    }

    ActivitiBPMNFeatureProvider featureProvider = getFeatureProvider(element);
    if (featureProvider != null) {
      Object bo = featureProvider.getBusinessObjectForPictogramElement(element);
      if (bo instanceof Pool) {
        return model.getBpmnModel().getProcess(((Pool) bo).getId());
      } else if (bo instanceof Lane) {
        return ((Lane) bo).getParentProcess();
      } else if (bo instanceof SubProcess) {
        return ((SubProcess) bo);
      }
    }
    return null;
  }
  private void doSaveImage(final String diagramFileString, BpmnMemoryModel model) {
    boolean saveImage =
        PreferencesUtil.getBooleanPreference(Preferences.SAVE_IMAGE, ActivitiPlugin.getDefault());
    if (saveImage) {
      List<String> languages =
          PreferencesUtil.getStringArray(
              Preferences.ACTIVITI_LANGUAGES, ActivitiPlugin.getDefault());
      if (languages != null && languages.size() > 0) {

        for (String language : languages) {
          for (Process process : model.getBpmnModel().getProcesses()) {
            fillContainerWithLanguage(process, language);
          }

          ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
          InputStream imageStream =
              processDiagramGenerator.generatePngDiagram(model.getBpmnModel());

          if (imageStream != null) {
            String imageFileName = null;
            if (diagramFileString.endsWith(".bpmn20.xml")) {
              imageFileName =
                  diagramFileString.substring(0, diagramFileString.length() - 11)
                      + "_"
                      + language
                      + ".png";
            } else {
              imageFileName =
                  diagramFileString.substring(0, diagramFileString.lastIndexOf("."))
                      + "_"
                      + language
                      + ".png";
            }
            File imageFile = new File(imageFileName);
            FileOutputStream outStream = null;
            ByteArrayOutputStream baos = null;
            try {
              outStream = new FileOutputStream(imageFile);
              baos = new ByteArrayOutputStream();
              IOUtils.copy(imageStream, baos);
              baos.writeTo(outStream);

            } catch (Exception e) {
              e.printStackTrace();
            } finally {
              if (outStream != null) {
                IOUtils.closeQuietly(outStream);
              }
              if (baos != null) {
                IOUtils.closeQuietly(baos);
              }
            }
          }
        }

      } else {
        marshallImage(model, diagramFileString);
      }
    }
  }
 @Override
 public void postReconnect(IReconnectionContext context) {
   Object connectionObject =
       getFeatureProvider().getBusinessObjectForPictogramElement(context.getConnection());
   if (connectionObject instanceof MessageFlow) {
     FlowNode source = null;
     FlowNode target = null;
     MessageFlow messageFlow = (MessageFlow) connectionObject;
     BpmnMemoryModel memoryModel = ModelHandler.getModel(EcoreUtil.getURI(getDiagram()));
     memoryModel.getBpmnModel().getMessageFlows().remove(messageFlow);
     if (context.getReconnectType().equalsIgnoreCase(ReconnectionContext.RECONNECT_TARGET)) {
       source = getFlowNode(context.getConnection().getStart());
       target = getFlowNode(context.getNewAnchor());
     } else {
       source = getFlowNode(context.getNewAnchor());
       target = getFlowNode(context.getConnection().getEnd());
     }
     messageFlow.setSourceRef(source.getId());
     messageFlow.setTargetRef(target.getId());
     memoryModel.getBpmnModel().getMessageFlows().add(messageFlow);
     undoedSource = messageFlow.getSourceRef();
     undoedTarget = messageFlow.getTargetRef();
   } else {
     return;
   }
   super.postReconnect(context);
 }
  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;
  }
  private void drawAllFlows(BpmnMemoryModel model) {
    BpmnModel bpmnModel = model.getBpmnModel();

    for (Process process : bpmnModel.getProcesses()) {
      drawSequenceFlowsInList(process.getFlowElements(), model);
      drawAssociationsInList(process.getArtifacts(), model);
    }
  }
  private void doSaveToBpmn(final BpmnMemoryModel model, final String diagramFileString)
      throws Exception {

    // add sequence flow bend-points to the model
    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();
    new GraphitiToBpmnDI(model, featureProvider).processGraphitiElements();

    BpmnXMLConverter converter = new BpmnXMLConverter();
    byte[] xmlBytes = converter.convertToXML(model.getBpmnModel());

    File objectsFile = new File(diagramFileString);
    FileOutputStream fos = new FileOutputStream(objectsFile);
    fos.write(xmlBytes);
    fos.close();
  }
  protected void doSaveToBpmn(final BpmnMemoryModel model, final String diagramFileString)
      throws Exception {

    // add sequence flow bend-points to the model
    final IFeatureProvider featureProvider = getDiagramTypeProvider().getFeatureProvider();
    new GraphitiToBpmnDI(model, featureProvider).processGraphitiElements();

    BpmnXMLConverter converter = new BpmnXMLConverter();
    byte[] xmlBytes = converter.convertToXML(model.getBpmnModel());

    File objectsFile = new File(diagramFileString);
    try {
      FileOutputStream fos = new FileOutputStream(objectsFile);
      fos.write(xmlBytes);
      fos.close();
    } catch (Exception e) {
      MessageBox messageBox =
          new MessageBox(Display.getCurrent().getActiveShell(), SWT.ICON_WARNING | SWT.OK);
      messageBox.setText("Warning");
      messageBox.setMessage("Error while saving the model " + e.getLocalizedMessage());
      messageBox.open();
    }
  }
  private void drawAssociation(Association association, BpmnMemoryModel model) {

    Anchor sourceAnchor = null;
    Anchor targetAnchor = null;
    BaseElement sourceElement = model.getFlowElement(association.getSourceRef());
    if (sourceElement == null) {
      sourceElement = model.getArtifact(association.getSourceRef());
    }
    if (sourceElement == null) {
      return;
    }
    ContainerShape sourceShape =
        (ContainerShape)
            getDiagramTypeProvider()
                .getFeatureProvider()
                .getPictogramElementForBusinessObject(sourceElement);

    if (sourceShape == null) {
      return;
    }

    EList<Anchor> anchorList = sourceShape.getAnchors();
    for (Anchor anchor : anchorList) {
      if (anchor instanceof ChopboxAnchor) {
        sourceAnchor = anchor;
        break;
      }
    }

    BaseElement targetElement = model.getFlowElement(association.getTargetRef());
    if (targetElement == null) {
      targetElement = model.getArtifact(association.getTargetRef());
    }
    if (targetElement == null) {
      return;
    }
    ContainerShape targetShape =
        (ContainerShape)
            getDiagramTypeProvider()
                .getFeatureProvider()
                .getPictogramElementForBusinessObject(targetElement);

    if (targetShape == null) {
      return;
    }

    anchorList = targetShape.getAnchors();
    for (Anchor anchor : anchorList) {
      if (anchor instanceof ChopboxAnchor) {
        targetAnchor = anchor;
        break;
      }
    }

    AddConnectionContext addContext = new AddConnectionContext(sourceAnchor, targetAnchor);

    List<GraphicInfo> bendpointList = new ArrayList<GraphicInfo>();
    if (model.getBpmnModel().getFlowLocationMap().containsKey(association.getId())) {
      List<GraphicInfo> pointList =
          model.getBpmnModel().getFlowLocationGraphicInfo(association.getId());
      if (pointList.size() > 2) {
        for (int i = 1; i < pointList.size() - 1; i++) {
          bendpointList.add(pointList.get(i));
        }
      }
    }

    addContext.putProperty("org.activiti.designer.bendpoints", bendpointList);

    addContext.setNewObject(association);
    getDiagramTypeProvider().getFeatureProvider().addIfPossible(addContext);
  }
  @Override
  protected void setInput(IEditorInput input) {
    super.setInput(input);

    final ActivitiDiagramEditorInput adei = (ActivitiDiagramEditorInput) input;
    final IFile dataFile = adei.getDataFile();

    final BpmnMemoryModel model =
        new BpmnMemoryModel(getDiagramTypeProvider().getFeatureProvider(), dataFile);
    ModelHandler.addModel(EcoreUtil.getURI(getDiagramTypeProvider().getDiagram()), model);

    String filePath = dataFile.getLocationURI().getPath();
    File bpmnFile = new File(filePath);
    try {
      if (bpmnFile.exists() == false) {
        model.setBpmnModel(new BpmnModel());
        model.addMainProcess();
        bpmnFile.createNewFile();
        dataFile.refreshLocal(IResource.DEPTH_INFINITE, null);
      } else {
        FileInputStream fileStream = new FileInputStream(bpmnFile);
        XMLInputFactory xif = XMLInputFactory.newInstance();
        InputStreamReader in = new InputStreamReader(fileStream, "UTF-8");
        XMLStreamReader xtr = xif.createXMLStreamReader(in);
        BpmnXMLConverter bpmnConverter = new BpmnXMLConverter();
        bpmnConverter.setUserTaskFormTypes(
            PreferencesUtil.getStringArray(Preferences.ALFRESCO_FORMTYPES_USERTASK));
        bpmnConverter.setStartEventFormTypes(
            PreferencesUtil.getStringArray(Preferences.ALFRESCO_FORMTYPES_STARTEVENT));
        BpmnModel bpmnModel = null;
        try {
          bpmnModel = bpmnConverter.convertToBpmnModel(xtr);
        } catch (Exception e) {
          bpmnModel = new BpmnModel();
        }
        model.setBpmnModel(bpmnModel);

        if (bpmnModel.getLocationMap().size() == 0) {
          BpmnAutoLayout layout = new BpmnAutoLayout(bpmnModel);
          layout.execute();
        }

        BasicCommandStack basicCommandStack =
            (BasicCommandStack) getEditingDomain().getCommandStack();

        if (input instanceof DiagramEditorInput) {

          basicCommandStack.execute(
              new RecordingCommand(getEditingDomain()) {

                @Override
                protected void doExecute() {
                  importDiagram(model);
                }
              });
        }
        basicCommandStack.saveIsDone();
        basicCommandStack.flush();
      }

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  private void marshallImage(BpmnMemoryModel model, String modelFileName) {
    try {
      final GraphicalViewer graphicalViewer =
          (GraphicalViewer)
              ((DiagramEditor)
                      model.getFeatureProvider().getDiagramTypeProvider().getDiagramEditor())
                  .getAdapter(GraphicalViewer.class);

      if (graphicalViewer == null || graphicalViewer.getEditPartRegistry() == null) {
        return;
      }
      final ScalableFreeformRootEditPart rootEditPart =
          (ScalableFreeformRootEditPart) graphicalViewer.getEditPartRegistry().get(LayerManager.ID);
      final IFigure rootFigure =
          ((LayerManager) rootEditPart).getLayer(LayerConstants.PRINTABLE_LAYERS);
      final IFigure gridFigure = ((LayerManager) rootEditPart).getLayer(LayerConstants.GRID_LAYER);
      final Rectangle rootFigureBounds = rootFigure.getBounds();

      final boolean toggleRequired = gridFigure.isShowing();

      final Display display = Display.getDefault();

      final Image img = new Image(display, rootFigureBounds.width, rootFigureBounds.height);
      final GC imageGC = new GC(img);
      final SWTGraphics grap = new SWTGraphics(imageGC);

      // Access UI thread from runnable to print the canvas to the image
      display.syncExec(
          new Runnable() {

            @Override
            public void run() {
              if (toggleRequired) {
                // Disable any grids temporarily
                gridFigure.setVisible(false);
              }
              // Deselect any selections
              graphicalViewer.deselectAll();
              rootFigure.paint(grap);
            }
          });

      ImageLoader imgLoader = new ImageLoader();
      imgLoader.data = new ImageData[] {img.getImageData()};

      ByteArrayOutputStream baos = new ByteArrayOutputStream(imgLoader.data.length);

      imgLoader.save(baos, SWT.IMAGE_PNG);

      imageGC.dispose();
      img.dispose();

      // Access UI thread from runnable
      display.syncExec(
          new Runnable() {

            @Override
            public void run() {
              if (toggleRequired) {
                // Re-enable any grids
                gridFigure.setVisible(true);
              }
            }
          });

      String imageFileName = null;
      if (modelFileName.endsWith(".bpmn20.xml")) {
        imageFileName = modelFileName.substring(0, modelFileName.length() - 11) + ".png";
      } else {
        imageFileName = modelFileName.substring(0, modelFileName.lastIndexOf(".")) + ".png";
      }
      File imageFile = new File(imageFileName);
      FileOutputStream outStream = new FileOutputStream(imageFile);
      baos.writeTo(outStream);

    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  protected void drawMessageFlows(
      final Collection<MessageFlow> messageFlows, final BpmnMemoryModel model) {

    for (final MessageFlow messageFlow : messageFlows) {

      Anchor sourceAnchor = null;
      Anchor targetAnchor = null;
      ContainerShape sourceShape =
          (ContainerShape)
              getDiagramTypeProvider()
                  .getFeatureProvider()
                  .getPictogramElementForBusinessObject(
                      model.getFlowElement(messageFlow.getSourceRef()));

      if (sourceShape == null) {
        continue;
      }

      EList<Anchor> anchorList = sourceShape.getAnchors();
      for (Anchor anchor : anchorList) {
        if (anchor instanceof ChopboxAnchor) {
          sourceAnchor = anchor;
          break;
        }
      }

      ContainerShape targetShape =
          (ContainerShape)
              getDiagramTypeProvider()
                  .getFeatureProvider()
                  .getPictogramElementForBusinessObject(
                      model.getFlowElement(messageFlow.getTargetRef()));

      if (targetShape == null) {
        continue;
      }

      anchorList = targetShape.getAnchors();
      for (Anchor anchor : anchorList) {
        if (anchor instanceof ChopboxAnchor) {
          targetAnchor = anchor;
          break;
        }
      }

      AddConnectionContext addContext = new AddConnectionContext(sourceAnchor, targetAnchor);

      List<GraphicInfo> bendpointList = new ArrayList<GraphicInfo>();
      if (model.getBpmnModel().getFlowLocationMap().containsKey(messageFlow.getId())) {
        List<GraphicInfo> pointList =
            model.getBpmnModel().getFlowLocationGraphicInfo(messageFlow.getId());
        if (pointList.size() > 2) {
          for (int i = 1; i < pointList.size() - 1; i++) {
            bendpointList.add(pointList.get(i));
          }
        }
      }
      addContext.putProperty("org.activiti.designer.bendpoints", bendpointList);
      addContext.putProperty(
          "org.activiti.designer.connectionlabel",
          model.getBpmnModel().getLabelGraphicInfo(messageFlow.getId()));

      addContext.setNewObject(messageFlow);
      getDiagramTypeProvider().getFeatureProvider().addIfPossible(addContext);
    }
  }
  @Override
  public boolean canReconnect(IReconnectionContext context) {
    FlowNode source = null;
    FlowNode target = null;
    Object target2 = null;
    Object targetContainer = null;
    Object targetContainer2 = null;
    Object sourceContainer = null;
    Object targetContainerParent = null;
    Object sourceContainerParent = null;
    Object sourceContainerParent2 = null;
    if (context.getReconnectType().equals(ReconnectionContext.RECONNECT_TARGET)) {
      source = getFlowNode(context.getConnection().getStart());
      target = getFlowNode(context.getNewAnchor());
      targetContainer =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getNewAnchor().getParent().eContainer());
      sourceContainer =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getConnection().getStart().eContainer().eContainer());
      targetContainerParent =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getNewAnchor().getParent().eContainer().eContainer());
      sourceContainerParent =
          getBusinessObjectForPictogramElement(
              (PictogramElement)
                  context.getConnection().getStart().getParent().eContainer().eContainer());
      // sourceContainerParent2 =
      // getBusinessObjectForPictogramElement((PictogramElement)context.getConnection().getStart().getParent().eContainer().eContainer().eContainer());
      // sourceContainerParent2 =
      // getBusinessObjectForPictogramElement((PictogramElement)context.getConnection().getStart().getParent().eContainer().eContainer().eContainer());
    } else {
      source = getFlowNode(context.getNewAnchor());
      target = getFlowNode(context.getConnection().getEnd());
      targetContainer =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getConnection().getEnd().eContainer().eContainer());
      targetContainer2 =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getConnection().getStart().eContainer().eContainer());
      sourceContainer =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getNewAnchor().getParent().eContainer());
      targetContainerParent =
          getBusinessObjectForPictogramElement(
              (PictogramElement)
                  context.getConnection().getEnd().getParent().eContainer().eContainer());
      sourceContainerParent =
          getBusinessObjectForPictogramElement(
              (PictogramElement) context.getNewAnchor().getParent().eContainer().eContainer());
      // sourceContainerParent2 =
      // getBusinessObjectForPictogramElement((PictogramElement)context.getNewAnchor().getParent().eContainer().eContainer().eContainer());
    }

    if (source != null && target != null && source != target) {
      BpmnMemoryModel memoryModel = ModelHandler.getModel(EcoreUtil.getURI(getDiagram()));
      Process sourceProcess = null;
      Process targetProcess = null;
      for (Process proc : memoryModel.getBpmnModel().getProcesses()) {
        if (proc.getFlowElement(source.getId()) != null) {
          sourceProcess = proc;
        }
        if (proc.getFlowElement(target.getId()) != null) {
          targetProcess = proc;
        }
      }

      /*if(context.getReconnectType().equals(ReconnectionContext.RECONNECT_TARGET)
      		&& sourceContainer instanceof SubProcess
      		&& target instanceof SubProcess){
      	return true;
      }*/

      // **New rules - SZ
      if (source instanceof ServiceTask
          || source instanceof UserTask
          || source instanceof ScriptTask
          || target instanceof ServiceTask
          || target instanceof UserTask
          || target instanceof ScriptTask
          || source instanceof ReceiveTask
          || source instanceof StartEvent
          // || source instanceof BoundaryEvent &&
          // ((BoundaryEvent)source).getEventDefinitions().get(0) instanceof MessageEventDefinition
          || target instanceof SendTask
          // || source instanceof IntermediateCatchEvent &&
          // ((IntermediateCatchEvent)source).getEventDefinitions().get(0) instanceof
          // MessageEventDefinition
          || target instanceof StartEvent
              && !(((StartEvent) target).getEventDefinitions().get(0)
                  instanceof MessageEventDefinition)) {
        return false;
      }
      // **

      // System.out.println("SOURCE PROC: "+sourceProcess.getId());
      // System.out.println("TARGET PROC: "+targetProcess.getId());

      if (!(context.getReconnectType().equals(ReconnectionContext.RECONNECT_TARGET))
          && targetContainerParent != sourceContainerParent
          && targetContainer != sourceContainer
          && targetContainer != sourceContainerParent
          && targetContainerParent != sourceContainer) {
        if (source instanceof SendTask
            || source instanceof EndEvent
                && ((EndEvent) source).getEventDefinitions().get(0)
                    instanceof MessageEventDefinition
            || source instanceof IntermediateThrowEvent
                && ((IntermediateThrowEvent) source).getEventDefinitions().get(0)
                    instanceof MessageEventDefinition) {
          return true;
        }
      }

      // **SubProcess bug fixes -SZ
      if (targetProcess == null && target.getId() != null) {
        if (sourceProcess != null
            && targetContainerParent != sourceContainerParent
            && sourceContainer != targetContainerParent
            && targetContainer instanceof SubProcess) {
          if (target instanceof StartEvent
              || target instanceof ReceiveTask
              || target instanceof CatchEvent) {
            return true;
          }
        }
      }
      // **

      if (!(sourceContainer instanceof SubProcess)) {
        if (sourceProcess == null || targetProcess == null || sourceProcess == targetProcess) {
          return false;
        }
      } else if (sourceContainerParent == targetContainer) {
        return false;
      } else if (context.getReconnectType().equals(ReconnectionContext.RECONNECT_TARGET)) {
        if (sourceContainer instanceof SubProcess && sourceContainer != targetContainer) {
        } else {
          sourceContainerParent =
              getBusinessObjectForPictogramElement(
                  (PictogramElement) context.getNewAnchor().getParent().eContainer().eContainer());
          sourceContainerParent2 =
              getBusinessObjectForPictogramElement(
                  (PictogramElement)
                      context.getNewAnchor().getParent().eContainer().eContainer().eContainer());
          if (sourceContainerParent2 == targetContainerParent
              || targetContainer == sourceContainer) {
            return false;
          }
        }
      } else if (sourceContainer instanceof SubProcess) {
        return false;
      }

      if (source instanceof Task
          || source instanceof SubProcess
          || (source instanceof IntermediateThrowEvent
              && ((IntermediateThrowEvent) source).getEventDefinitions().get(0)
                  instanceof MessageEventDefinition)
          || (source instanceof EndEvent
              && ((EndEvent) source).getEventDefinitions().get(0)
                  instanceof MessageEventDefinition)) {
        if (target instanceof Task
            || (target instanceof IntermediateCatchEvent
                && ((IntermediateCatchEvent) target).getEventDefinitions().get(0)
                    instanceof MessageEventDefinition)
            || (source instanceof StartEvent
                && ((StartEvent) source).getEventDefinitions().get(0)
                    instanceof MessageEventDefinition)
            || target instanceof SubProcess
            || target instanceof StartEvent
            || (target instanceof BoundaryEvent
                && ((BoundaryEvent) target).getEventDefinitions().get(0)
                    instanceof MessageEventDefinition)) {
          return true;
        } else {
          return false;
        }
      }
      return false;
    } else {
      return false;
    }
  }