/**
 * This program and the accompanying materials
 * are made available under the terms of the License
 * which accompanies this distribution in the file LICENSE.txt
 */
package com.archimatetool.editor.diagram.policies;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.NonResizableEditPolicy;
import org.eclipse.gef.editpolicies.ResizableEditPolicy;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;

import com.archimatetool.editor.diagram.commands.CreateDiagramObjectCommand;
import com.archimatetool.editor.diagram.commands.SetConstraintObjectCommand;
import com.archimatetool.editor.diagram.editparts.IConstrainedSizeEditPart;
import com.archimatetool.editor.diagram.editparts.INonResizableEditPart;
import com.archimatetool.model.IDiagramModelContainer;
import com.archimatetool.model.IDiagramModelObject;
import com.archimatetool.model.ILockable;



/**
 * Policy for General Diagrams
 * 
 * @author Phillip Beauvoir
 */
public class DiagramLayoutPolicy
extends XYLayoutEditPolicy {
    
    @Override
    protected Command getCreateCommand(CreateRequest request) {
        Rectangle bounds = getConstraintFor(request);
        return new CreateDiagramObjectCommand(getHost(), request, bounds);
    }
    
    /*
     * Over-ride this to get any extra constraints for an object
     */
    @Override
    protected Rectangle getConstraintFor(CreateRequest request) {
        Rectangle bounds = (Rectangle)super.getConstraintFor(request);
        
        Dimension d = getMaximumSizeFor(request.getNewObjectType());
        bounds.width = Math.min(d.width, bounds.width);
        bounds.height = Math.min(d.height, bounds.height);
        
        return bounds;
    }
    
    /**
     * @param object
     * @return The Maximum size constraint for an object
     */
    protected Dimension getMaximumSizeFor(Object object) {
        return IFigure.MAX_DIMENSION;
    }
    
    @Override
    protected EditPolicy createChildEditPolicy(EditPart child) {
        if(isChildEditPartLocked(child)) {
            return new LockedResizableEditPolicy();
        }
        if(child instanceof INonResizableEditPart) {
            return new NonResizableEditPolicy();
        }
        if(child instanceof IConstrainedSizeEditPart) {
            return new ConstrainedResizableEditPolicy();
        }
        return new ResizableEditPolicy();
    }
    
    @Override
    protected Command createChangeConstraintCommand(ChangeBoundsRequest request, EditPart child, Object constraint) {
        // If child part is locked, limit movement
        if(isChildEditPartLocked(child)) {
            return null;
        }

        // Return a command that can move and/or resize a child
        if(constraint instanceof Rectangle) {
            return new SetConstraintObjectCommand(request, (IDiagramModelObject)child.getModel(), (Rectangle)constraint);
        }

        return null;
    }
    
    /**
     * @param child
     * @return True id child EditPart is locked
     */
    protected boolean isChildEditPartLocked(EditPart child) {
        return child.getModel() instanceof ILockable && ((ILockable)child.getModel()).isLocked();
    }
    
    /*
     * This allows us to drag parts from a parent container to another.
     * This is the "add" counterpart to the "remove" Command created in BasicContainerEditPolicy.getOrphanChildrenCommand(GroupRequest);
     * 
     * If you don't want a part to be added, return null here.
     */
    @Override
    protected AddObjectCommand createAddCommand(ChangeBoundsRequest request, EditPart childEditPart, Object constraint) {
        IDiagramModelContainer parent = (IDiagramModelContainer)getHost().getModel();
        IDiagramModelObject child = (IDiagramModelObject)childEditPart.getModel();
        
        // Keep within box
        Rectangle bounds = (Rectangle)constraint;
        if(bounds.x < 0) {
            bounds.x = 0;
        }
        if(bounds.y < 0) {
            bounds.y = 0;
        }
        
        return new AddObjectCommand(parent, child, bounds);
    }
    
    /**
     * AddObjectCommand
     */
    public static class AddObjectCommand extends Command {
        IDiagramModelContainer parent;
        IDiagramModelObject child;
        Rectangle bounds;

        public AddObjectCommand(IDiagramModelContainer parent, IDiagramModelObject child, Rectangle bounds) {
            this.parent = parent;
            this.child = child;
            this.bounds = bounds.getCopy();
        }
        
        @Override
        public void execute() {
            child.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
            parent.getChildren().add(child);
        }

        @Override
        public void undo() {
            parent.getChildren().remove(child);
        }
        
        @Override
        public void dispose() {
            parent = null;
            child = null;
        }
    }
}


@@ -1044,32 +1044,79 @@
 zableEditPart;%0D%0A
+import com.archimatetool.model.IDiagramModel;%0D%0A
 import com.archi
@@ -4231,32 +4231,85 @@
 l();%0D%0A        %0D%0A
+        Rectangle bounds = (Rectangle)constraint;%0D%0A%0D%0A
         // Keep 
@@ -4315,16 +4315,27 @@
  within 
+the parent 
 box%0D%0A   
@@ -4343,51 +4343,163 @@
     
-Rectangle bounds = (Rectangle)constraint;%0D%0A
+// Fixed 2019-06-11 to check that the parent is not a diagram model (which can have negative space)%0D%0A        if(!(parent instanceof IDiagramModel)) %7B%0D%0A    
     
@@ -4530,24 +4530,28 @@
             
+ 
+   
 bounds.x = 0
@@ -4553,32 +4553,36 @@
 x = 0;%0D%0A        
+    
 %7D%0D%0A        if(bo
@@ -4568,32 +4568,36 @@
      %7D%0D%0A        
+ 
+   
 if(bounds.y %3C 0)
@@ -4592,32 +4592,36 @@
 ounds.y %3C 0) %7B%0D%0A
+    
             boun
@@ -4627,24 +4627,39 @@
 nds.y = 0;%0D%0A
+            %7D%0D%0A
         %7D%0D%0A 

Fix child object x,y set to 0,0 when dragged out of parent onto diagram