// Path: api/src/main/java/de/tesis/dynaware/grapheditor/EditorElement.java
// public enum EditorElement
// {
//     CONNECTOR,
//     NODE,
//     JOINT;
// }
// 
// Path: api/src/main/java/de/tesis/dynaware/grapheditor/impl/GraphEventManagerImpl.java
// public class GraphEventManagerImpl implements GraphEventManager
// {
// 
//     private GraphInputGesture gesture;
//     private Object owner;
// 
//     @Override
//     public boolean activateGesture(final GraphInputGesture pGesture, final Event pEvent, final Object pOwner)
//     {
//         if (!canOverwrite(owner, pOwner))
//         {
//             return false;
//         }
//         if (canActivate(pGesture, pEvent))
//         {
//             gesture = pGesture;
//             owner = pOwner;
//             return true;
//         }
//         // ELSE:
//         return false;
//     }
// 
//     private boolean canActivate(final GraphInputGesture pGesture, final Event pEvent)
//     {
//         final GraphInputGesture current = gesture;
//         if (current == pGesture)
//         {
//             return true;
//         }
//         else if (current == null)
//         {
//             final boolean isTouch = pEvent instanceof TouchEvent || pEvent instanceof MouseEvent me && me.isSynthesized()
//                     || pEvent instanceof ScrollEvent se && se.getTouchCount() > 0;
//             if (!isTouch)
//             {
//                 return switch (pGesture)
//                         {
//                             case PAN -> pEvent instanceof ScrollEvent se && !se.isControlDown()
//                                     || pEvent instanceof MouseEvent me && me.isSecondaryButtonDown();
//                             case ZOOM -> pEvent instanceof ScrollEvent se && se.isControlDown();
//                             case SELECT, CONNECT, MOVE, RESIZE -> pEvent instanceof MouseEvent me &&
//                                     me.isPrimaryButtonDown();
//                         };
//             }
//             else
//             {
//                 return switch (pGesture)
//                         {
//                             case ZOOM -> pEvent instanceof ZoomEvent;
//                             case PAN -> pEvent instanceof TouchEvent && ((TouchEvent) pEvent).getTouchCount() > 1;
//                             case SELECT, CONNECT, MOVE, RESIZE -> true;
//                         };
//             }
//         }
//         return false;
//     }
// 
//     @Override
//     public boolean finishGesture(final GraphInputGesture pExpected, final Object pOwner)
//     {
//         if (gesture == pExpected && (owner == pOwner || !isVisible(owner)))
//         {
//             gesture = null;
//             owner = null;
//             return true;
//         }
//         return false;
//     }
// 
//     private static boolean canOverwrite(final Object pExisting, final Object pCandidate)
//     {
//         if (pExisting == pCandidate)
//         {
//             return true;
//         }
//         if (pCandidate == null)
//         {
//             return false;
//         }
//         return pExisting == null || !isVisible(pExisting);
//     }
// 
//     private static boolean isVisible(final Object pNode)
//     {
//         if (pNode != null)
//         {
//             if (pNode instanceof Node n)
//             {
//                 return n.isVisible() && n.getParent() != null && n.getScene() != null;
//             }
//             return true;
//         }
//         // ELSE: null
//         return false;
//     }
// }


import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import de.tesis.dynaware.grapheditor.EditorElement;
import de.tesis.dynaware.grapheditor.impl.GraphEventManagerImpl;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.event.Event;
/*
 * Copyright (C) 2005 - 2014 by TESIS DYNAware GmbH
 */
package de.tesis.dynaware.grapheditor.utils;




/**
 * General properties for the graph editor.
 *
 * <p>
 * For example, should the editor have 'bounds', or should objects be draggable outside the editor area?
 * </p>
 *
 * <p>
 * If a bound is <b>active</b>, objects that are dragged or resized in the editor should stop when they hit the edge,
 * and the editor region will not try to grow in size. Otherwise it will grow up to its max size.
 * </p>
 *
 * <p>
 * Also stores properties for whether the grid is visible and/or snap-to-grid is on.
 * </p>
 */
public class GraphEditorProperties implements GraphEventManager
{

    /**
     * The default max width of the editor region, set on startup.
     */
    public static final double DEFAULT_MAX_WIDTH = Double.MAX_VALUE;
    /**
     * The default max height of the editor region, set on startup.
     */
    public static final double DEFAULT_MAX_HEIGHT = Double.MAX_VALUE;

    public static final double DEFAULT_BOUND_VALUE = 15;
    public static final double DEFAULT_GRID_SPACING = 12;

    // The distance from the editor edge at which the objects should stop when dragged / resized.
    private double northBoundValue = DEFAULT_BOUND_VALUE;
    private double southBoundValue = DEFAULT_BOUND_VALUE;
    private double eastBoundValue = DEFAULT_BOUND_VALUE;
    private double westBoundValue = DEFAULT_BOUND_VALUE;

    // Off by default.
    private final BooleanProperty gridVisible = new SimpleBooleanProperty(this, "gridVisible"); //$NON-NLS-1$
    private final BooleanProperty snapToGrid = new SimpleBooleanProperty(this, "snapToGrid"); //$NON-NLS-1$
    private final DoubleProperty gridSpacing = new SimpleDoubleProperty(this, "gridSpacing", DEFAULT_GRID_SPACING); //$NON-NLS-1$

    private final Map<EditorElement, BooleanProperty> readOnly = new EnumMap<>(EditorElement.class);

