/*
 * 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 shared.swing;

import ilog.views.util.styling.IlvStylable;
import ilog.views.util.swing.IlvSwingUtil;
import shared.AbstractExample;
import shared.Util;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;


/**
 * <code>CSSComboBox</code> is a Swing combination box that allows the user to
 * select a style sheet for a stylable chart.
 */
public class CSSComboBox extends JComboBox<String> {

  /**
   * The stylable chart.
   */
  private IlvStylable chart;

  /**
   * The example that this combination box is associated with.
   */
  private AbstractExample example;

  /**
   * The name of the data directory containing the CSS files.
   */
  private String dataDirectory;

  /**
   * The list of sample CSS file names to use when the example is running as an
   * applet. The files do not specify any path or extension. The files are
   * assumed to be located in <code>dataDirectory</code> and have an extension
   * of ".css".
   */
  private String[] appletCSSFiles;

  /**
   * The list of CSS file names displayed by the combination box. The files do
   * not specify any path and are assumed to be located in
   * <code>dataDirectory</code>.
   * The first element of the list is special and is used to indicate that
   * styling should be disabled.
   */
  private List<String> cssFileNames;

  /**
   * The list of URLs for each CSS file displayed by the combination box. This list
   * parallels the <code>cssFileNames</code> list. The value of the first
   * element is <code>null</code> and is used to indicate that styling should be
   * disabled.
   */
  private List<URL> cssFileURLs;

  /**
   * Creates a new <code>CSSComboBox</code> for the specified example.
   *
   * @param example The example that the combination box is associated with.
   * @param chart The chart.
   * @param dataDirectory The name of the data directory containing the CSS
   * files.
   * @param appletCSSFiles The list of sample CSS file names to use when the
   * example is running as an applet. The files should be specified without any
   * path or extension. The files are assumed to be located in
   * <code>dataDirectory</code> and have an extension of ".css".
   */
  public CSSComboBox(AbstractExample example,
                     IlvStylable chart,
                     String dataDirectory,
                     String[] appletCSSFiles) {
    this.chart = chart;
    this.example = example;
    this.dataDirectory = dataDirectory;
    this.appletCSSFiles = appletCSSFiles;

    // Compute the list of available CSS files and their URLs. Then prepend the
    // special item at index 0 to disable styling.
    cssFileNames = new ArrayList<String>();
    cssFileURLs = new ArrayList<URL>();
    getCSSFiles(cssFileNames, cssFileURLs);
    cssFileNames.add(0, "Default Style");
    cssFileURLs.add(0, null);

    // Set the list of CSS file names as the model of the combination box.
    setModel(new DefaultComboBoxModel<String>(cssFileNames.toArray(new String[cssFileNames.size()])));

    // Add the listener that will set the style sheet on the chart when a
    // CSS file is selected in the combination box.
    addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent evt) {
        int idx = getSelectedIndex();
        try {
          if (idx <= 0) {
            getChart().setStyleSheets(null);
          } else {
            URL cssURL = (URL) cssFileURLs.get(idx);
            getChart().setStyleSheets(0, cssURL.toString());
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });

    // Initially select that styling is disabled.
    setSelectedIndex(0);
  }

  /**
   * Returns the chart.
   *
   * @return The chart.
   */
  protected IlvStylable getChart() {
    return chart;
  }

  /**
   * Computes the list of available CSS files and their corresponding URLs.
   */
  private void getCSSFiles(List<String> files, List<URL> urls) {
    // In an application context, first list all CSS files in the data directory.

    File[] css = Util.listDirectory(dataDirectory, "css");
    for (int i = 0; i < css.length; i++) {
      String fileName = css[i].getName();
      try {
        URL url = getDataFileURL(fileName);
        files.add(fileName);
        urls.add(url);
      } catch (IOException ex) {
        // Theoretically, there should be no problem accessing the URL of a file that
        // we just listed from the data directory. So, we ignore any such problem files.
      }
    }
    

    // Then add any CSS files that might be bundled into the applet or application jar.
    // If a jar'd file duplicates one from the external file system, the external file
    // takes precedence.
    for (int i = 0; i < appletCSSFiles.length; i++) {
      String fileName = appletCSSFiles[i] + ".css";
      if (!files.contains(fileName)) {
        try {
          URL url = getDataFileURL(fileName);
          files.add(fileName);
          urls.add(url);
        } catch (IOException ex) {
          // In an applet context, the list of applet files is required.
            IlvSwingUtil.showErrorDialog(this, ex);
        }
      }
    }
  }

  /**
   * Returns the URL of the specified data file.
   */
  private URL getDataFileURL(String fileName)
      throws IOException {
    String file = dataDirectory + File.separator + fileName;
    return example.getResourceURL(file);
  }

}