/*
 * 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 ganttviewer.views;

import ganttviewer.util.GanttViewerProperties;
import ganttviewer.viewer.View;
import ganttviewer.viewer.Viewer;
import ilog.views.chart.IlvChart;
import ilog.views.chart.IlvChartAreaSynchronizer;
import ilog.views.chart.IlvChartLayout;
import ilog.views.gantt.IlvActivityFactory;
import ilog.views.gantt.IlvConstraintFactory;
import ilog.views.gantt.IlvGanttModel;
import ilog.views.gantt.IlvHierarchyChart;
import ilog.views.gantt.IlvResource;
import ilog.views.gantt.IlvScheduleChart;
import ilog.views.gantt.IlvTimeScrollController;
import ilog.views.gantt.event.SelectionEvent;
import ilog.views.gantt.event.SelectionListener;
import ilog.views.gantt.event.TimeChangedEvent;
import ilog.views.gantt.event.TimeScrollListener2;
import ilog.views.gantt.event.VisibleDurationChangedEvent;
import ilog.views.gantt.event.VisibleTimeChangedEvent;
import ilog.views.gantt.graphic.IlvActivityTileLayout;
import ilog.views.gantt.graphic.IlvGanttSheet;
import ilog.views.gantt.graphic.grid.IlvGanttGridRenderer;
import ilog.views.gantt.graphic.grid.IlvWeekendGrid;
import ilog.views.schedule.IlvResourceDataChart;
import ilog.views.schedule.interactor.IlvScheduleInfoViewInteractor;
import ilog.views.util.styling.IlvStylingException;

import java.awt.Dimension;

import javax.swing.JComponent;
import javax.swing.JSplitPane;

/**
 * <code>ResourceUsageView</code> is the resource usage view.
 */
public class ResourceUsageView extends View implements SelectionListener {

  private static final String QUANTITY_COLUMN = "Qty";

  private static final String NAME_COLUMN = "Name";

  /**
   * ResourceData chart.
   */
  private IlvResourceDataChart loadChart;

  /**
   * Activity factory.
   */
  private IlvActivityFactory activityFactory;

  /**
   * Constraint factory.
   */
  private IlvConstraintFactory constraintFactory;

  /**
   * A time scroll controller.
   */
  private IlvTimeScrollController timeScrollController;

  /**
   * Builds a <code>ResourceUsageView</code>.
   * @param viewer The viewer.
   * @param iD The ID of the view.
   * @param name The name of the view.
   * @param timeScrollController A time scroll controller.
   * @param activityFactory An activity factory.
   * @param constraintFactory A constraint factory.
   */
  public ResourceUsageView(Viewer viewer, String iD, String name,
      IlvTimeScrollController timeScrollController,
      IlvActivityFactory activityFactory, IlvConstraintFactory constraintFactory) {
    super(viewer, iD, name);
    this.activityFactory = activityFactory;
    this.constraintFactory = constraintFactory;
    this.timeScrollController = timeScrollController;
    // set the Schedule chart.
    setMainComponent(new IlvScheduleChart());
  }

  /**
   * Customizes the Schedule chart before it is added.
   * @param component The chart to be added.
   * @return A split pane to add.
   */
  Override
  protected JComponent mainComponentAboutToBeAdded(JComponent component) {
    IlvScheduleChart chart = (IlvScheduleChart) component;
    timeScrollController.addTimeScrollable(chart);
    // factories init.
    chart.setActivityFactory(activityFactory);
    chart.setConstraintFactory(constraintFactory);
    // listen to selection changes.
    chart.addSelectionListener(this);
    // create the load chart.
    loadChart = new IlvResourceDataChart();
    // synchronize both charts
    loadChart.getChartArea().getChart().setResizingPolicy(null);
    loadChart.setVisibleInterval(chart.getVisibleTime(), chart
        .getVisibleDuration());
    chart.addTimeScrollListener(new TimeScrollListener2() {
      Override
      public void visibleTimeChanged(VisibleTimeChangedEvent evt) {
        if (!evt.isAdjusting()) {
          loadChart.setVisibleTime(evt.getTime());
        }
      }

      Override
      public void visibleDurationChanged(VisibleDurationChangedEvent evt) {
        loadChart.setVisibleInterval(getScheduleChart().getVisibleTime(), evt
            .getDuration());
      }

      Override
      public void minVisibleTimeChanged(TimeChangedEvent evt) {
      }

      Override
      public void maxVisibleTimeChanged(TimeChangedEvent evt) {
      }

      Override
      public void minVisibleDurationChanged(VisibleDurationChangedEvent evt) {
      }
    });
    // configure the table
    configureTable(chart);
    // configure the load chart
    configureLoadChart(loadChart);
    // set hover highlighting
    chart.getGanttSheet().setHoverHighlightingMode(IlvGanttSheet.HH_GRAYSCALE);
    // force the weekend grid to print opaque. This reduces the print job
    // size from >60Mb to approx. 150Kb.
    IlvGanttGridRenderer verticalGrid = chart.getGanttSheet().getVerticalGrid();
    if (verticalGrid instanceof IlvWeekendGrid) {
      ((IlvWeekendGrid) verticalGrid).setPrintWeekendsOpaque(true);
    }
    // enable animation of changes to the visible time interval.
    chart.setVisibleIntervalAnimationSteps(4);
    // the split pane to be added.
    JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
    splitPane.setDividerSize(3);
    splitPane.setResizeWeight(0.75);
    splitPane.setTopComponent(chart);
    splitPane.setBottomComponent(loadChart);
    return splitPane;
  }

