/*
 * 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.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.IlvDiagrammerViewBar;
import ilog.views.diagrammer.application.IlvDiagrammerAction;

import ilog.views.sdm.IlvSDMEngine;
import ilog.views.sdm.renderer.graphlayout.IlvGraphLayoutRenderer;
import ilog.views.sdm.util.IlvSDMMutableStyleSheet;

import ilog.views.graphlayout.IlvGraphLayout;
import ilog.views.graphlayout.IlvGraphLayoutReport;
import ilog.views.graphlayout.GraphLayoutEvent;
import ilog.views.graphlayout.GraphLayoutEventListener;
import ilog.views.graphlayout.random.IlvRandomLayout;

import ilog.views.IlvPoint;
import ilog.views.IlvTransformer;

import ilog.views.util.IlvProductUtil;
import ilog.views.util.IlvResourceUtil;
import ilog.views.util.swing.IlvSwingUtil;
import ilog.views.util.swing.IlvJComboBox;

import javax.swing.*;
import java.util.*;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import java.net.URL;

/**
 * This is a very simple applet/application that uses the
 * <code>IlvDiagrammer</code> to perform a rotated layout.
 * It uses the rotation angle feature of the graph layout renderer.
 * It loads a style sheet containing the layout specification.
 * It allows to set various layout parameters by using the
 * <code>IlvSDMMutableStyleSheet</code>. 
 */ 
public class RotatedLayoutApplet extends JApplet
{
  static {
    // This applet is designed to run only with default resource bundle
    // and various selected other resource bundles.
    // Setting the available resource suffixes avoids the applet
    // trying to load resource bundles for other locales over the network,
    // even if the current locale of the browser is different.
    if (IlvResourceUtil.isInApplet())
      IlvResourceUtil.setAvailableResourceSuffixes("", "_ja");

    // Test code for whether the demo works in RTL locales
    // Locale newLocale = new Locale("he");
    // IlvSwingUtil.setDefaultLocale(newLocale);
  }

