/*
 * 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.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import ilog.views.dashboard.IlvDashboardDiagram;
import ilog.views.dashboard.IlvDashboardSymbol;
import ilog.views.dashboard.IlvDashboardSymbol.Parameter;
import ilog.views.sdm.IlvSDMModel;
import ilog.views.util.swing.IlvSwingUtil;

/**
 * The supervisor is associated to a dashboard. It will introspect it in order
 * to get the parameters to update, and it will periodically request values for
 * those parameters to the simulator
 */
public class Supervisor {

  // the time for periodic updates.
  private Timer timer = null;

  // storage for the parameters to update and to request to simulator
  private Hashtable<String, Vector<String>> mapping = null;

  // the dashboard associated with this supervisor
  private IlvDashboardDiagram dashboard = null;
//  private String name;

  // the simulator to request values
  private Simulator simulator = null;

  /**
   * Creates the supervisor for the specified dashboard. It will update data in
   * this dashboard according to the specified period. Values will be asked to
   * the given simulator
   */
  public Supervisor(String name, IlvDashboardDiagram dashboard, int period, Simulator simulator) {
//    this.name = name;
    this.dashboard = dashboard;
    this.simulator = simulator;
    mapping = new Hashtable<String, Vector<String>>();

    // get parameters from the dashboard in order to update/request them later
    extractParameters();

    // creates a task to update the model periodically
    TimerTask task = new TimerTask() {
      Override
      public void run() {
        IlvSwingUtil.invokeAndWait(new Runnable() {
          Override
          public void run() {
            updateModel();
          }
        });

      }
    };
    // creates the timer that will perform the task. It will start in 2s
    timer = new Timer();
    timer.schedule(task, 2000, period);
  }

  /**
   * Extract the mapped symbol parameters from the dashboard and store them in
   * order to be able to request their value to the simulator and to update the
   * model later
   */
  private void extractParameters() {
    // go through all symbols of the dashboard
    // IlvDashboardSymbolIterator symbols = dashboard.getSymbols();
    Iterator<IlvDashboardSymbol> symbols = dashboard.iterator();
    while (symbols.hasNext()) {
      IlvDashboardSymbol symbol = symbols.next();

      // go through parameters of the symbol
      int count = symbol.getParameterCount();
      if (count > 0) {
        int mapped = 0;
        Vector<String> params = new Vector<String>(); // create a list for the mapped parameters
        for (int i = 0; i < count; i++) {
          Parameter param = symbol.getParameter(i);

          // if parameter is mapped then add the mapping name into list
          if (param.isMapped()) {
            mapped++;
            params.add(symbol.getParameterMapping(param));
          }
        }

        // associated the list to the symbol
        if (mapped > 0) {
          mapping.put(symbol.getID(), params);
        }
      }
    }
  }

  /**
   * Update the model with new parameter's values. Value are asked to the
   * simulator
   */
  private void updateModel() {

    IlvSDMModel model = dashboard.getView().getModel();

    // go throught the list of symbols which have mapped parameters
    for (Enumeration<String> e = mapping.keys(); e.hasMoreElements();) {
      String symbolID = (String) e.nextElement();
      // get the mapped parameters of the symbol
      Vector<String> params = mapping.get(symbolID);
      if (params != null) {

        Object symbol = model.getObject(symbolID);

        // for each mapped parameters we ask a value to the simulator
        // and we update the model with this new value
        for (int i = 0; i < params.size(); i++) {
          String mapName = (String) params.get(i); // get the name of the param
          Object value = simulator.getValue(mapName); // request the value for
                                                      // this param
          if (value != null) {
            model.setObjectProperty(symbol, mapName, value); // update the model
          }

        }
      }
    }

  }

}