/**
   * return commands to transform a binary association to n-ary association or allow adding
   * branches.
   *
   * @param createConnectionViewAndElementRequest the create connection view and element request
   * @param command that will contains subcommands
   * @return the command
   */
  public Command getCommand(
      CreateConnectionViewAndElementRequest createConnectionViewAndElementRequest,
      Command command) {
    // 0. get source and target type
    command = new CompoundCommand();
    EditPart sourceEditPart = createConnectionViewAndElementRequest.getSourceEditPart();
    EditPart targetEditPart = createConnectionViewAndElementRequest.getTargetEditPart();

    // if the the source or the target is a node association the goal is
    // to create only one branch
    if ((((View) sourceEditPart.getModel()).getType() == "" + AssociationNodeEditPart.VISUAL_ID)) {
      return getBranchAssociationCommand(createConnectionViewAndElementRequest, command);
    }

    if ((((View) targetEditPart.getModel()).getType() == "" + AssociationNodeEditPart.VISUAL_ID)) {
      return UnexecutableCommand.INSTANCE;
    }
    // the source or the target has to be different of a dependency branch
    if (sourceEditPart instanceof AssociationBranchEditPart) {
      GraphicalEditPart associationNodeEditPart =
          lookForAssociationNodeEditPart((AssociationBranchEditPart) sourceEditPart);

      if (associationNodeEditPart != null) {
        createConnectionViewAndElementRequest.setSourceEditPart(associationNodeEditPart);
        return getBranchAssociationCommand(createConnectionViewAndElementRequest, command);

      } else {
        return UnexecutableCommand.INSTANCE;
      }
    }
    // the source or the target has to be different of a dependency branch
    if (targetEditPart instanceof AssociationBranchEditPart) {
      return UnexecutableCommand.INSTANCE;
    }

    // if not this a transformation of simple dependency to multiDependency
    return getAssociationToMultiAssociationCommand(createConnectionViewAndElementRequest, command);
  }
  /**
   * code to create new branch.
   *
   * @param createConnectionViewAndElementRequest the create connection view and element request
   * @param command that will contain sub commands
   * @return the command in charge of the branch creation
   */
  private Command getBranchAssociationCommand(
      CreateConnectionViewAndElementRequest createConnectionViewAndElementRequest,
      Command command) {
    command = new CompoundCommand();
    // init
    EditPart sourceEditPart = createConnectionViewAndElementRequest.getSourceEditPart();
    EditPart targetEditPart = createConnectionViewAndElementRequest.getTargetEditPart();

    if ((targetEditPart.getModel() instanceof Edge)) {
      return null;
    }
    if (targetEditPart != null) {
      // the source or the target must be a association
      // look for the edit part that represent the editpart
      EObject association = null;
      NamedElement newSemanticElement = null;
      if (((View) sourceEditPart.getModel()).getElement() != null
          && ((View) sourceEditPart.getModel()).getElement() instanceof Association) {
        association = ((View) sourceEditPart.getModel()).getElement();
        newSemanticElement = (NamedElement) ((View) targetEditPart.getModel()).getElement();
      }

      if (((View) targetEditPart.getModel()).getElement() != null
          && ((View) targetEditPart.getModel()).getElement() instanceof Association) {
        association = ((View) targetEditPart.getModel()).getElement();
        newSemanticElement = (NamedElement) ((View) sourceEditPart.getModel()).getElement();
      }
      // System.err.println("step init, can execute?" + command.canExecute());
      // 0. add semantic
      CreateElementRequest request =
          new CreateElementRequest(
              getEditingDomain(),
              association,
              UMLElementTypes.Property_3005,
              UMLPackage.eINSTANCE.getAssociation_OwnedEnd());
      request.setParameter("type", newSemanticElement);
      EditElementCommand propertyCreateCommand = new PropertyCommandForAssociation(request);
      ((CompoundCommand) command).add(new ICommandProxy(propertyCreateCommand));

      // System.err.println("0. add semantic, can execute?" + command.canExecute());
      // 1. add the branch graphically
      ConnectionViewDescriptor viewDescriptor =
          new ConnectionViewDescriptor(
              UMLElementTypes.Association_4019,
              ((IHintedType) UMLElementTypes.Association_4019).getSemanticHint(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint());
      GraphicalAssociationBranchViewCommand aBranchCommand =
          new GraphicalAssociationBranchViewCommand(
              getEditingDomain(),
              new SemanticAdapter(null, sourceEditPart.getModel()),
              new SemanticAdapter(null, targetEditPart.getModel()),
              sourceEditPart.getViewer(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
              viewDescriptor,
              request);
      // CustomDeferredCreateConnectionViewCommand aBranchCommand = new
      // CustomDeferredCreateConnectionViewCommand(getEditingDomain(),
      // ((IHintedType)UMLElementTypes.Association_4019).getSemanticHint(), new
      // SemanticAdapter(null, sourceEditPart.getModel()), new SemanticAdapter(null,
      // targetEditPart.getModel()), sourceEditPart.getViewer(),
      // ((IGraphicalEditPart)sourceEditPart).getDiagramPreferencesHint(), viewDescriptor, null);

      aBranchCommand.setElement(association);
      ((CompoundCommand) command).add(new ICommandProxy(aBranchCommand));
      // System.err.println("1. add the branch graphically, can execute?" + command.canExecute());
      return command;
    }
    return UnexecutableCommand.INSTANCE;
  }
  /**
   * transform binary association to n-ary association.
   *
   * @param createConnectionViewAndElementRequest the create connection view and element request
   * @param command the command
   * @return the command in charge of this job
   */
  private Command getAssociationToMultiAssociationCommand(
      CreateConnectionViewAndElementRequest createConnectionViewAndElementRequest,
      Command command) {
    // 0. creation of variables
    command = new CompoundCommand();
    Point sourceLocation = null;
    Point targetLocation = null;
    Point nodeLocation = null;
    NamedElement newSemanticElement = null; // element that will be added as
    // client ou supplier of the
    // association
    EStructuralFeature feature = null; // role client or supplier
    EditPart sourceEditPart = createConnectionViewAndElementRequest.getSourceEditPart();
    EditPart targetEditPart = createConnectionViewAndElementRequest.getTargetEditPart();
    View associationView = null;
    Association association = null;
    View parentView = null;

    Property sourceEnd = null;
    Property targetEnd = null;

    // ---------------------------------------------------------
    // help to debug
    //		System.err.println("\n+ 0. creation of variables");
    //		System.err.println("+-> editting domain"+ getEditingDomain());
    //		System.err.println("+-> sourceEditpart:" + sourceEditPart);
    //		System.err.println("+-> targetEditPart:" + targetEditPart);
    // ---------------------------------------------------------

    // 1. initialization
    ICommandProxy startcommand =
        ((ICommandProxy) createConnectionViewAndElementRequest.getStartCommand());
    if (startcommand == null) {
      return null;
    }
    Iterator<?> ite = ((CompositeCommand) startcommand.getICommand()).iterator();

    while (ite.hasNext()) {
      ICommand currentCommand = (ICommand) ite.next();
      if (currentCommand instanceof SetConnectionBendpointsCommand) {
        sourceLocation = ((SetConnectionBendpointsCommand) currentCommand).getSourceRefPoint();
        targetLocation = ((SetConnectionBendpointsCommand) currentCommand).getTargetRefPoint();
      }
    }

    if (targetEditPart != null) {
      // the source or the target must be a association
      // look for the edit part that represent the editpart
      if (((View) sourceEditPart.getModel()).getElement() != null
          && ((View) sourceEditPart.getModel()).getElement() instanceof Association) {
        associationView = ((View) sourceEditPart.getModel());
        association = (Association) ((View) sourceEditPart.getModel()).getElement();
        nodeLocation = sourceLocation;
        newSemanticElement = (NamedElement) ((View) targetEditPart.getModel()).getElement();
        feature = UMLPackage.eINSTANCE.getTypedElement_Type();
        sourceEnd =
            AssociationEndSourceLabelHelper.getInstance()
                .getUMLElement(
                    (org.eclipse.gef.GraphicalEditPart) sourceEditPart.getChildren().get(0));
        targetEnd =
            AssociationEndTargetLabelHelper.getInstance()
                .getUMLElement(
                    (org.eclipse.gef.GraphicalEditPart) sourceEditPart.getChildren().get(1));
      }

      if (((View) targetEditPart.getModel()).getElement() != null
          && ((View) targetEditPart.getModel()).getElement() instanceof Association) {
        associationView = ((View) targetEditPart.getModel());
        association = (Association) ((View) targetEditPart.getModel()).getElement();
        nodeLocation = targetLocation;
        newSemanticElement = (NamedElement) ((View) sourceEditPart.getModel()).getElement();
        feature = UMLPackage.eINSTANCE.getTypedElement_Type();
        sourceEnd =
            AssociationEndSourceLabelHelper.getInstance()
                .getUMLElement(
                    (org.eclipse.gef.GraphicalEditPart) targetEditPart.getChildren().get(0));
        targetEnd =
            AssociationEndTargetLabelHelper.getInstance()
                .getUMLElement(
                    (org.eclipse.gef.GraphicalEditPart) targetEditPart.getChildren().get(1));
      }

      if (associationView == null || (targetEditPart.getModel() instanceof Edge)) {
        return null;
      }
      parentView = (View) associationView.eContainer();
      // ---------------------------------------------------------
      // help to debug
      //			System.err.println("+ 1. initialization");
      //			System.err.println("+-> sourceLocation:" + sourceLocation);
      //			System.err.println("+-> targetLocation:" + targetLocation);
      //			System.err.println("+-> AssociationView:" + associationView);
      //			System.err.println("+-> association:" + association);
      //			System.err.println("+-> nodeLocation:" + nodeLocation);
      //			System.err.println("+-> newSemanticElement:" + newSemanticElement);
      //			System.err.println("+-> feature:" + feature);
      //			System.err.println("+-> parentView:" + parentView);
      // ---------------------------------------------------------
      // 8 Ensure that all member ends belong to the association
      ArrayList<Property> ownedProperty = new ArrayList<Property>();
      ownedProperty.addAll(association.getMemberEnds());
      IElementEditService provider = ElementEditServiceUtils.getCommandProvider(association);
      if (provider != null) {
        SetRequest setRequest =
            new SetRequest(
                association, UMLPackage.eINSTANCE.getAssociation_OwnedEnd(), ownedProperty);
        ICommand iCommand = provider.getEditCommand(setRequest);
        ((CompoundCommand) command).add(new ICommandProxy(iCommand));
      }

      // 2. Remove the view of the association
      DeleteCommand deleteCommand =
          new DeleteLinkDuringCreationCommand(
              getEditingDomain(), (Edge) associationView, sourceEditPart.getViewer());
      deleteCommand.setReuseParentTransaction(true);
      Command removecommand = new ICommandProxy(deleteCommand);
      // to execute
      ((CompoundCommand) command).add(removecommand);

      // ((CompoundCommand)command).add(removecommand);

      // ---------------------------------------------------------
      // help to debug
      //			System.err.println("+ 2. Remove the view of the association");
      //			System.err.println("+-> command:" + command.canExecute());
      // ---------------------------------------------------------

      // 3. set a new end association in the UML model
      // 3.1 creation of the property
      CreateElementRequest request =
          new CreateElementRequest(
              getEditingDomain(),
              association,
              UMLElementTypes.Property_3005,
              UMLPackage.eINSTANCE.getAssociation_OwnedEnd());
      request.setParameter("type", newSemanticElement);
      EditElementCommand propertyCreateCommand = new PropertyCommandForAssociation(request);
      propertyCreateCommand.setReuseParentTransaction(true);
      ((CompoundCommand) command).add(new ICommandProxy(propertyCreateCommand));

      // 3. Node creation at this position
      View associationViewSource = ((Edge) associationView).getSource();
      View associationViewTarget = ((Edge) associationView).getTarget();
      AssociationDiamonViewCreateCommand nodeCreation =
          new AssociationDiamonViewCreateCommand(
              getEditingDomain(),
              parentView,
              sourceEditPart.getViewer(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
              nodeLocation,
              new SemanticAdapter(association, null));
      nodeCreation.setReuseParentTransaction(true);
      ((CompoundCommand) command).add(new ICommandProxy(nodeCreation));

      // 4. reconstruction of the old link by taking in account the old
      // connection
      ConnectionViewDescriptor viewDescriptor =
          new ConnectionViewDescriptor(
              UMLElementTypes.Association_4019,
              ((IHintedType) UMLElementTypes.Association_4019).getSemanticHint(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint());

      // 5. reconstruction of the first branch between old source to node
      ICommand firstBranchCommand =
          new GraphicalAssociationBranchViewCommand(
              getEditingDomain(),
              (IAdaptable) nodeCreation.getCommandResult().getReturnValue(),
              new SemanticAdapter(null, associationViewSource),
              sourceEditPart.getViewer(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
              viewDescriptor,
              sourceEnd);

      // ICommand firstBranchCommand = new
      // CustomDeferredCreateConnectionViewCommand(getEditingDomain(),
      // ((IHintedType)UMLElementTypes.Association_4019).getSemanticHint(),
      // (IAdaptable)nodeCreation.getCommandResult().getReturnValue(), new SemanticAdapter(null,
      // associationViewSource), sourceEditPart.getViewer(),
      // ((IGraphicalEditPart)sourceEditPart).getDiagramPreferencesHint(), viewDescriptor, null);
      ((GraphicalAssociationBranchViewCommand) firstBranchCommand).setElement(association);
      ((CompoundCommand) command).add(new ICommandProxy(firstBranchCommand));
      // 6. reconstruction of the second branch between node to old target
      ICommand secondBranchCommand =
          new GraphicalAssociationBranchViewCommand(
              getEditingDomain(),
              (IAdaptable) nodeCreation.getCommandResult().getReturnValue(),
              new SemanticAdapter(null, associationViewTarget),
              sourceEditPart.getViewer(),
              ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
              viewDescriptor,
              targetEnd);

      // ICommand secondBranchCommand = new
      // CustomDeferredCreateConnectionViewCommand(getEditingDomain(),
      // ((IHintedType)UMLElementTypes.Association_4019).getSemanticHint(),
      // (IAdaptable)nodeCreation.getCommandResult().getReturnValue(), new SemanticAdapter(null,
      // associationViewTarget), sourceEditPart.getViewer(),
      // ((IGraphicalEditPart)sourceEditPart).getDiagramPreferencesHint(), viewDescriptor, null);
      ((GraphicalAssociationBranchViewCommand) secondBranchCommand).setElement(association);
      ((CompoundCommand) command).add(new ICommandProxy(secondBranchCommand));

      // 7. Create of the third branch between node and target our source.
      ICommand thirdBranchCommand = null;

      if (associationView.equals((sourceEditPart.getModel()))) {
        // third branch node and target
        thirdBranchCommand =
            new GraphicalAssociationBranchViewCommand(
                getEditingDomain(),
                (IAdaptable) nodeCreation.getCommandResult().getReturnValue(),
                new SemanticAdapter(null, targetEditPart.getModel()),
                sourceEditPart.getViewer(),
                ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
                viewDescriptor,
                request);

        // thirdBranchCommand = new CustomDeferredCreateConnectionViewCommand(getEditingDomain(),
        // ((IHintedType)UMLElementTypes.Association_4019).getSemanticHint(),
        // (IAdaptable)nodeCreation.getCommandResult().getReturnValue(), new SemanticAdapter(null,
        // targetEditPart.getModel()), sourceEditPart.getViewer(),
        // ((IGraphicalEditPart)sourceEditPart).getDiagramPreferencesHint(), viewDescriptor, null);
      } else {
        // third branch source and node
        thirdBranchCommand =
            new GraphicalAssociationBranchViewCommand(
                getEditingDomain(),
                new SemanticAdapter(null, sourceEditPart.getModel()),
                (IAdaptable) nodeCreation.getCommandResult().getReturnValue(),
                sourceEditPart.getViewer(),
                ((IGraphicalEditPart) sourceEditPart).getDiagramPreferencesHint(),
                viewDescriptor,
                request);

        // thirdBranchCommand = new CustomDeferredCreateConnectionViewCommand(getEditingDomain(),
        // ((IHintedType)UMLElementTypes.Association_4019).getSemanticHint(), new
        // SemanticAdapter(null, sourceEditPart.getModel()),
        // (IAdaptable)nodeCreation.getCommandResult().getReturnValue(), sourceEditPart.getViewer(),
        // ((IGraphicalEditPart)sourceEditPart).getDiagramPreferencesHint(), viewDescriptor, null);
      }
      ((GraphicalAssociationBranchViewCommand) thirdBranchCommand).setElement(association);
      ((CompoundCommand) command).add(new ICommandProxy(thirdBranchCommand));
    }
    return command;
  }