/*
 * 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.GanttViewer;
import ganttviewer.util.GanttViewerLogger;
import ganttviewer.util.GanttViewerProperties;
import ganttviewer.util.PERTDiagram;
import ganttviewer.viewer.View;
import ganttviewer.viewer.Viewer;
import ganttviewer.viewer.exceptions.ViewException;
import ilog.views.IlvManagerViewInteractor;
import ilog.views.IlvPoint;
import ilog.views.IlvRect;
import ilog.views.IlvTransformer;
import ilog.views.event.InteractorListener;
import ilog.views.event.TransformerListener;
import ilog.views.gantt.IlvActivity;
import ilog.views.gantt.IlvGanttModel;
import ilog.views.gantt.IlvGanttModelUtil;
import ilog.views.gantt.event.SelectionEvent;
import ilog.views.gantt.event.SelectionListener;

import java.io.IOException;
import java.util.Iterator;

import javax.swing.JComponent;
import javax.swing.JEditorPane;

/**
 * <code>PERTView</code> is the dedicated PERT view.
 */
public class PERTView extends View implements SelectionListener {

  private static final String PERT_DIAGRAM_IMPL_CLASS = "ganttviewer.pert.PERTDiagramImpl";

  /**
   * The PERT diagram.
   */
  private PERTDiagram pertDiagram = null;

  /**
   * Initialization flag.
   */
  private boolean initialized = false;

  /**
   * Builds a <code>PERTView</code>.
   * @param viewer The viewer.
   * @param iD The ID of the view.
   * @param name The name of the view.
   */
  public PERTView(Viewer viewer, String iD, String name) {
    super(viewer, iD, name);
    // create the PERT diagram
    try {
      Class<?> pertDiagramClass = Class
          .forName(PERTView.PERT_DIAGRAM_IMPL_CLASS);
      // Diagrammer is in the classpath.
      pertDiagram = (PERTDiagram) pertDiagramClass.getDeclaredConstructor().newInstance();
      pertDiagram.addSelectionListener(this);
    } catch (Throwable th) {
      // Diagrammer may not be in the classpath
      pertDiagram = new WebPage();
    }
    // create the view.
    setMainComponent((JComponent) pertDiagram);
  }

  /**
   * Customizes the view before it is added.
   * @param component The view to be added.
   * @return The component to add.
   */
  Override
  protected JComponent mainComponentAboutToBeAdded(JComponent component) {
    ((PERTDiagram) component).initialize();
    return component;
  }

  /**
   * Attaches the Gantt data model to the view.
   * @param model The Gantt data model.
   */
  Override
  protected void attachModel(Object model) {
    pertDiagram.attachGanttModel((IlvGanttModel) model);
    // apply default transformation
    pertDiagram.setTransformer(getDefaultTransformer());
  }

  /**
   * 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) {
    try {
      pertDiagram.applyStyle(css);
    } catch (Exception e) {
      GanttViewerLogger.error(new ViewException(
          "Unable to apply stylesheet to the PERT view", e));
    }
  }

  /**
   * Returns the default transformer.
   * @return The transformer.
   */
  Override
  public IlvTransformer getDefaultTransformer() {
    IlvRect rect = pertDiagram.boundingBox();
    IlvRect visibleRect = pertDiagram.visibleRect();
    if ((visibleRect.width == 0) || (visibleRect.height == 0)) {
      return new IlvTransformer();
    }
    Iterator<IlvActivity> it = IlvGanttModelUtil
        .activityPostorderIterator(pertDiagram.getGanttModel());
    if (!it.hasNext()) {
      return new IlvTransformer();
    }
    IlvActivity firstActivity = it.next();
    IlvRect firstActivityBBox = pertDiagram.boundingBox(firstActivity);
    // scroll to center the view on the first activity
    double dy = -(firstActivityBBox.y + firstActivityBBox.height / 2 - visibleRect.height / 2);
    IlvTransformer newTransformer = new IlvTransformer();
    IlvTransformer.computeTransformer(new IlvRect(rect.x, rect.y,
        visibleRect.width, visibleRect.height), new IlvRect(rect.x, dy,
        visibleRect.width, visibleRect.height), newTransformer);
    return newTransformer;
  }

  /**
   * When the view is displayed, selects what has been selected in the previous view if possible.
   */
  Override
  public void setAsCurrentView() {
    if (!initialized) {
      // re-apply default transformation because it has not been
      // done during GUI creation
      pertDiagram.setTransformer(this.getDefaultTransformer());
      initialized = true;
    }
  }

  /**
   * Activity 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 IlvActivity) {
      pertDiagram.setSelected((IlvActivity) obj, selected);
    }
  }

  /**
   * Deselects all elements.
   */
  Override
  protected void deSelectAllImpl() {
    pertDiagram.deSelectAll();
  }

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

  /**
   * Instantiated when JViews Diagrammer is not available.
   */
  SuppressWarnings("serial")
  private class WebPage extends JEditorPane implements PERTDiagram {

    /**
     * Builds a <code>WebPage</code>.
     */
    public WebPage() {
      setEditable(false);
      // content type
      if ((GanttViewerProperties.getLocale().getVariant() != null)
          && !"".equals(GanttViewerProperties.getLocale().getVariant())) {
        setContentType("text/html;CHARSET="
            + GanttViewerProperties.getLocale().getVariant());
      } else {
        setContentType("text/html");
      }
      // open HTML
      try {
        this.setPage(GanttViewer.class.getResource(GanttViewerProperties
            .getString("NoPERT.Page")));
      } catch (IOException e) {
        // doing nothing, white page
      }
    }

    Override
    public void addInteractorListener(InteractorListener listener) {
    }

    Override
    public void addSelectionListener(SelectionListener listener) {
    }

    Override
    public void addTransformerListener(TransformerListener listener) {
    }

    Override
    public void applyStyle(String css) throws Exception {
    }

    Override
    public void attachGanttModel(IlvGanttModel ganttModel) {
    }

    Override
    public IlvGanttModel getGanttModel() {
      return null;
    }

    Override
    public IlvRect boundingBox() {
      return new IlvRect(0, 0, 0, 0);
    }

    Override
    public IlvRect boundingBox(IlvActivity activity) {
      return new IlvRect(0, 0, 0, 0);
    }

    Override
    public void deSelectAll() {
    }

    Override
    public IlvManagerViewInteractor getInteractor() {
      return null;
    }

    Override
    public IlvTransformer getTransformer() {
      return new IlvTransformer();
    }

    Override
    public void initialize() {
    }

    Override
    public boolean isSelected(IlvActivity activity) {
      return false;
    }

    Override
    public void removeInteractorListener(InteractorListener listener) {
    }

    Override
    public void removeSelectionListener(SelectionListener listener) {
    }

    Override
    public void removeTransformerListener(TransformerListener listener) {
    }

    Override
    public void setInteractor(IlvManagerViewInteractor interactor) {
    }

    Override
    public void setSelected(IlvActivity activity, boolean selected) {
    }

    Override
    public void setTransformer(IlvTransformer t) {
    }

    Override
    public IlvRect visibleRect() {
      return new IlvRect(0, 0, 0, 0);
    }

    Override
    public void zoom(IlvPoint point, double sx, double sy) {
    }

    Override
    public void zoomToFit() {
    }

  }

}