/*
 * 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.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyVetoException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.StringTokenizer;

import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToolBar;

import ilog.views.IlvRect;
import ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.IlvDiagrammerAction;
import ilog.views.diagrammer.application.IlvDiagrammerFrame;
import ilog.views.diagrammer.application.IlvDiagrammerPaletteBar;
import ilog.views.util.IlvProductUtil;

/**
 * This example shows how to build a business process modeler based on a diagram
 * component, {@link ilog.views.diagrammer.IlvDiagrammer}.
 * <p>
 * The example is based on the predefined class
 * {@link ilog.views.diagrammer.application.IlvDiagrammerApplication} supplied
 * with Perforce JViews Diagrammer.
 * <p>
 * You can also look at the "Diagram Editor" example, which shows how to build
 * your own customized application using the components of the
 * {@link ilog.views.diagrammer.application} package (toolbars, menus, and so
 * on).
 */
public class ProcessModeler extends IlvDiagrammerFrame {
  // The resource bundle used to get localized messages for
  // this class.
  //
  private ResourceBundle bundle;

  private URL[] styleSheets;
  private JComboBox<URL> combo;
  private JTextField descriptionField;

  /**
   * Creates a new process modeler.
   */
  public ProcessModeler() {
    super();

    // 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);

    // Load the property file.
    //
    bundle = ResourceBundle.getBundle("modeler");

    // Set default arguments.
    //
    setDefaultArgs(new String[] { "-title", bundle.getString("ProcessModeler.FrameTitle"), "-mdi", "-tree", "-psheet",
        "-edit", "-style", "data/default.css", "-palette", "data/bpm-palette.xml", "-data", "data/hotline.idpr" });
  }

  /**
   * Maximizes the initial frame.
   */
  Override
  protected void ready() {
    super.ready();

    JInternalFrame[] frames = getDesktopPane().getAllFrames();
    if (frames != null && frames.length > 0) {
      try {
        frames[0].setMaximum(true);
      } catch (PropertyVetoException e) {
      }
    }
    if (getCurrentDiagrammer() != null) {
      adjustView(getCurrentDiagrammer());
    }
  }