  {
    // This sample uses JViews Diagrammer features. When deploying an
    // application that includes this code, you need 
    // a Rogue Wave JViews Diagrammer Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(
        IlvProductUtil.JViews_Diagrammer_Deployment);
  }

  /** The diagrammer */
  IlvDiagrammer diagrammer = new IlvDiagrammer();

  /** The style sheet for temporary changes */
  IlvSDMMutableStyleSheet styleSheet = new IlvSDMMutableStyleSheet(
                                          diagrammer.getEngine(), true, false);

  /** The display names of the samples */
  String[] sampleNames;

  /** The base file names of the samples (excluding the .xml or .css */
  String[] fileNames;

  /** The shear modes: the values must be the index in the combo box. */
  final static int UNSHEARED = 0;
  final static int SHEAR_X   = 1;
  final static int SHEAR_Y   = 2;

  /** Whether the rotation is a shear in X direction. */
  int shearMode = UNSHEARED;

  /** A text field to display messages */
  JTextField msgLine = new JTextField();

  /** The default angle */
  static final float DEFAULT_ANGLE = 30.f;

  /** Fields for the offset parameters */
  NumberField rotationAngleSelector =
    new NumberField(-45, 45, DEFAULT_ANGLE, false, 6, 1);

  /**
   * Initializes the applet/application.
   */
  public void init()
  {
    // we use the standard diagrammer toolbar
    IlvDiagrammerViewBar toolbar = new IlvDiagrammerViewBar();

    // various settings of the diagrammer
    diagrammer.setSelectMode(true);
    diagrammer.setScrollable(true);
    diagrammer.setEditingAllowed(true);
    diagrammer.setMinimumZoom(0.02f);
    diagrammer.setMaximumZoom(10f);
    diagrammer.getView().setBackground(Color.white);
    diagrammer.getView().setForeground(SystemColor.windowText);

    // initialize the sample names
    initSampleNames();

    // create the file selector
    JComboBox fileSelector = new IlvJComboBox();
    for (int i = 0; i < sampleNames.length; i++)
      fileSelector.addItem(sampleNames[i]);
    fileSelector.setToolTipText(getString("FileSelector.Tooltip"));
    fileSelector.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          JComboBox comboBox = (JComboBox)event.getSource();
          String sampleName = (String)comboBox.getSelectedItem();
          for (int i = 0; i < sampleNames.length; i++)
            if (sampleNames[i].equals(sampleName))
              loadSample(i);
        }
      });

    // create the top panel with the toolbar and the file selector
    JPanel topPanel = new JPanel();
    topPanel.setLayout(new FlowLayout(FlowLayout.LEADING));
    topPanel.add(toolbar);
    JLabel label = new JLabel(getString("FileSelector.Label"));
    label.setToolTipText(getString("FileSelector.Tooltip"));
    topPanel.add(label);
    topPanel.add(fileSelector);

    // create the bottom panel with the layout buttons and the message line
    JPanel bottomPanel = new JPanel();
    bottomPanel.setLayout(new BorderLayout());
    bottomPanel.add(createParameterPanel(), BorderLayout.CENTER);
    bottomPanel.add(msgLine, BorderLayout.SOUTH);
    msgLine.setEditable(false);

    // put diagrammer, top panel and bottom panel together
    getContentPane().setLayout(new BorderLayout(0, 0));
    getContentPane().add(diagrammer, BorderLayout.CENTER);
    getContentPane().add(topPanel, BorderLayout.NORTH);
    getContentPane().add(bottomPanel, BorderLayout.SOUTH);

    // set the component orientation according to the locale
    Locale loc = IlvSwingUtil.getDefaultLocale();
    ComponentOrientation co = ComponentOrientation.getOrientation(loc);
    getContentPane().applyComponentOrientation(co);

    // set the initial rotation angle
    styleSheet.setDeclaration("GraphLayout", "rotationAngle", "" + DEFAULT_ANGLE);

    // load the initial sample
    loadSample(0);
    diagrammer.getView().fitTransformerToContent(true);
  }

  /**
   * 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 work around memory management issues
    // in the Sun JRE. See the method documentation for more
    // details and a description of the known issues.
    IlvSwingUtil.cleanupApplet();
  }

  /**
   * Initialize the information about the samples.
   */
  private void initSampleNames()
  {
    sampleNames = new String[4];
    fileNames = new String[4];

    sampleNames[0] = getString("Sample.TreeLayout");
    fileNames[0]   = "tree";
    sampleNames[1] = getString("Sample.HierarchicalLayout");
    fileNames[1]   = "hierarchical";
    sampleNames[2] = getString("Sample.GridLayout");
    fileNames[2]   = "grid";
    sampleNames[3] = getString("Sample.TMLLayout");
    fileNames[3]   = "tml";
  }

  /**
   * Creates the layout parameter panel.
   */
  private JPanel createParameterPanel()
  {
    JPanel panel = new JPanel();
    GridBagLayout gridbag = new GridBagLayout();
    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;
    c.anchor = GridBagConstraints.EAST;
    panel.setLayout(gridbag);

    // rotation angle parameter
    c.gridx = 0;
    c.gridy = 0;
    JLabel label = new JLabel(getString("RotationAngle.Label"));
    label.setToolTipText(getString("RotationAngle.Tooltip"));
    panel.add(label, c);
    c.gridx = 1;
    panel.add(rotationAngleSelector, c);

    rotationAngleSelector.setToolTipText(
      getString("RotationAngle.Tooltip"));
    rotationAngleSelector.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          setRotationAngle((NumberField)e.getSource());
        }
      });

    // spacer
    c.gridx = 2;
    panel.add(new JLabel("       "));

    // rotation angle parameter
    c.gridx = 3;
    label = new JLabel(getString("ShearMode.Label"));
    label.setToolTipText(getString("ShearMode.Tooltip"));
    panel.add(label, c);
    c.gridx = 4;
    JComboBox shearModeSelector = new IlvJComboBox();
    shearModeSelector.addItem(getString("ShearMode.Unsheared"));
    shearModeSelector.addItem(getString("ShearMode.ShearX"));
    shearModeSelector.addItem(getString("ShearMode.ShearY"));
    shearModeSelector.setToolTipText(getString("ShearMode.Tooltip"));
    shearModeSelector.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent event) {
          JComboBox comboBox = (JComboBox)event.getSource();
          shearMode = comboBox.getSelectedIndex();
          setRotationAngle(rotationAngleSelector);
        }
      });
    panel.add(shearModeSelector, c);

    // set the component orientation according to the locale
    Locale loc = IlvSwingUtil.getDefaultLocale();
    ComponentOrientation co = ComponentOrientation.getOrientation(loc);
    panel.applyComponentOrientation(co);

    return panel;
  }

  /**
   * Load a sample file. It loads both the XML file and the style file.
   * @param index The index of the sample file.
   */
  private void loadSample(int index)
  {
    String fileNameBase = fileNames[index];
    try {
      showMessage(getString("FileReadingStartMessage"), fileNameBase);
      // load an empty file. This avoids that we get temporary styling
      // warnings because the data and css files don't match eachother
      diagrammer.setDataFile(
        IlvSwingUtil.getRelativeURL(this, "data/empty.xml"));
      // load the style file
      diagrammer.setStyleSheet(
        IlvSwingUtil.getRelativeURL(this, "data/" + fileNameBase + ".css"));
      // load a mutable style file that we use for temporary style changes
      diagrammer.getEngine().setStyleSheets(1, styleSheet.toString());
      // load the data file
      diagrammer.setDataFile(
        IlvSwingUtil.getRelativeURL(this, "data/" + fileNameBase + ".xml"));
      // zoom to fit 
      diagrammer.fitToContents(); 
      showMessage(getString("FileReadingDoneMessage"), fileNameBase);
    } catch (Exception e) {
      showMessage(e.getMessage());
    }
  }

  /**
   * Sets the rotation angle of the rotated model.
   */
  private void setRotationAngle(NumberField valueSelector)
  {
    styleSheet.setAdjusting(true);
    try {
      IlvTransformer t;
      double D;
      double angle = valueSelector.getValue();
      switch (shearMode) {
        case UNSHEARED:
          styleSheet.removeDeclaration("GraphLayout", "rotationTransformer");
          styleSheet.setDeclaration("GraphLayout", "rotationAngle", "" + angle);
          break;
        case SHEAR_X:
          t = new IlvTransformer(new IlvPoint(), angle);
          t.setValues(t.getx11(), 0, t.getx21(), t.getx22(),
                      t.getx0(), t.gety0());
          D = t.getDeterminant();
          t.setValues(t.getx11() / D, t.getx12() / D,
                      t.getx21() / D, t.getx22() / D,
                      t.getx0(), t.gety0());
          styleSheet.removeDeclaration("GraphLayout", "rotationAngle");
          styleSheet.setDeclaration("GraphLayout", "rotationTransformer",
             "" + t.getx11() + "," + t.getx12() + "," + 
                  t.getx21() + "," + t.getx11() + "," +
                  t.getx0() + "," + t.gety0());
          break;
        case SHEAR_Y:
          t = new IlvTransformer(new IlvPoint(), angle);
          t.setValues(t.getx11(), t.getx12(), 0, t.getx22(),
                      t.getx0(), t.gety0());
          D = t.getDeterminant();
          t.setValues(t.getx11() / D, t.getx12() / D,
                      t.getx21() / D, t.getx22() / D,
                      t.getx0(), t.gety0());
          styleSheet.removeDeclaration("GraphLayout", "rotationAngle");
          styleSheet.setDeclaration("GraphLayout", "rotationTransformer",
             "" + t.getx11() + "," + t.getx12() + "," + 
                  t.getx21() + "," + t.getx11() + "," +
                  t.getx0() + "," + t.gety0());
          break;
      }
    } finally {
      styleSheet.setAdjusting(false);
      diagrammer.fitToContents(); 
    }
  }

  /**
   * Displays a message.
   */
  void showMessage(String message)
  {
    // the message is displayed in the message line
    msgLine.setText(message);
    msgLine.paintImmediately(0, 0, msgLine.getWidth(), msgLine.getHeight());
  }

  void showMessage(String msgformat, Object val)
  {
    Object[] args = { val };
    showMessage(MessageFormat.format(msgformat, args));
  }

  /**
   * Returns a string.
   */
  static String getString(String key)
  {
    return IlvResourceUtil.getString(key, RotatedLayoutApplet.class);
  }

  /**
   * Allows you to run the demo as a standalone application.
   */
  public static void main(String[] args)
  {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        RotatedLayoutApplet applet = new RotatedLayoutApplet();
        applet.init();

        JFrame frame = new JFrame(getString("Frame.Label"));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 600);
        frame.getContentPane().add(applet);
        frame.setVisible(true);
        
      }
    });
  }
}