    private final ObservableMap<String, String> customProperties = FXCollections.observableHashMap();

// Path: api/src/main/java/de/tesis/dynaware/grapheditor/EditorElement.java
// public enum EditorElement
// {
//     CONNECTOR,
//     NODE,
//     JOINT;
// }
// 
// Path: api/src/main/java/de/tesis/dynaware/grapheditor/impl/GraphEventManagerImpl.java
// public class GraphEventManagerImpl implements GraphEventManager
// {
// 
//     private GraphInputGesture gesture;
//     private Object owner;
// 
//     @Override
//     public boolean activateGesture(final GraphInputGesture pGesture, final Event pEvent, final Object pOwner)
//     {
//         if (!canOverwrite(owner, pOwner))
//         {
//             return false;
//         }
//         if (canActivate(pGesture, pEvent))
//         {
//             gesture = pGesture;
//             owner = pOwner;
//             return true;
//         }
//         // ELSE:
//         return false;
//     }
// 
//     private boolean canActivate(final GraphInputGesture pGesture, final Event pEvent)
//     {
//         final GraphInputGesture current = gesture;
//         if (current == pGesture)
//         {
//             return true;
//         }
//         else if (current == null)
//         {
//             final boolean isTouch = pEvent instanceof TouchEvent || pEvent instanceof MouseEvent me && me.isSynthesized()
//                     || pEvent instanceof ScrollEvent se && se.getTouchCount() > 0;
//             if (!isTouch)
//             {
//                 return switch (pGesture)
//                         {
//                             case PAN -> pEvent instanceof ScrollEvent se && !se.isControlDown()
//                                     || pEvent instanceof MouseEvent me && me.isSecondaryButtonDown();
//                             case ZOOM -> pEvent instanceof ScrollEvent se && se.isControlDown();
//                             case SELECT, CONNECT, MOVE, RESIZE -> pEvent instanceof MouseEvent me &&
//                                     me.isPrimaryButtonDown();
//                         };
//             }
//             else
//             {
//                 return switch (pGesture)
//                         {
//                             case ZOOM -> pEvent instanceof ZoomEvent;
//                             case PAN -> pEvent instanceof TouchEvent && ((TouchEvent) pEvent).getTouchCount() > 1;
//                             case SELECT, CONNECT, MOVE, RESIZE -> true;
//                         };
//             }
//         }
//         return false;
//     }
// 
//     @Override
//     public boolean finishGesture(final GraphInputGesture pExpected, final Object pOwner)
//     {
//         if (gesture == pExpected && (owner == pOwner || !isVisible(owner)))
//         {
//             gesture = null;
//             owner = null;
//             return true;
//         }
//         return false;
//     }
// 
//     private static boolean canOverwrite(final Object pExisting, final Object pCandidate)
//     {
//         if (pExisting == pCandidate)
//         {
//             return true;
//         }
//         if (pCandidate == null)
//         {
//             return false;
//         }
//         return pExisting == null || !isVisible(pExisting);
//     }
// 
//     private static boolean isVisible(final Object pNode)
//     {
//         if (pNode != null)
//         {
//             if (pNode instanceof Node n)
//             {
//                 return n.isVisible() && n.getParent() != null && n.getScene() != null;
//             }
//             return true;
//         }
//         // ELSE: null
//         return false;
//     }
// }


// Path: api/src/main/java/de/tesis/dynaware/grapheditor/utils/GraphEditorProperties.java
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import de.tesis.dynaware.grapheditor.EditorElement;
import de.tesis.dynaware.grapheditor.impl.GraphEventManagerImpl;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.event.Event;

/*
 * Copyright (C) 2005 - 2014 by TESIS DYNAware GmbH
 */
package de.tesis.dynaware.grapheditor.utils;




/**
 * General properties for the graph editor.
 *
 * <p>
 * For example, should the editor have 'bounds', or should objects be draggable outside the editor area?
 * </p>
 *
 * <p>
 * If a bound is <b>active</b>, objects that are dragged or resized in the editor should stop when they hit the edge,
 * and the editor region will not try to grow in size. Otherwise it will grow up to its max size.
 * </p>
 *
 * <p>
 * Also stores properties for whether the grid is visible and/or snap-to-grid is on.
 * </p>
 */
public class GraphEditorProperties implements GraphEventManager
{

    /**
     * The default max width of the editor region, set on startup.
     */
    public static final double DEFAULT_MAX_WIDTH = Double.MAX_VALUE;
    /**
     * The default max height of the editor region, set on startup.
     */
    public static final double DEFAULT_MAX_HEIGHT = Double.MAX_VALUE;

    public static final double DEFAULT_BOUND_VALUE = 15;
    public static final double DEFAULT_GRID_SPACING = 12;

    // The distance from the editor edge at which the objects should stop when dragged / resized.
    private double northBoundValue = DEFAULT_BOUND_VALUE;
    private double southBoundValue = DEFAULT_BOUND_VALUE;
    private double eastBoundValue = DEFAULT_BOUND_VALUE;
    private double westBoundValue = DEFAULT_BOUND_VALUE;

    // Off by default.
    private final BooleanProperty gridVisible = new SimpleBooleanProperty(this, "gridVisible"); //$NON-NLS-1$
    private final BooleanProperty snapToGrid = new SimpleBooleanProperty(this, "snapToGrid"); //$NON-NLS-1$
    private final DoubleProperty gridSpacing = new SimpleDoubleProperty(this, "gridSpacing", DEFAULT_GRID_SPACING); //$NON-NLS-1$

    private final Map<EditorElement, BooleanProperty> readOnly = new EnumMap<>(EditorElement.class);

    private final ObservableMap<String, String> customProperties = FXCollections.observableHashMap();

    private final GraphEventManager eventManager = new GraphEventManagerImpl();