/*
 * 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.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;

import ilog.views.IlvGraphic;
import ilog.views.IlvHandlesSelection;
import ilog.views.IlvManager;
import ilog.views.IlvManagerView;
import ilog.views.IlvPoint;
import ilog.views.IlvTransformer;
import ilog.views.graphic.IlvText;
import ilog.views.interactor.IlvSelectInteractor;
import ilog.views.interactor.IlvZoomViewInteractor;
import ilog.views.swing.IlvJManagerViewControlBar;
import ilog.views.swing.IlvJScrollManagerView;

/**
 * This is a very simple application allows to compare the memory
 * consumption between an <code>IlvText</code> object and a special
 * lightweight text object that contains fewer parameters. The same
 * mechanism can be applied to other <code>IlvGraphic</code> classes
 * as well. This is a general implementation technique that can be used
 * to reduce the memory consumption of an application.
 * It shows a manager view and allows to switch between memory-heavy
 * <code>IlvText</code> and lightweight <code>LightText</code>.
 * A realtime memory chart display shows how the memory changes over time.
 */
SuppressWarnings("serial")
public class LightTextApp extends JRootPane
{
  IlvManager manager;
  Color[] colors;
  boolean lightText = false;

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

  /**
   * Initializes the application.
   */
  public void init()
  {
    // initialize the colors
    colors = new Color[7];
    colors[0] = Color.yellow;
    colors[1] = Color.cyan;
    colors[2] = Color.pink;
    colors[3] = Color.green;
    colors[4] = Color.lightGray;
    colors[5] = new Color(221,255,128);
    colors[6] = new Color(255,222,128);

    // create a manager
    manager = new IlvManager();

    // create a manager view
    IlvManagerView mgrview = new IlvManagerView(manager);

    // create the scroll manager view 
    IlvJScrollManagerView scrollManView = new IlvJScrollManagerView(mgrview);

    // Some settings on the manager view and on the scroll manager view
    mgrview.setAntialiasing(true);
    mgrview.setKeepingAspectRatio(true);
    mgrview.setBackground(Color.white);
    mgrview.setForeground(SystemColor.windowText);   
    Color xc = SystemColor.windowText;
    xc = new Color(255-xc.getRed(), 255-xc.getGreen(), 255-xc.getBlue());
    mgrview.setDefaultXORColor(xc);
    mgrview.setDefaultGhostColor(SystemColor.windowText);
    mgrview.setZoomFactorRange(0.02, 10.0);

    // Settings parameters for selection handles
    IlvHandlesSelection.defaultHandleColor = Color.red;
    IlvHandlesSelection.defaultHandleBackgroundColor = Color.red;
    IlvHandlesSelection.defaultHandleShape = IlvHandlesSelection.SQUARE_SHAPE;

    // Now, fill the manager
    fillManager(lightText);

    // create the standard control bar
    IlvJManagerViewControlBar controlBar = new IlvJManagerViewControlBar();
    controlBar.setView(mgrview);

    // modify the interactors such that the demo looks better
    ((IlvSelectInteractor)controlBar.getSelectInteractor()).setOpaqueMove(true);    ((IlvZoomViewInteractor)controlBar.getZoomViewInteractor()).setPermanent(true);

    // set the initial interactor
    mgrview.setInteractor(controlBar.getSelectInteractor());

    // create a checkbox that allows to enable/disable the light text
    JCheckBox useLightText = new JCheckBox("Lightweight Text", false);
    useLightText.setToolTipText(
        "Enable or disable the use of light text objects");
    useLightText.addItemListener(new ItemListener() {
      Override
      public void itemStateChanged(ItemEvent e) {
        boolean old = lightText;
        if (e.getStateChange() == ItemEvent.SELECTED)
          lightText = true;
        else if (e.getStateChange() == ItemEvent.DESELECTED)
          lightText = false;
        if (old != lightText)
          fillManager(lightText);
      }
    });

    // create the top panel with the toolbar and the pop-up checkbox
    JPanel topPanel = new JPanel();
    topPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    topPanel.add(controlBar);
    topPanel.add(new JLabel("   "));
    topPanel.add(useLightText);

    JPanel aux = new JPanel(new GridLayout(2,1));
    JLabel label = new JLabel("0");
    aux.add(new JLabel("Memory Usage:  "));
    aux.add(label);

    JPanel bottomPanel = new JPanel(new BorderLayout(2, 2));
    bottomPanel.add(aux, BorderLayout.WEST);
    bottomPanel.add(new MemoryHistory(label), BorderLayout.CENTER); 

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

    mgrview.setDoubleBuffering(true);
    mgrview.setTransformer(new IlvTransformer(1.5, 0, 0, 1.2, 0, 0));
  }

