/*
 * 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.Container;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import ilog.views.chart.IlvChart;
import ilog.views.chart.IlvColor;
import ilog.views.chart.IlvStyle;
import ilog.views.chart.data.IlvCyclicDataSet;
import ilog.views.chart.renderer.IlvSingleChartRenderer;
import ilog.views.chart.renderer.IlvSinglePolylineRenderer;
import ilog.views.util.IlvProductUtil;

/**
 * An example showing the capabilities of the Charts library for handling
 * fixed-size storage.
 */
public class FixedSizeStorage extends JFrame {
  /** The number of charts. */
  // the default sizes of various windows
//  private static final int MAIN_WINDOW_DEFAULT_WIDTH = 550;
//  private static final int MAIN_WINDOW_DEFAULT_HEIGHT = 500;

  /** Number of visible points. */
  private static final int VISI_COUNT = 70;

  /** Number of points added during each update. */
  private static final int UPDATE_COUNT = 2;

  /** The data sets. */
  private IlvCyclicDataSet inputData;
  /** The Chart */
  private IlvChart chart;

  private int counter = 0;

  public FixedSizeStorage() {
    super("Real-time Updates With Fixed Size Storage");
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    init();
  }

  /**
   * Initializes the example's user interface in the specified container.
   */
  public void init() {
    Container container = getContentPane();

    // Create the data sets. The data sets containing the random values are
    // instances of IlvCyclicDataSet with a buffer size equal to VISI_COUNT and
    // no x values storage.
    inputData = new IlvCyclicDataSet("Input", VISI_COUNT, IlvCyclicDataSet.ROTATE_MODE, false);
    chart = createChart();
    IlvSingleChartRenderer r = createRenderer(chart);
    chart.addRenderer(r, inputData);
    container.add(chart, BorderLayout.CENTER);
    setSize(450, 380);
    // The timer that adds new data point
    Timer timer = new Timer(1000 / 25, new ActionListener() {
      Override
      public void actionPerformed(ActionEvent evt) {
        FixedSizeStorage.this.addData();
      }
    });
    timer.start();
  }

  /**
   * Creates a chart monitor.
   */
  protected IlvChart createChart() {
    // Create a new Cartesian chart with no default scales & grids.
    final IlvChart chart = new IlvChart(IlvChart.CARTESIAN, false);

    // Configure the x and y axes.
    chart.getXAxis().setAutoDataRange(false);
    chart.getXAxis().setVisibleRange(0, VISI_COUNT - 1);
    chart.getYAxis(0).setDataRange(-8, 8);
    // Enable automatic scrolling as new data comes in outside the visible
    // range.
    chart.setShiftScroll(true);

    // Customize the chart appeareance.
    chart.setForeground(Color.black);
    chart.setFont(new Font("Dialog", Font.PLAIN, 10));
    chart.getChartArea().setPlotStyle(new IlvStyle(Color.black, IlvColor.darkSlateGray));

    JLabel label = new JLabel("Monitor - # Visible Points: " + VISI_COUNT + " - # Added Points: " + UPDATE_COUNT,
        JLabel.LEFT);
    label.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 0));
    label.setForeground(Color.white);
    chart.setHeader(label);

    return chart;
  }

  /**
   * Creates an instance of the current selected renderer type.
   */
  private IlvSingleChartRenderer createRenderer(IlvChart chart) {
    return new IlvSinglePolylineRenderer();
  }

  /**
   * Invoked by the background timer to add new data points.
   */
  void addData() {
    inputData.startBatch();
    for (int j = 0; j < UPDATE_COUNT; ++j) {
      inputData.addData(0, RandomGenerator.rand(counter));
      ++counter;
    }
    inputData.endBatch();
  }

  /**
   * Application mainline.
   */
  public static void main(String[] args) {
    // This sample uses JViews Charts features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Charts Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Charts_Deployment);

    SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        FixedSizeStorage frame = new FixedSizeStorage();
        frame.setVisible(true);
      }
    });
  }

  // --------------------------------------------------------------------------

  /**
   * Generates a random number sequence
   */
  private static class RandomGenerator {
    static Random random = new Random();
    static double randHold;

    static double rand(long counter) {
      if (random.nextDouble() < 0.2)
        randHold = random.nextGaussian() + 1;
      return 6. * Math.cos(0.013 * counter + randHold * Math.sin(0.026 * counter * randHold));
    }
  }
}