private void removeConnector(Connector connector) {
    connectorList.remove(connector);
    Node connectorNode = connectors.remove(connector.getId());

    if (connectorNode != null && connectorNode.getParent() != null) {

      // TODO: remove connectors&connections?

      if (connector.isInput()) {
        inputList.remove(connectorNode);
      } else if (connector.isOutput()) {
        outputList.remove(connectorNode);
      }
      NodeUtil.removeFromParent(connectorNode);
    }
  }
  private void addConnector(final Connector connector) {
    connectorList.add(connector);
    ConnectorCircle circle = new ConnectorCircle(controller, getSkinFactory(), connector, 20);

    //        Color fillColor = skinFactory.getConnectionFillColor(connector.getType());
    //        Color strokeColor = skinFactory.getConnectionStrokeColor(connector.getType());
    //
    //        if (fillColor == null) {
    //            fillColor = new Color(0.1, 0.1, 0.1, 0.5);
    //        }
    //
    //        if (strokeColor == null) {
    //            strokeColor = new Color(120 / 255.0, 140 / 255.0, 1, 0.42);
    //        }
    //
    //
    //        circle.setFill(fillColor);
    //        circle.setStroke(strokeColor);
    //
    //        circle.setStrokeWidth(3);

    final Circle connectorNode = circle;

    connectors.put(connector.getId(), connectorNode);

    if (connector.isInput()) {
      inputList.add(connectorNode);
    }
    if (connector.isOutput()) {
      outputList.add(connectorNode);
    }

    DoubleBinding startXBinding =
        new DoubleBinding() {
          {
            super.bind(node.layoutXProperty(), node.widthProperty());
          }

          @Override
          protected double computeValue() {
            double posX = node.getLayoutX();

            if (connector.isOutput()) {
              posX += node.getWidth();
            }

            return posX;
          }
        };

    DoubleBinding startYBinding =
        new DoubleBinding() {
          {
            super.bind(node.layoutYProperty(), node.heightProperty());
          }

          @Override
          protected double computeValue() {

            double connectorHeight = connectorNode.getRadius() * 2;
            double gap = 5;

            double numConnectors = inputList.size();

            int connectorIndex = inputList.indexOf(connectorNode);

            if (connector.isOutput()) {
              numConnectors = outputList.size();
              connectorIndex = outputList.indexOf(connectorNode);
            }

            double totalHeight = numConnectors * connectorHeight + (numConnectors - 1) * gap;

            double midPointOfNode = node.getLayoutY() + node.getHeight() / 2;

            double startY = midPointOfNode - totalHeight / 2;

            double y =
                startY + (connectorHeight + gap) * connectorIndex + (connectorHeight + gap) / 2;

            return y;
          }
        };

    connectorNode.layoutXProperty().bind(startXBinding);
    connectorNode.layoutYProperty().bind(startYBinding);

    node.boundsInLocalProperty()
        .addListener(
            new ChangeListener<Bounds>() {
              @Override
              public void changed(
                  ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
                computeInputConnectorSize();
                computeOutputConnectorSize();
                adjustConnectorSize();
              }
            });

    NodeUtil.addToParent(getParent(), connectorNode);

    connectorNode
        .onMouseEnteredProperty()
        .set(
            new EventHandler<MouseEvent>() {
              @Override
              public void handle(MouseEvent t) {
                connectorNode.toFront();
              }
            });

    connectorNode
        .onMousePressedProperty()
        .set(
            new EventHandler<MouseEvent>() {
              @Override
              public void handle(MouseEvent t) {

                // we are already connected and manipulate the existing connection
                // rather than creating a new one
                if (controller
                    .getConnections(connector.getType())
                    .isInputConnected(connector.getId())) {
                  return;
                }

                newConnectionSkin =
                    new FXNewConnectionSkin(
                        getSkinFactory(),
                        getParent(),
                        connector,
                        getController(),
                        connector.getType());

                newConnectionSkin.add();

                t.consume();
                MouseEvent.fireEvent(newConnectionSkin.getReceiverConnector(), t);
              }
            });

    connectorNode
        .onMouseDraggedProperty()
        .set(
            new EventHandler<MouseEvent>() {
              @Override
              public void handle(MouseEvent t) {

                // we are already connected and manipulate the existing connection
                // rather than creating a new one
                if (controller
                    .getConnections(connector.getType())
                    .isInputConnected(connector.getId())) {
                  return;
                }

                t.consume();
                MouseEvent.fireEvent(newConnectionSkin.getReceiverConnector(), t);
              }
            });

    connectorNode
        .onMouseReleasedProperty()
        .set(
            new EventHandler<MouseEvent>() {
              @Override
              public void handle(MouseEvent t) {

                // we are already connected and manipulate the existing connection
                // rather than creating a new one
                if (controller
                    .getConnections(connector.getType())
                    .isInputConnected(connector.getId())) {
                  return;
                }

                t.consume();
                try {
                  MouseEvent.fireEvent(newConnectionSkin.getReceiverConnector(), t);
                } catch (Exception ex) {
                  // TODO exception is not critical here (node already removed)
                }
              }
            });
  }