  /**
   * Fills the manager.
   */
  private void fillManager(boolean useLightText)
  {
    IlvGraphic g;
    manager.setContentsAdjusting(true);
    try {
      manager.deleteAll(true);
      int count = 0;
      for (int i = 0; i < 100; i++) {
        for (int j = 0; j < 100; j++) {
          IlvPoint p = new IlvPoint(10 + i * 80, 10 + j * 50);
          String label =  "Text " + j + " " + i;
          if (useLightText) {
            LightText text = new LightText(p, label);
            setNodeAttributes(text, count++);
            text.move(p.x, p.y);
            g = text;
          } else { 
            IlvText text = new IlvText(p, label);
            setNodeAttributes(text, count++);
            text.move(p.x, p.y);
            g = text;
          }
          manager.addObject(g, true);
        }
      }
    } finally {
      manager.setContentsAdjusting(false);
    }
  }

  /**
   * Sets the attributes of a node.
   */
  private void setNodeAttributes(IlvText node, int count)
  {
    node.setAntialiasing(true);
    node.setFillOn(true);
    node.setStrokeOn(true);
    node.setLeftMargin(6);
    node.setRightMargin(6);
    node.setTopMargin(3);
    node.setBottomMargin(3);
    node.setForeground(Color.blue);
    node.setFillPaint(colors[count % 7]);
  }

  /**
   * Sets the attributes of a node.
   */
  private void setNodeAttributes(LightText node, int count)
  {
    node.setUpdating(true);
    node.setAntialiasing(true);
    node.setFillOn(true);
    node.setStrokeOn(true);
    node.setLeftMargin(6);
    node.setRightMargin(6);
    node.setTopMargin(3);
    node.setBottomMargin(3);
    node.setForeground(Color.blue);
    node.setFillPaint(colors[count % 7]);
    node.setUpdating(false);
  }

  /**
   * Allows you to run the demo as a standalone application.
   */
  public static void main(String[] arg)
  {
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    SwingUtilities.invokeLater(
      new Runnable() {
        Override
        public void run() {
          LightTextApp app = new LightTextApp();
          app.init();

          JFrame frame = new JFrame("Lightweight Text Example");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(500, 500);
          frame.getContentPane().add(app);
          frame.setVisible(true);
        }
      });
  }

  /**
   * The memory history panel.
   * This displays the currently used memory.
   * It updates the display every second.
   */
  class MemoryHistory extends JPanel implements ActionListener
  {
    long maxMem = 32000;
    long[] memSteps = null;
    JLabel label;

    /**
     * Constructor.
     */
    MemoryHistory(JLabel label)
    {
      this.label = label;
      new javax.swing.Timer(1000, this).start();
    }

    /**
     * Called by the timer every second. Calculates the newly used memory.
     */
    Override
    public void actionPerformed(ActionEvent evt)
    {
      Runtime rt = Runtime.getRuntime();
      rt.gc();
      long used = rt.totalMemory() - rt.freeMemory();
      addEntry(used);
      if (label != null) {
        long kb = used / 1024;
        label.setText("" + kb + " KB");
      }
      repaint();
    }

    /**
     * Paints this memory history panel.
     */
    Override
    public void paint(Graphics g) {
      super.paint(g);
      int w = getWidth();
      int h = getHeight();
      g.setColor(Color.black);
      g.fillRect(0, 0, w, h);
      g.setColor(Color.green);
      for (int i = 0; i < w; i += 15)
        g.drawLine(i, 0, i, h);
      for (int i = 0; i < h; i += 15)
        g.drawLine(0, i, w, i);
      g.setColor(Color.yellow);
      float f = (float)h / (float)maxMem;
      for (int i = 1; i < memSteps.length; i++) {
        g.drawLine(w-1-i, h - (int)(memSteps[i-1] * f) ,w-2-i, h - (int)(memSteps[i] * f));
      }
      g.setColor(Color.lightGray);
      g.drawRect(0,0,w,h);
      g.drawRect(1,1,w-2,h-2);
      g.drawRect(0,0,w-2,h-2);
    }

    /**
     * Add an entry to the memory history.
     */
    private void addEntry(long val)
    {
      if (memSteps == null || memSteps.length == 0) return;
      int n = memSteps.length;
      if (n > 1)
        System.arraycopy(memSteps, 0, memSteps, 1, n-1);
      memSteps[0] = val;
      if (val > maxMem) maxMem = 3 * val / 2;
    }

    /**
     * Changes the bounds of this panel.
     */
    Override
    public void setBounds(int x, int y, int w, int h)
    {
      long[] old = memSteps;
      memSteps = new long[w];
      if (old != null) {
        int n = Math.min(old.length, memSteps.length);
        System.arraycopy(old, 0, memSteps, 0, n);
      }
      super.setBounds(x, y, w, h);
    }

    /**
     * Returns the preferred size.
     */
    Override
    public Dimension getPreferredSize() {
      return new Dimension(60,60);
    }

    /**
     * Returns the minimum size.
     */
    Override
    public Dimension getMinimumSize() {
      return new Dimension(60,60);
    }
  }
}