/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © 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 ilog.views.*;
import ilog.views.graphic.*;
//import ilog.views.util.IlvProductUtil;
import ilog.views.util.swing.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 * This sample shows how the alignment mechanism of rotated text works.
 * 
 */
public class RotateAlignText extends JApplet
{
  {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Rogue Wave JViews Diagrammer Deployment license.
//    IlvProductUtil.DeploymentLicenseRequired(
//        IlvProductUtil.JViews_Diagrammer_Deployment);
  }

  IlvText text = 
    new IlvText(new IlvPoint(100, 100), 
                "This is a multiline\ntext that\ncan be rotated\nand aligned");
  IlvLine normLine = new IlvLine();
  IlvLine orthLine = new IlvLine();
  IlvManager manager;
  IlvManagerView view;
  int initialTextRotationAngle = 10;
  int initialThresholdAngle = 30;
  int initialRotationAngle = 45;

  /**
   * Initializes the applet/application.
   */
  public void init()
  {
    super.init();

    // fill the manager with the text object and the two auxiliary lines
    manager = new IlvManager();

    text.setFont(new Font("arial", Font.BOLD, 15));
    text.setAntialiasing(true);
    text.setFractionalMetrics(true);
    manager.addObject(text, true);
    adjust(initialTextRotationAngle,
           initialRotationAngle,
           initialThresholdAngle);

    normLine.setForeground(Color.green);
    orthLine.setForeground(Color.pink);
    manager.addObject(normLine, true);
    manager.addObject(orthLine, true);

    // create the view
    view = new IlvManagerView(manager) {
      public void reshape(int x, int y, int w, int h) {
        // As of JDK1.5, the method Component.reshape is deprecated and calls
        // the method Component.setBounds. Overriding the deprecated variant
        // ensures that it works when either the deprecated, or the replacement
        // variant are called.
        super.reshape(x, y, w, h);
        centerText(w, h);
      }
    };
    view.setBackground(Color.white);
    view.setAntialiasing(true);

    // create three dial controls.

    // The outer dial controls the rotation of the text
    final JDial outerDial = new JDial(true);
    outerDial.setAngleColor(new Color(0,200,0));
    outerDial.setAngle(initialTextRotationAngle);

    // the middle dial controls the rotation alignment axes
    JDial middleDial = new JDial(false);
    middleDial.setAngleColor(new Color(0,0,200));
    middleDial.setAngle(initialRotationAngle);

    // the innermost dial controls the rotation alignment threshold angle
    JDial innerDial = new JDial(false);
    innerDial.setAngleColor(new Color(200,0,0));
    innerDial.setShowAngleColorAt4Sides(true);
    innerDial.setStartAngle(initialRotationAngle);
    innerDial.setAngle(initialThresholdAngle);

    // nest the dials and the view inside eachother
    outerDial.add(middleDial);
    middleDial.add(innerDial);
    innerDial.add(view);

    // configure the labels
    outerDial.getTopLeftLabel().setForeground(Color.green.darker());
    outerDial.getTopRightLabel().setForeground(Color.blue);
    outerDial.getBottomLeftLabel().setForeground(Color.red.darker());
    outerDial.getTopLeftLabel().setText("" + initialTextRotationAngle + " degree");
    outerDial.getTopRightLabel().setText("" + initialRotationAngle + " degree");
    outerDial.getBottomLeftLabel().setText("" + initialThresholdAngle + " degree");

    // outer dial rotates the text
    outerDial.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          int angle = ((JDial)evt.getSource()).getAngle();
          outerDial.getTopLeftLabel().setText("" + angle + " degree");
          adjust(angle, text.getRotationAlignmentAngle(),
                        text.getRotationAlignmentThresholdAngle()); 
        }
      });

    // middle dial sets the rotation alignment angle
    middleDial.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          JDial middleDial1 = (JDial)evt.getSource();
          int angle = middleDial1.getAngle();
          outerDial.getTopRightLabel().setText("" + angle + " degree");
          if (angle >= 180) {
            while (angle >= 180) 
              angle -= 180;
            // could indicate that the middleDial has only 180 degree range:
            // middleDial.setAngle(angle);
          }
          JDial innerDial1 = (JDial)middleDial1.getContents();
          innerDial1.setStartAngle(angle);
          adjust(getTextAngle(), angle,
                 text.getRotationAlignmentThresholdAngle());
        }
      });

    // middle dial sets the rotation alignment angle
    innerDial.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
          JDial innerDial1 = (JDial)evt.getSource();
          int angle = innerDial1.getAngle();
          if (angle >= 90) {
            while (angle >= 90) 
              angle -= 90;
            innerDial1.setAngle(angle);
          }
          outerDial.getBottomLeftLabel().setText("" + angle + " degree");
          adjust(getTextAngle(), text.getRotationAlignmentAngle(), angle);
        }
      });

    getContentPane().setLayout(new BorderLayout(0,0));
    getContentPane().add(outerDial, BorderLayout.CENTER);
  }

  /**
   * Called when this applet is being reclaimed in order to destroy
   * any resources that it has allocated.
   */
  public void destroy()
  {
    super.destroy();

    // This method is intended to workaround memory management issues
    // in the Sun JRE. Please refer to the method documentation for more
    // details and a description of the known issues.
    IlvSwingUtil.cleanupApplet();
  }

  /**
   * Adjust the text and the auxiliary lines to the new situation.
   */
  void adjust(final float textAngle,
              final float rotationAlignmentAngle,
              final float rotationAlignmentThreshold)
  {
    double currentAngle = getTextAngle();
    final double deltaAngle = textAngle - currentAngle;
    text.getGraphicBag().applyToObject(text, new IlvApplyObject() {
        public void apply(IlvGraphic g, Object arg) {
          text.rotate(new IlvPoint(), deltaAngle);
          text.setRotationAlignmentAngle(rotationAlignmentAngle);
          text.setRotationAlignmentThresholdAngle(rotationAlignmentThreshold);
        }
    }, null, true);

    // center the text object
    if (view != null) {
      Rectangle r = view.getBounds();
      centerText(r.width, r.height);
    }
  }

  /**
   * Returns the current angle of the text object.
   */
  float getTextAngle()
  {
    IlvTransformer t = text.getTransformer();
    if (t == null) return 0;
    return (float)(90 - 180 * Math.atan2(t.getx22(), t.getx21()) / Math.PI);
  }

  /**
   * Center the text object in the view.
   */
  void centerText(final int w, final int h)
  {
    // center the text
    IlvPoint p = text.getEffectiveAnchorPoint();
    IlvRect bbox = text.boundingBox();
    float dx = p.x - bbox.x;
    float dy = p.y - bbox.y;
    float x = w  / 2 - dx;
    float y = h  / 2 - dy;
    manager.moveObject(text, x, y, true);

    // rotate the two auxiliary lines as necessary
    manager.applyToObject(normLine, new IlvApplyObject() {
        public void apply(IlvGraphic g, Object arg) {
          double angle = Math.PI * text.getRotationAlignmentAngle() / 180;
          float r = Math.max(w, h);
          IlvPoint p0 = new IlvPoint((float)(w/2 - r * Math.cos(angle)),
                                     (float)(h/2 - r * Math.sin(angle)));
          IlvPoint p1 = new IlvPoint((float)(w/2 + r * Math.cos(angle)),
                                     (float)(h/2 + r * Math.sin(angle)));
          normLine.setFrom(p0);
          normLine.setTo(p1);
        }
     }, null, true);
    manager.applyToObject(normLine, new IlvApplyObject() {
        public void apply(IlvGraphic g, Object arg) {
          double angle = Math.PI * text.getRotationAlignmentAngle() / 180;
          float r = Math.max(w, h);
          IlvPoint p0 = new IlvPoint((float)(w/2 - r * Math.sin(angle)),
                                     (float)(h/2 + r * Math.cos(angle)));
          IlvPoint p1 = new IlvPoint((float)(w/2 + r * Math.sin(angle)),
                                     (float)(h/2 - r * Math.cos(angle)));
          orthLine.setFrom(p0);
          orthLine.setTo(p1);
        }
     }, null, true);
  }

  /**
   * The main routine.
   */
  public static void main(String[] args) 
  {
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    SwingUtilities.invokeLater(
      new Runnable() {
        public void run() {
          RotateAlignText applet = new RotateAlignText();
          applet.init();

          JFrame frame = new JFrame();
          frame.setTitle("JViews Rotated Aligned Text Sample");
          frame.setSize(600, 620);
          frame.getContentPane().add(applet);
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setVisible(true);
        }
      });
  }
}