/*
 * 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.
 */

package service;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;

import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;

import ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.application.IlvDiagrammerAction;
import ilog.views.diagrammer.application.IlvDiagrammerAction.StatusEvent;
import ilog.views.diagrammer.application.IlvDiagrammerAction.StatusListener;
import ilog.views.diagrammer.application.IlvDiagrammerFrame;
import ilog.views.sdm.IlvSDMEngine;
import ilog.views.sdm.IlvSDMException;
import ilog.views.util.IlvProductUtil;

/**
 * A diagrammer demo that shows how to create the model through API.
 * 
 * @since JViews 8.1
 */

public class ServiceMonitoringGUI extends IlvDiagrammerFrame {

  private static URL VERTICAL_STYLE_SHEET;
  private static URL HORIZONTAL_STYLE_SHEET;
  private static URL RADIAL_STYLE_SHEET;

  /**
   * Entry point.
   * 
   * @param args
   */
  // entry point
  public static void main(final String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        new ServiceMonitoringGUI().init(args);
      }
    });
  }

  /**
   * Constructor
   */
  public ServiceMonitoringGUI() {
    super(new String[] { "-simple" });

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

  /**
   * Initialize the main panel
   */
  Override
  public void init(Container panel) {

    // set style sheet urls
    try {
      VERTICAL_STYLE_SHEET = new URL(getBaseURL(), "data/service.css");
      HORIZONTAL_STYLE_SHEET = new URL(getBaseURL(), "data/service-horizontal.css");
      RADIAL_STYLE_SHEET = new URL(getBaseURL(), "data/service-radial.css");
    } catch (MalformedURLException ex) {
      ex.printStackTrace();
    }

    // Set up the panel.
    //
    super.init(panel);

    // Create the IlvDiagrammer instance.
    //
    final IlvDiagrammer diagrammer = getCurrentDiagrammer();
    // set title
    JFrame frame = (JFrame) SwingUtilities.getAncestorOfClass(JFrame.class, diagrammer);
    if (frame != null) {
      frame.setTitle("Creating Diagrams using the SDK");
    }

    // Allow selection.
    diagrammer.setSelectMode(true);
    // Allow scrolling.
    diagrammer.setScrollable(true);

    // Add a toolbar for controlling the view
    //
    panel.add(makeControlPanel(diagrammer.getEngine()), BorderLayout.EAST);

    try {
      // Load style definition
      diagrammer.setStyleSheet(VERTICAL_STYLE_SHEET);

      // Populate data model and load it into diagrammer engine
      diagrammer.getEngine().setModel(ServiceMonitoringModel.makeModel());

      // add metadata to store x,y position, but not in original model
      diagrammer.getEngine().setMetadataEnabled(true);
      diagrammer.getEngine().updateNodePositions();

      // disable editing, but allow node to move after a layout has been
      // performed
      diagrammer.getSelectInteractor().setMoveAllowed(true);
      diagrammer.getEngine().loadData();
    } catch (Exception e) {
      e.printStackTrace();
    }
    // disable layout, to allow moving nodes interactively
    diagrammer.getEngine().setNodeLayoutEnabled(false);

    // be sure that 'refresh' button doesn't enable again the layout
    IlvDiagrammerAction.addStatusListener(new StatusListener() {
      Override
      public void actionFinished(StatusEvent event) {
        diagrammer.getEngine().setNodeLayoutEnabled(false);
      }

      Override
      public void actionDescribed(StatusEvent event) {
      }

      Override
      public void actionStarted(StatusEvent event) {
      }
    });
  }

  /**
   * Creates the panel with all controls.
   * 
   * @return a JPanel
   */
  private JComponent makeControlPanel(final IlvSDMEngine engine) {
    Box box = Box.createVerticalBox();

    // level of detail controls
    box.add(new JLabel("Level of Detail"));
    ActionListener lodListener = new ActionListener() {
      Override
      public void actionPerformed(final ActionEvent e) {
        restoreSelection(engine, new Runnable() {
          Override
          public void run() {
            // set new detail level
            engine.setDetailLevel(e.getActionCommand());
            engine.loadData();
          }
        });
      }
    };
    ButtonGroup bg = new ButtonGroup();
    // make 3 radio buttons for level of details
    JRadioButton high = new JRadioButton("High");
    high.setActionCommand(IlvSDMEngine.HIGH_DETAIL_LEVEL);
    high.setSelected(true);
    high.addActionListener(lodListener);
    bg.add(high);
    box.add(high);
    JRadioButton medium = new JRadioButton("Medium");
    medium.setActionCommand(IlvSDMEngine.MEDIUM_DETAIL_LEVEL);
    medium.addActionListener(lodListener);
    bg.add(medium);
    box.add(medium);
    JRadioButton low = new JRadioButton("Low");
    low.setActionCommand(IlvSDMEngine.LOW_DETAIL_LEVEL);
    low.addActionListener(lodListener);
    bg.add(low);
    box.add(low);

    // graph layout options
    box.add(Box.createVerticalStrut(10));
    box.add(new JLabel("Graph Layout"));
    ActionListener glListener = new ActionListener() {
      Override
      public void actionPerformed(final ActionEvent e) {
        restoreSelection(engine, new Runnable() {
          Override
          public void run() {
            String css = null;
            if (e.getActionCommand().equals("Horizontal")) {
              // we could also load a brand new css, but here we choose to
              // illustrate
              // the cascading with a css that contain an overriding rule.
              css = HORIZONTAL_STYLE_SHEET.toString();
            } else if (e.getActionCommand().equals("Radial")) {
              css = RADIAL_STYLE_SHEET.toString();
            } else {
              css = VERTICAL_STYLE_SHEET.toString();
            }

            // validate the new layout direction, i.e. the new style sheet.
            try {
              // will reset all renderers as well, including graph layout
              engine.setStyleSheets(0, css, true);
              // force node layout
              engine.performNodeLayout();
              engine.setNodeLayoutEnabled(false);
              // adapt view
              getDiagrammers()[0].fitToContents();
            } catch (IlvSDMException ex) {
              ex.printStackTrace();
            }
          }
        });
      }
    };
    bg = new ButtonGroup();
    // make 3 radio buttons for graph layout
    JRadioButton vert = new JRadioButton("Vertical");
    vert.setActionCommand("Vertical");
    vert.setSelected(true);
    vert.addActionListener(glListener);
    bg.add(vert);
    box.add(vert);

    JRadioButton horiz = new JRadioButton("Horizontal");
    horiz.setActionCommand("Horizontal");
    horiz.addActionListener(glListener);
    bg.add(horiz);
    box.add(horiz);

    JRadioButton radial = new JRadioButton("Fixed length");
    radial.setActionCommand("Radial");
    radial.addActionListener(glListener);
    bg.add(radial);
    box.add(radial);

    return box;
  }

  /**
   * Runs a runnable preserving sdm selection. The runnable is supposed to reset
   * selection (e.g. call to engine.loadData())
   * 
   * @param engine
   *          the sdm engine
   * @param r
   *          the runnable to call
   */
  static private void restoreSelection(IlvSDMEngine engine, Runnable r) {
    engine.setAdjusting(true);
    Enumeration<?> e = engine.getSelectedObjects();
    try {
      r.run();
    } finally {
      // restore selected objects
      while (e.hasMoreElements()) {
        engine.setSelected(e.nextElement(), true);
      }
      engine.setAdjusting(false);
    }
  }
}