/**
   * @param wireNew If true, OutputPorts of operators will be added to readyOutputs once they are
   *     wired.
   */
  private void autoWire(
      CompatibilityLevel level,
      List<Operator> operators,
      LinkedList<OutputPort> readyOutputs,
      boolean recursive,
      boolean wireNew)
      throws PortException {
    transformMDNeighbourhood();

    for (Operator op : operators) {
      try {
        readyOutputs = op.preAutoWire(readyOutputs);
      } catch (OperatorException e) {
        getEnclosingOperator().getLogger().log(Level.WARNING, "During auto-wiring: " + e, e);
      }
      autoWire(level, op.getInputPorts(), readyOutputs);
      transformMDNeighbourhood();
      if (recursive) {
        if (op instanceof OperatorChain) {
          for (ExecutionUnit subprocess : ((OperatorChain) op).getSubprocesses()) {
            // we have already removed all connections, so keepConnections=true in recursive call
            subprocess.autoWire(level, true, recursive);
          }
        }
      }
      if (wireNew) {
        addReadyOutputs(readyOutputs, op.getOutputPorts());
      }
    }
    autoWire(level, getInnerSinks(), readyOutputs);
    transformMDNeighbourhood();
  }
  /**
   * Moves the operators from this process to another process, keeping all connections intact. TODO:
   * Test more rigorously. Do we register/unregister everything correctly?
   *
   * @return the number of ports the connections of which could not be restored
   */
  public int stealOperatorsFrom(ExecutionUnit otherUnit) {
    int failedReconnects = 0;

    // remember source and sink connections so we can reconnect them later.
    Map<String, InputPort> sourceMap = new HashMap<String, InputPort>();
    Map<String, OutputPort> sinkMap = new HashMap<String, OutputPort>();
    for (OutputPort source : otherUnit.getInnerSources().getAllPorts()) {
      if (source.isConnected()) {
        sourceMap.put(source.getName(), source.getDestination());
      }
    }
    otherUnit.getInnerSources().disconnectAll();
    for (InputPort sink : otherUnit.getInnerSinks().getAllPorts()) {
      if (sink.isConnected()) {
        sinkMap.put(sink.getName(), sink.getSource());
      }
    }
    otherUnit.getInnerSinks().disconnectAll();

    // Move operators
    Iterator<Operator> i = otherUnit.operators.iterator();
    while (i.hasNext()) {
      Operator operator = i.next();
      i.remove();
      otherUnit.unregister(operator);
      Process otherProcess = operator.getProcess();
      if (otherProcess != null) {
        operator.unregisterOperator(otherProcess);
      }
      this.operators.add(operator);
      operator.setEnclosingProcess(null);
      // operator.unregisterOperator(operator.getProcess());
      registerOperator(operator, true);
      // operator.registerOperator(this.getEnclosingOperator().getProcess());
    }

    // Rewire sources and sinks
    for (Map.Entry<String, InputPort> entry : sourceMap.entrySet()) {
      OutputPort mySource = getInnerSources().getPortByName(entry.getKey());
      if (mySource != null) {
        mySource.connectTo(entry.getValue());
      } else {
        failedReconnects++;
      }
    }
    getInnerSources().unlockPortExtenders();

    for (Map.Entry<String, OutputPort> entry : sinkMap.entrySet()) {
      InputPort mySink = getInnerSinks().getPortByName(entry.getKey());
      if (mySink != null) {
        entry.getValue().connectTo(mySink);
      } else {
        failedReconnects++;
      }
    }
    getInnerSinks().unlockPortExtenders();

    fireUpdate(this);
    return failedReconnects;
  }
  /**
   * Clones operators contained in <code>original</code>, adds them to this execution unit and wires
   * them as they were originally.
   *
   * @param forParallelExecution Indicates whether this clone is supposed to be executed in
   *     parallel. If yes, the clone will not be registered with the parent process and will share
   *     its {@link Operator#applyCount} with the original.
   */
  public void cloneExecutionUnitFrom(ExecutionUnit original, boolean forParallelExecution) {
    // Clone operators
    Map<String, Operator> clonedOperatorsByName = new HashMap<String, Operator>();
    for (Operator originalChild : original.operators) {
      Operator clonedOperator =
          originalChild.cloneOperator(originalChild.getName(), forParallelExecution);
      addOperator(clonedOperator, !forParallelExecution);
      clonedOperatorsByName.put(originalChild.getName(), clonedOperator);
    }

    // Restore connections
    cloneConnections(original.getInnerSources(), original, clonedOperatorsByName);
    for (Operator op : original.operators) {
      cloneConnections(op.getOutputPorts(), original, clonedOperatorsByName);
    }

    // Unlock
    original.getInnerSources().unlockPortExtenders();
    original.getInnerSinks().unlockPortExtenders();
    for (Operator op : this.operators) {
      op.getInputPorts().unlockPortExtenders();
      op.getOutputPorts().unlockPortExtenders();
    }

    // Other:
    this.expanded = original.expanded;
  }
  @Override
  protected String conditionedApply(
      Operator operator, String operatorTypeName, XMLImporter importer) {
    if (operator.getParameters().isSpecified(parameterName)) {
      try {
        String attributeName = operator.getParameterAsString(parameterName);

        ChangeAttributeRole setRoleOp = OperatorService.createOperator(ChangeAttributeRole.class);

        // inserting operator into process
        ExecutionUnit process = operator.getExecutionUnit();
        int operatorIndex = process.getOperators().indexOf(operator);
        process.addOperator(setRoleOp, operatorIndex + 1);

        // setting parameter
        setRoleOp.setParameter(ChangeAttributeRole.PARAMETER_NAME, attributeName);
        setRoleOp.setParameter(ChangeAttributeRole.PARAMETER_TARGET_ROLE, targetRole);
        return "Inserted operator for explicitly setting attribute <code>"
            + attributeName
            + "</code> to role <code>"
            + targetRole
            + "</code>";
      } catch (UndefinedParameterError e) {
        return null;
      } catch (OperatorCreationException e) {
        return null;
      }
    }
    return null;
  }
 private void unwire(Operator op, boolean recursive) throws PortException {
   op.getOutputPorts().disconnectAll();
   if (recursive) {
     if (op instanceof OperatorChain) {
       for (ExecutionUnit subprocess : ((OperatorChain) op).getSubprocesses()) {
         subprocess.unwire(recursive);
       }
     }
   }
 }
 @Override
 public void execute(ExecutionUnit unit) throws OperatorException {
   Logger logger = unit.getEnclosingOperator().getLogger();
   if (logger.isLoggable(Level.FINE)) {
     logger.fine(
         "Executing subprocess "
             + unit.getEnclosingOperator().getName()
             + "."
             + unit.getName()
             + ". Execution order is: "
             + unit.getOperators());
   }
   Enumeration<Operator> opEnum = unit.getOperatorEnumeration();
   while (opEnum.hasMoreElements()) {
     // for (Operator operator : unit.getOperators()) {
     Operator operator = opEnum.nextElement();
     operator.execute();
     operator.freeMemory();
   }
 }
  /**
   * The given operators will be inserted at the last position of the currently selected operator
   * chain.
   */
  public void insert(List<Operator> newOperators) {
    Object selectedNode = getSelectedOperator();
    if (selectedNode == null) {
      SwingTools.showVerySimpleErrorMessage("cannot_insert_operator");
      return;
    } else if (mainFrame.getProcessPanel().getProcessRenderer().getModel().getDisplayedChain()
        == selectedNode) {
      for (Operator newOperator : newOperators) {
        int index =
            mainFrame
                .getProcessPanel()
                .getProcessRenderer()
                .getProcessIndexUnder(
                    mainFrame
                        .getProcessPanel()
                        .getProcessRenderer()
                        .getModel()
                        .getCurrentMousePosition());
        if (index == -1) {
          index = 0;
        }
        ((OperatorChain) selectedNode).getSubprocess(index).addOperator(newOperator);
      }
    } else {
      int i = 0;
      Operator selectedOperator = (Operator) selectedNode;
      ExecutionUnit process = selectedOperator.getExecutionUnit();
      int parentIndex = process.getOperators().indexOf(selectedOperator) + 1;
      for (Operator newOperator : newOperators) {
        process.addOperator(newOperator, parentIndex + i);
        i++;
      }
    }

    AutoWireThread.autoWireInBackground(newOperators, true);
    mainFrame.selectOperators(newOperators);
  }
        /** Draws the operator annoations. */
        private void draw(
            final ExecutionUnit process,
            final Graphics2D g2,
            final ProcessRendererModel rendererModel,
            final boolean printing) {
          if (!visualizer.isActive()) {
            return;
          }

          // operator attached annotations
          List<Operator> selectedOperators = rendererModel.getSelectedOperators();
          for (Operator operator : process.getOperators()) {
            if (selectedOperators.contains(operator)) {
              continue;
            }
            drawOpAnno(operator, g2, rendererModel, printing);
          }
          // selected operators annotations need to be drawn over non selected ones
          for (Operator selOp : selectedOperators) {
            if (process.equals(selOp.getExecutionUnit())) {
              drawOpAnno(selOp, g2, rendererModel, printing);
            }
          }
        }
  @Override
  public void apply() {
    try {
      Operator oldOperator = inputPort.getPorts().getOwner().getOperator();
      Operator newOperator =
          NewOperatorDialog.selectMatchingOperator(
              RapidMinerGUI.getMainFrame().getActions(), null, neededClass, null, null);

      if (newOperator != null) {
        ExecutionUnit unit = inputPort.getPorts().getOwner().getConnectionContext();
        int index = unit.getIndexOfOperator(oldOperator);
        if (index == -1) {
          unit.addOperator(newOperator);
        } else {
          unit.addOperator(newOperator, unit.getIndexOfOperator(oldOperator));
        }
        if (RapidMinerGUI.getMainFrame().VALIDATE_AUTOMATICALLY_ACTION.isSelected()) {
          unit.autoWireSingle(newOperator, CompatibilityLevel.VERSION_5, true, true);
        }
      }
    } catch (OperatorCreationException e) {
    }
  }
  private void cloneConnections(
      OutputPorts originalPorts,
      ExecutionUnit originalExecutionUnit,
      Map<String, Operator> clonedOperatorsByName) {
    for (OutputPort originalSource : originalPorts.getAllPorts()) {
      if (originalSource.isConnected()) {

        OutputPort mySource;
        if (originalPorts.getOwner().getOperator()
            == originalExecutionUnit.getEnclosingOperator()) {
          // this is an inner source
          mySource = getInnerSources().getPortByName(originalSource.getName());
          if (mySource == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such inner source).");
          }
        } else {
          // this is an output port
          Operator myOperator =
              clonedOperatorsByName.get(
                  originalSource.getPorts().getOwner().getOperator().getName());
          if (myOperator == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such operator).");
          }
          mySource = myOperator.getOutputPorts().getPortByName(originalSource.getName());
          if (mySource == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding source for "
                    + originalSource
                    + " not found (no such output port).");
          }
        }

        InputPort originalDestination = originalSource.getDestination();
        InputPort myDestination;
        if (originalDestination.getPorts().getOwner().getOperator()
            == originalExecutionUnit.getEnclosingOperator()) {
          // this is an inner sink
          myDestination = getInnerSinks().getPortByName(originalDestination.getName());
          if (myDestination == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such inner sink).");
          }
        } else {
          // this is an input port
          Operator myOperator =
              clonedOperatorsByName.get(
                  originalDestination.getPorts().getOwner().getOperator().getName());
          if (myOperator == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such operator).");
          }
          myDestination = myOperator.getInputPorts().getPortByName(originalDestination.getName());
          if (myDestination == null) {
            throw new RuntimeException(
                "Error during clone: Corresponding destination for "
                    + originalDestination
                    + " not found (no such input port).");
          }
        }
        mySource.connectTo(myDestination);
      }
    }
  }