  /**
   * Configures the table.
   * @param chart The Schedule chart.
   */
  protected void configureTable(IlvScheduleChart chart) {
    chart.getTable().getColumn(NAME_COLUMN).setPreferredWidth(
        Integer.parseInt(GanttViewerProperties
            .getString("Table.Column.Name.Width")));
    // remove quantity
    chart.getTable().removeColumn(QUANTITY_COLUMN);
  }

  /**
   * Configures the Resource Data chart.
   * @param loadChart The Resource Data chart.
   */
  protected void configureLoadChart(IlvResourceDataChart loadChart) {
    loadChart.setMinimumSize(new Dimension(50, 50));
    // add a highlight interactor that displays the load of a resource in a
    // tooltip
    loadChart.addInteractor(new IlvScheduleInfoViewInteractor());
    // synchronize the data models of the charts. Resources selected in the
    // in the Schedule chart will be displayed in the Resource Data chart.
    loadChart.syncGanttModel(getScheduleChart(),
        IlvResourceDataChart.DISPLAY_SELECTED_LEAVES);
    // customize the legend
    customizeLegend(loadChart);
    IlvChart.Area chartArea = loadChart.getChartArea();
    IlvChartAreaSynchronizer.synchronize(chartArea.getChart(),
        getScheduleChart().getGanttSheet());
  }

  /**
   * Customizes the legend.
   * @param loadChart The Resource Data chart.
   */
  protected void customizeLegend(IlvResourceDataChart loadChart) {
    loadChart.setLegendPosition(IlvChartLayout.SOUTH_TOP);
  }

  /**
   * Attaches the Gantt data model to the view.
   * @param model The Gantt data model.
   */
  Override
  protected void attachModel(Object model) {
    IlvScheduleChart chart = getScheduleChart();
    chart.setGanttModel((IlvGanttModel) model);
    if (model == null) {
      return;
    }
    // graph layout
    chart.getGanttSheet().setActivityLayout(new IlvActivityTileLayout());
    // expand all rows
    chart.expandAllRows();
  }

  /**
   * Returns the Schedule chart.
   * @return The Schedule chart.
   */
  public IlvScheduleChart getScheduleChart() {
    return (IlvScheduleChart) getMainComponent();
  }

  /**
   * Returns the Resource Data chart.
   * @return The Resource Data chart.
   */
  public IlvResourceDataChart getLoadChart() {
    return loadChart;
  }

  /**
   * Indicates whether this view is stylable or not.
   * @return <code>true</code>.
   */
  Override
  public boolean isStylable() {
    return true;
  }

  /**
   * Applies the style to this view.
   * @param css The CSS.
   */
  Override
  public void applyStyle(String css) throws IlvStylingException {
    IlvHierarchyChart chart = getScheduleChart();
    chart.setStyleSheet(css);
  }

  /**
   * Resource selection implementation.
   * @param obj The object to (de)select.
   * @param selected The selection status.
   */
  Override
  protected void setSelectedImpl(Object obj, boolean selected) {
    if (obj instanceof IlvResource) {
      getScheduleChart().select((IlvResource) obj, selected);
    }
  }

  /**
   * Listens for selection changes.
   * @param event The selection event.
   */
  Override
  public void selectionChanged(SelectionEvent event) {
    super.selectionChanged(event.getSource(), event.isObjectSelected());
  }

  /**
   * Deselects all.
   */
  Override
  protected void deSelectAllImpl() {
    getScheduleChart().deSelectAllRows();
  }

}