/*
 * 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 ilog.views.gantt.IlvGanttChart;
import ilog.views.gantt.action.IlvZoomToFitAction;
import ilog.views.gantt.project.IlvGanttProjectConfiguration;
import ilog.views.gantt.project.IlvGanttXMLDataSource;
import ilog.views.util.IlvProductUtil;
import ilog.views.util.styling.IlvStylingException;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


/**
 * Extend Project sample.
 * This sample code shows how to change the Gantt data source using the
 * project configuration built with the Gantt Designer.
 */
public class ExtendProject extends JPanel {

  public IlvGanttChart chart;

  // The project configuration file obtained using the Gantt Designer.
  static final String projectURL = "data/basic.igpr";

  // The complex XML data we want to use instead of the basic one
  static final String complexXML = "data/complexGantt.xml";

  // The zoom-to-fit action.
  private IlvZoomToFitAction zoomToFitAction;

  public ExtendProject(JFrame frame) {
    final JFrame parent = frame;

    // Prepare the JPanel's appearance
    setLayout(new BorderLayout());
    JPanel panel = new JPanel();

    chart = new IlvGanttChart();
    try {
      // Set initially the sample project
      chart.setProject(getResourceURL(projectURL));
    } catch (IOException e1) {
      JOptionPane.showMessageDialog(parent,
                                    e1,
                                    "Error",
                                    JOptionPane.ERROR_MESSAGE);
    } catch (IlvStylingException e1) {
      JOptionPane.showMessageDialog(parent,
                                    e1,
                                    "Error",
                                    JOptionPane.ERROR_MESSAGE);
    }

    // A button to change the data of the project.
    Button buttonGantt = new Button("Change to more complex data");
    buttonGantt.addActionListener(new ActionListener()
    {
      Override
      public void actionPerformed(ActionEvent e) {
        // Let's take the project configuration to change the data
        // of the project.
        IlvGanttProjectConfiguration configuration =
          new IlvGanttProjectConfiguration();
        try {
          // Read the configuration file.
          URL url = getResourceURL(projectURL);
          configuration.read(url);
          // The project configuration contains now the styling, the reference
          // to the data source and the Gantt model from this data source.

          // In order to change the data source of this configuration,
          // we need to:
          // 1. Change the data source of this configuration.
          // 2. Create the data model from this data source, and put it
          //    into the configuration.
          // 3. Apply this new configuration to the Gantt

          // 1. Change the data source by referencing a new XML file
          IlvGanttXMLDataSource dataSource = new IlvGanttXMLDataSource();
          dataSource.setDataURL(getResourceURL(complexXML));
          configuration.setDataSource(dataSource);
          try {
            // 2. Update the Gantt model of the configuration associated to
            //    this data source.
            dataSource.read(configuration.getGanttModel());
          } catch (Exception e1) {
            e1.printStackTrace();
          }

          // 3. Apply the new configuration to the chart.
          configuration.apply(chart);

        } catch (MalformedURLException ex) {
          // cannot happen except if URL is changed
          JOptionPane.showMessageDialog(parent,
                                        ex,
                                        "Error",
                                        JOptionPane.ERROR_MESSAGE);
        } catch (IlvStylingException ex) {
          JOptionPane.showMessageDialog(parent,
                                        ex,
                                        "Error",
                                        JOptionPane.ERROR_MESSAGE);
        } catch (IOException ex) {
          JOptionPane.showMessageDialog(parent,
                                        ex,
                                        "Error",
                                        JOptionPane.ERROR_MESSAGE);
        }
        chart.revalidate();
        // Make sure the full chart is visible.
        zoomToFit();
        chart.expandAllRows();
      }
    });
    panel.add(buttonGantt);

    add(BorderLayout.CENTER, chart);
    chart.revalidate();
    zoomToFitAction = new IlvZoomToFitAction(chart, "", null, null, "", "");
    zoomToFit();
    // Make sure the full chart is visible.
    chart.expandAllRows();
    add(BorderLayout.SOUTH, panel);
  }

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

    SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBounds(10, 400, 700, 400);
        ExtendProject example = new ExtendProject(frame);
        frame.getContentPane().add(example);
        frame.setVisible(true);
      }
    });
  }


  // =========================================
  // Accessing Resources
  // =========================================

  /**
   * Returns the fully qualified URL of a resource file that is specified
   * relative to the working directory of the example. Note that this is
   * different than calling <code>Class.getResource()</code>, which performs
   * resource lookup relative to the example's classpath.
   *
   * @param relativePath The path of the resource file, relative to the working
   *                     directory of the example.
   * @return The resource URL.
   *
   * @throws IOException if the path cannot be resolved to a valid and existing
   *                     URL.
   */
  public URL getResourceURL(String relativePath)
      throws IOException {
    relativePath = relativePath.replace('\\', '/');
    URL url;

    // In an application context, we try to find an external file relative to
    // the current working directory. If an external file does not exist, then
    // the file may be bundled into the jar with the classes. In this case, we
    // prepend a '/' to relativePath so that we search relative to the
    // classloader's root and not relative to the packaging of the current
    // class.

    File file = new File(relativePath);
    // If the file exists in the external file system, we return its
    // corresponding URL.
    if (file.exists()) {
      url = file.toURI().toURL();
    }
    // Otherwise, we search for the file relative to the classloader's root.
    // This will find the file if it is packaged into a jar with the classes.
    else {
      // Prepend a '/' so that we search relative to the classloader's root and
      // not relative to the packaging of the current class.
      if (relativePath.charAt(0) != '/') {
        relativePath = '/' + relativePath;
      }
      url = getClass().getResource(relativePath);
    }


    // Verify that we have a valid URL by trying to open its associated stream.
    if (url == null) {
      throw new FileNotFoundException(relativePath);
    }
    InputStream stream = url.openStream();
    stream.close();
    return url;
  }

  /**
   * Zooms the chart to fit the data model's time interval.
   */
  protected void zoomToFit() {
    zoomToFitAction.perform();
  }

}