/*
 * 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 demo.dashboard;

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import ilog.views.dashboard.IlvDashboardContext;
import ilog.views.dashboard.IlvDashboardDiagram;
import ilog.views.diagrammer.IlvDiagrammerException;
import ilog.views.sdm.IlvSDMView;

/**
 * This class defines the logic of the JViews Diagrammer Faces Dashboard sample.
 */
public class DashboardBean {

  public IlvDashboardDiagram getDashboard() throws MalformedURLException, IOException, IlvDiagrammerException {
    ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
    Map<String, Object> appMap = ctx.getApplicationMap();
    BAMCockpit cockpit = (BAMCockpit) appMap.get("BAMCockpit");

    IlvDashboardDiagram dashboard;
    if (cockpit == null) {
      dashboard = new IlvDashboardDiagram(new IlvDashboardContext(), new IlvSDMView());
      dashboard.readDashboard(ctx.getResource("/data/bam.idbd"));
      cockpit = new BAMCockpit(dashboard);
      appMap.put("BAMCockpit", cockpit);
      cockpit.start();
    } else
      dashboard = cockpit.getDashboard();
    return dashboard;
  }

  private static class BAMCockpit implements Runnable {

    // delay between refreshes, in ms
    public long ANIM_DELAY = 3000l;
    // max variation at each refresh
    public double DELTA = 10d;
    // visitor array, each entry between 0 and 100
    public double[] visitors = { 10d, 20d, 30d, 20d };

    private IlvDashboardDiagram dashboard;

    private Thread thread;

    private boolean stopped = true;

    /**
     * @param dashboard
     *          the diagram to animate
     */
    public BAMCockpit(IlvDashboardDiagram dashboard) {
      this.dashboard = dashboard;
    }

    public void start() {
      if (stopped) {
        stopped = false;
        thread = new Thread(this);
        thread.start();
      }
    }

    SuppressWarnings("unused")
    public void stop() {
      stopped = true;
    }

    // called by the thread
    Override
    public void run() {
      while (true && !stopped) {
        changeRandomValues();
        updateDashBoard();
        try {
          Thread.sleep(ANIM_DELAY);
        } catch (InterruptedException ex) {
        }
      }
    }

    public IlvDashboardDiagram getDashboard() {
      return dashboard;
    }

    /**
     * Animates the dashboard by changing some values
     */
    private void changeRandomValues() {
      for (int i = 0; i < 4; i++) {
        double delta = DELTA * (Math.random() - .5d);
        visitors[i] += delta;
        // bound changes
        if (visitors[i] < 0)
          visitors[i] -= delta * 2d;
        if (visitors[i] > 100)
          visitors[i] -= delta * 2d;
      }
    }

    // update the dashboard symbols
    private void updateDashBoard() {
      dashboard.setAdjusting(true);

      // update the 4 bar charts
      Object v = dashboard.getObject("visitors");
      double totalVisitors = 0d;
      for (int i = 0; i < 4; i++) {
        dashboard.setObjectProperty(v, "value" + (i + 1), Double.valueOf(visitors[i]));
        totalVisitors += visitors[i];
      }

      // update total gauge
      Object yty1 = dashboard.getObject("yty_visitors");
      // normalize value
      int total = (int) (totalVisitors / 40d * 1000d);
      dashboard.setObjectProperty(yty1, "value", Double.valueOf(total / 1000d));
      dashboard.setObjectProperty(yty1, "preset", Double.valueOf((Math.random() - 0.5) + total / 1000d));

      // update funnel1
      Object f1 = dashboard.getObject("website");
      total = (int) totalVisitors * 550;
      dashboard.setObjectProperty(f1, "value1", Integer.valueOf(total));
      dashboard.setObjectProperty(f1, "value2", Integer.valueOf(total / 4));
      dashboard.setObjectProperty(f1, "value3", Integer.valueOf(total / 5));
      dashboard.setObjectProperty(f1, "value4", Integer.valueOf(total / 50));

      // update opportunities
      Object o1 = dashboard.getObject("opportunities");
      total = (int) totalVisitors;
      dashboard.setObjectProperty(o1, "value1", Integer.valueOf(total));
      dashboard.setObjectProperty(o1, "value2", Integer.valueOf(total / 4));
      dashboard.setObjectProperty(o1, "value3", Integer.valueOf(total / 5));
      dashboard.setObjectProperty(o1, "value4", Integer.valueOf(total / 50));

      // update opportunity gauge
      Object yty2 = dashboard.getObject("yty_business");
      // normalize value
      Object old = dashboard.getObjectProperty(yty2, "value");
      int val = ((Number) old).intValue();
      // add last opportunities
      val = (val + total / 50) % 500;
      dashboard.setObjectProperty(yty2, "value", Integer.valueOf(val));
      dashboard.setObjectProperty(yty2, "preset", Double.valueOf((Math.random() - 0.5) * 20 + val));

      // update the pie chart
      Object revenues = dashboard.getObject("revenues");
      double rev_value = Math.random() * 1000;
      dashboard.setObjectProperty(revenues, "USA", Double.valueOf(rev_value * 3 + Math.random() * 50));
      dashboard.setObjectProperty(revenues, "Europe", Double.valueOf(rev_value * 2 + Math.random() * 50));
      dashboard.setObjectProperty(revenues, "APAC", Double.valueOf(rev_value * 1 + Math.random() * 50));
      dashboard.setObjectProperty(revenues, "ROW", Double.valueOf(rev_value * 1 + Math.random() * 50));

      dashboard.setAdjusting(false);
    }
  }
}