package demo.view.viewmode;

import demo.view.DemoBase;
import y.base.Node;
import y.view.EditMode;
import y.view.Graph2D;
import y.view.ViewMode;

import java.awt.EventQueue;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;

/**
 * Demonstrates how to customize {@link EditMode} to allow moving
 * of nodes that are not selected and to restrict edge creation to
 * <code>CTRL</code>-dragging on nodes that are not selected.
 * @author Thomas Behr
 */
public class CustomEdgeCreationDemo extends DemoBase {
  protected EditMode createEditMode() {
    return new CustomEditMode();
  }

  public static void main( String[] args ) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        initLnF();
        (new CustomEdgeCreationDemo()).start();
      }
    });
  }

  /**
   * Allows moving of nodes that are not selected and restricts edge creation
   * to <code>CTRL</code>-dragging on nodes that are not selected.
   */
  private static final class CustomEditMode extends EditMode {
    /**
     * Overwritten to allow moving of nodes that are not selected. 
     * @param graph the graph the node resides in.
     * @param node the node which is being dragged.
     * @param wasSelected whether the element is already selected.
     * @param x the x coordinate of the current mouse drag event point.
     * @param y the y coordinate of the current mouse drag event point.
     * @param firstDrag <code>true</code> if the previous mouse event captured by
     * this <code>ViewMode</code> was <em>not</em> a drag event;
     */
    protected void nodeDragged(
            final Graph2D graph,
            final Node node,
            final boolean wasSelected,
            final double x,
            final double y,
            final boolean firstDrag
    ) {
      if (wasSelected) {
        // the default behavior:
        // move the selection
        if (firstDrag) {
          final ViewMode moveSelectionMode = getMoveSelectionMode();
          if (!isSelectionEmpty(graph) &&
              doAllowMoveSelection() &&
              moveSelectionMode != null) {
            setChild(moveSelectionMode, lastPressEvent, lastDragEvent);
          }
        }
      } else {
        // special behavior:
        // if the node is not selected, check if an edge should be created ...
        final ViewMode createEdgeMode = getCreateEdgeMode();
        if (isCreateEdgeGesture(lastPressEvent, lastDragEvent) &&
            doAllowEdgeCreation() &&
            createEdgeMode != null) {
          setChild(createEdgeMode, lastPressEvent, lastDragEvent);
        } else if (firstDrag) {
          // ... else move the selected node
          final ViewMode moveSelectionMode = getMoveSelectionMode();
          if (moveSelectionMode != null) {
            // to do that, simply make the node the only selected element in
            // the graph
            unselectAll(graph);
            setSelected(graph, node, true);
            setChild(moveSelectionMode, lastPressEvent, lastDragEvent);
          }
        }
      }
    }

    /**
     * Overwritten to restrict edge creation to <code>CTRL</code>-dragging.
     * @param lastPress the last press event
     * @param lastDrag the last drag event
     * @return <code>true</code> if the specified events qualify as default
     * edge creation gesture and the <code>CTRL</code> key is pressed, too;
     * <code>false</code> otherwise.
     */
    protected boolean isCreateEdgeGesture(
            final MouseEvent lastPress,
            final MouseEvent lastDrag
    ) {
      final boolean accept = super.isCreateEdgeGesture(lastPress, lastDrag);
      return accept && isCtrlDown(lastPress);
    }

    private static boolean isCtrlDown( final MouseEvent e ) {
      final int mask = InputEvent.CTRL_DOWN_MASK;
      return (e.getModifiersEx() & mask) == mask;
    }
  }
}
