/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import ilog.views.IlvGraphic;
import ilog.views.IlvManager;
import ilog.views.IlvManagerView;
import ilog.views.IlvRect;
import ilog.views.IlvReshapeSelection;
import ilog.views.IlvSelection;
import ilog.views.accelerator.IlvFitToSizeAccelerator;
import ilog.views.accelerator.IlvIdentityAccelerator;
import ilog.views.accelerator.IlvZoomInAccelerator;
import ilog.views.accelerator.IlvZoomOutAccelerator;
import ilog.views.graphic.IlvEllipse;
import ilog.views.graphic.IlvRectangle;
import ilog.views.interactor.IlvSelectInteractor;
//import ilog.views.util.IlvProductUtil;

/**
 * This example shows how to constrain the reshaping of the selected 
 * graphic object. This interactor performs differently if the selected
 * graphic object has a constraint installed. 
 */
public class ConstrainedReshapeInteractor
  extends IlvReshapeSelection
{ 
  /**
   * The constraint key:
   */
  public final static String CONSTRAINT_PROPERTY = "ConstraintProperty";
    
  /** 
   * Creates an moveObjectInteractor.
   */
  public ConstrainedReshapeInteractor()
  {
    super();
  }

  /**
   * This method is called to let the interactor reshape an object. 
   * If the specified graphic object has a constraint installed, 
   * this method tests if the constraint is satisfied. If yes,
   * the graphic object will be reshaped. If no, the reshape action 
   * will be rejected.
   * @param graphic The <code>IlvGraphic</code> to reshape.
   * @param newRect The new rectangle defining the bounds of the graphic.
   *         The rectangle is in manager's coordinates.
   */
  Override
  protected void reshapeObject(IlvGraphic graphic, final IlvRect newRect)
  {
    // Get the constraint
    Object property = graphic.getProperty(CONSTRAINT_PROPERTY);
    // Test the size
    if (property instanceof Constraint) {
      if (!((Constraint)property).isGoodSize(newRect)) {
        Toolkit.getDefaultToolkit().beep();
        return;      
      }
    }
    super.reshapeObject(graphic, newRect);
  }
  
  
  public static void main(String[] args)
  {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Diagrammer Deployment license.
//    IlvProductUtil.DeploymentLicenseRequired(
//        IlvProductUtil.JViews_Diagrammer_Deployment);

    // Set the default reshape interactor. This new interactor takes into account 
    // the constraint installed on graphic objects:
    IlvSelection.SetDefaultInteractor(ConstrainedReshapeInteractor.class.getName());
    
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    SwingUtilities.invokeLater(
      new Runnable() {
        Override
        public void run() {
          JFrame f = new JFrame("Constrained Reshape Sample");
          f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          f.setSize(new Dimension(300, 300));
          IlvManager mgr = new IlvManager();
          mgr.addAccelerator(new IlvIdentityAccelerator(KeyEvent.KEY_PRESSED,
                          KeyEvent.VK_I, 0));
          mgr.addAccelerator(new IlvZoomOutAccelerator(KeyEvent.KEY_PRESSED,
                                                       KeyEvent.VK_U, KeyEvent.CTRL_MASK));
          mgr.addAccelerator(new IlvZoomInAccelerator(KeyEvent.KEY_PRESSED,
                                                      KeyEvent.VK_Z, KeyEvent.CTRL_MASK));
          mgr.addAccelerator(new IlvFitToSizeAccelerator(KeyEvent.KEY_PRESSED, 
                                                         KeyEvent.VK_F, 0));
          
          IlvGraphic g = new IlvRectangle(new IlvRect(10,10,30,30));
          g.setBackground(Color.yellow);
          g.setFillOn(true);
          g.setProperty(CONSTRAINT_PROPERTY, new Constraint(5, 2, 80, 60));
          mgr.addObject(g, false);
          
          g = new IlvEllipse(new IlvRect(50,50,50,30));
          g.setBackground(Color.cyan);
          g.setFillOn(true);
          g.setProperty(CONSTRAINT_PROPERTY, new Constraint(5, 2, 80, 60));
          mgr.addObject(g, false);

          IlvManagerView v = new IlvManagerView(mgr);

          // Install View Interactor
          IlvSelectInteractor inter = new IlvSelectInteractor();
          inter.setOpaqueMove(true);
          inter.setOpaqueResize(true);
          v.setInteractor(inter);

          f.getContentPane().setLayout(new BorderLayout());
          f.getContentPane().add("Center", v);
          f.setVisible(true);
        }
      });
  }
}

/**
 * Defines the constraints for a graphic object.
 */
class Constraint {   
  /**
   * The minimum width of the constrained object.
   */
  public double minWidth = 1;
  /**
   * The minimum height of the constrained object.
   */
  public double minHeight = 1;
  /**
   * The maximum width of the constrained object.
   */
  public double maxWidth = 100;
  /**
   * The maximum height of the constrained object.
   */
  public double maxHeight = 100;

  /**
   * Creates a constraint by specifying the constrained graphic object and its 
   * constraint values.
   * @param minWidth The minimum width of the constrained object.
   * @param minHeight The minimum height of the constrained object.
   * @param maxWidth The maximum width of the constrained object.
   * @param maxHeight The maximum height of the constrained object.
   */
  public Constraint(double minWidth, double minHeight, double maxWidth, double maxHeight) {
    this.minWidth = minWidth;
    this.minHeight = minHeight;
    this.maxWidth = maxWidth;
    this.maxHeight = maxHeight;
  }
  
  /**
   * Checks if the specified rect is a good size.
   * @param size The size to be tested.
   * @return True The rect meets the constraints.
   */
  public boolean isGoodSize(IlvRect size) {
    return size.width <= maxWidth 
        && size.width >= minWidth
        && size.height >= minHeight
        && size.height <= maxHeight;      
  }
}