  /**
   * Initializes the GUI.
   * 
   * @param contentPane
   *          The container of the application.
   */
  Override
  public void init(Container contentPane) {
    super.init(contentPane);

    // Create the combo box that lets the user choose a diagram.
    //
    JPanel styleSheetPanel = new JPanel(new GridBagLayout());
    JToolBar[] palettes = getPaletteToolBars();
    Container toolbarPanel = palettes[0].getParent();
    JPanel newPanel = new JPanel(new BorderLayout());
    newPanel.add(toolbarPanel, BorderLayout.CENTER);
    newPanel.add(styleSheetPanel, BorderLayout.SOUTH);
    contentPane.remove(toolbarPanel);
    contentPane.add(newPanel, BorderLayout.NORTH);

    GridBagConstraints c = new GridBagConstraints();
    c.gridy = 0;
    c.insets = new Insets(5, 5, 5, 5);
    c.weightx = 0;
    c.fill = GridBagConstraints.NONE;

    JLabel label = new JLabel(bundle.getString("ProcessModeler.ChooseStyleSheet"));
    c.gridx = 0;
    styleSheetPanel.add(label, c);

    styleSheets = readStyleSheets();

    combo = new JComboBox<URL>(styleSheets);
    combo.setRenderer(new DefaultListCellRenderer() {
      Override
      public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
          boolean cellHasFocus) {
        JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        label.setText(getProperty((URL) value, "ShortDescription"));
        return label;
      }
    });
    combo.addItemListener(new ItemListener() {
      Override
      public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
          loadStyleSheet((URL) combo.getSelectedItem());
        }
      }
    });
    c.gridx = 1;
    styleSheetPanel.add(combo, c);

    descriptionField = new JTextField();
    descriptionField.setEditable(false);
    String initialDescr = getProperty(styleSheets[0], "LongDescription");
    descriptionField.setText(initialDescr);
    c.weightx = 1;
    c.gridx = 2;
    c.fill = GridBagConstraints.HORIZONTAL;
    styleSheetPanel.add(descriptionField, c);
  }

  /**
   * Reads the list of style sheets from the property file.
   */
  private URL[] readStyleSheets() {
    List<URL> l = new ArrayList<URL>();
    try {
      URL documentBase = new URL("file:./");
      String list = bundle.getString("ProcessModeler.StyleSheetList");
      StringTokenizer tok = new StringTokenizer(list, " ,");
      while (tok.hasMoreTokens()) {
        String name = tok.nextToken();
        URL styleSheet = new URL(documentBase, "data/" + name + ".css");
        l.add(styleSheet);
      }
    } catch (Exception ex) {
      IlvDiagrammerAction.error(getApplicationContentPane(), bundle, "ProcessModeler.ErrorWhileListingStyleSheets",
          null, ex);
    }
    return l.toArray(new URL[l.size()]);
  }

  private String getProperty(URL url, String property) {
    String key = url.toExternalForm();
    key = key.substring(key.lastIndexOf('/') + 1);
    key = key.substring(0, key.lastIndexOf('.'));
    return bundle.getString("ProcessModeler." + key + "." + property);
  }

  /**
   * Loads a new style sheet.
   */
  private void loadStyleSheet(URL newStyleSheet) {
    descriptionField.setText(getProperty(newStyleSheet, "LongDescription"));

    // Change the style sheet for the other open diagrams.
    //
    IlvDiagrammer[] diagrammers = getDiagrammers();
    for (int i = 0; i < diagrammers.length; i++) {
      IlvDiagrammer d = diagrammers[i];
      try {
        d.setStyleSheet(newStyleSheet);
      } catch (Exception e) {
        IlvDiagrammerAction.error(getApplicationContentPane(), bundle, "ProcessModeler.ErrorWhileLoadingStyleSheet",
            new Object[] { newStyleSheet }, e);
      }

      // Relayout the diagram, because the new style may cause
      // nodes to overlap.
      //
      d.layoutAllNodes();
      d.layoutLinks();

      // Center the diagram nicely.
      //
      adjustView(d);

      // Update the icons in the tree.
      //
      if (getTree() != null)
        getTree().updateIcons();
    }

    // Update the palette toolbars.
    //
    JToolBar[] palettes = getPaletteToolBars();
    for (int i = 0; i < palettes.length; i++) {
      JToolBar palette = palettes[i];
      if (palette instanceof IlvDiagrammerPaletteBar) {
        try {
          ((IlvDiagrammerPaletteBar) palette).setStyleSheet(newStyleSheet);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    // Make sure new buffers use the new style sheet.
    //
    setStyleSheetURL(newStyleSheet);
  }

  /**
   * Changes the zoom factor.
   */
  Override
  protected IlvDiagrammer createDiagrammer() {
    IlvDiagrammer diagrammer = super.createDiagrammer();
    diagrammer.setZoomFactor(1.5);
    return diagrammer;
  }

  /**
   * Changes zooms and translates the view so that the diagram is best visible.
   * 
   * @param d
   *          The diagram component.
   */
  private void adjustView(IlvDiagrammer d) {
    d.resetZoom();
    d.zoomOut();

    IlvRect bbox = d.getEngine().getGrapher().computeBBox(d.getView().getTransformer());
    Dimension size = d.getView().getSize();

    double x, y;
    double margin = 10;
    if (bbox.width > size.width) {
      x = margin;
    } else {
      x = (size.width - bbox.width) / 2;
    }
    if (bbox.height > size.height) {
      y = margin;
    } else {
      y = (size.height - bbox.height) / 2;
    }
    d.getView().translate(x - bbox.x, y - bbox.y, true);
  }

  /**
   * The main method of the application. You must always supply your own main
   * when subclassing
   * {@link ilog.views.diagrammer.application.IlvDiagrammerApplication}.
   * 
   * @param args
   *          The command-line arguments.
   */
  public static void main(final String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        // Create the new modeler application and show it.
        //
        new ProcessModeler().init(args);
      }
    });
  }
}