/*
 * 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.IlvPoint;
import ilog.views.IlvRect;
import ilog.views.IlvTransformer;
import ilog.views.gantt.IlvGanttChart;
import ilog.views.gantt.IlvGanttModel;
import ilog.views.gantt.IlvHierarchyChart;
import ilog.views.gantt.action.IlvZoomToFitAction;
import ilog.views.gantt.event.ActivityEvent;
import ilog.views.gantt.event.ActivityNameEvent;
import ilog.views.gantt.graphic.IlvActivityGraphic;
import ilog.views.gantt.graphic.IlvDefaultActivityRendererFactory;
import ilog.views.gantt.graphic.IlvDefaultConstraintGraphicFactory;
import ilog.views.gantt.graphic.renderer.composite.IlvActivityCompositeGraphicRenderer;
import ilog.views.graphic.IlvGeneralPath;
import ilog.views.graphic.IlvRectangle;
import ilog.views.graphic.IlvText;
import ilog.views.graphic.composite.IlvCompositeGraphic;
import ilog.views.graphic.composite.layout.IlvAttachmentConstraint;
import ilog.views.graphic.composite.layout.IlvAttachmentLocation;
import ilog.views.java2d.IlvLinearGradientPaint;
import ilog.views.util.IlvProductUtil;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.awt.geom.Point2D;
import javax.swing.*;


/**
 * Composite Graphic sample.
 * This sample code shows how to use composite graphic activity renderers.
 */
public class CGORendererExample extends JPanel {

  /**
   * A "foreground" color.
   */
  static final Color FOREGROUND_COLOR = new Color(76, 27, 27);

  /**
   * The chart.
   */
  public IlvHierarchyChart chart;

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

  /**
   * Builds a <code>CGORendererExample</code>.
   * @param frame The frame.
   */
  public CGORendererExample(JFrame frame) {
    // Prepare the JPanel's appearance
    setLayout(new BorderLayout());
    chart = new IlvGanttChart();

    // Create a simple model
    IlvGanttModel model = new SimpleProject(chart);

    // Set a custom activity renderer
    chart
        .setActivityRendererFactory(new CustomActivityCompositeGraphicRendererFactory(
            chart));
    // Customize constraint graphics
    chart.setConstraintGraphicFactory(new IlvDefaultConstraintGraphicFactory() {

      /**
       * Overrides to customize constraints color.
       */
      Override
      public Color getConstraintColor() {
        return FOREGROUND_COLOR;
      }

    });

    // Set the model
    chart.setGanttModel(model);

    zoomToFitAction = new IlvZoomToFitAction(chart, "", null, null,
        "Zoom To Fit", "");

    add(BorderLayout.NORTH, createToolbar());
    add(BorderLayout.CENTER, chart);

    zoomToFit();

    // Make sure the full chart is visible.
    chart.expandAllRows();
    chart.revalidate();
  }

  /**
   * This method creates a toolbar for this example.
   * @return The toolbar.
   */
  protected JToolBar createToolbar() {
    JToolBar toolbar = new JToolBar();
    toolbar.setFloatable(false);
    // add a zoom-in button
    JButton zoomInButton = new JButton(chart.getZoomInAction());
    zoomInButton.setText(null);
    toolbar.add(zoomInButton);
    // add a zoom-out button
    JButton zoomOutButton = new JButton(chart.getZoomOutAction());
    zoomOutButton.setText(null);
    toolbar.add(zoomOutButton);
    // add a zoom-to-fit button
    JButton zoomToFitButton = new JButton(zoomToFitAction);
    toolbar.add(zoomToFitButton);
    return toolbar;
  }

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

  /**
   * A custom renderer factory.
   */
  public class CustomActivityCompositeGraphicRendererFactory extends
      IlvDefaultActivityRendererFactory {

    /**
     * Creates a customized activity renderer factory.
     */
    public CustomActivityCompositeGraphicRendererFactory(IlvHierarchyChart chart) {
      super(chart);
      // Customize the leaf activities' rendering
      setLeafActivityRenderer(new CustomLeafActivityCompositeGraphicRenderer());
      // Customize the parent activities' rendering
      setParentActivityRenderer(new CustomParentActivityCompositeGraphicRenderer());
    }

  }

  /**
   * A custom leaf activity renderer based on a composite graphic.
   */
  class CustomLeafActivityCompositeGraphicRenderer extends
      IlvActivityCompositeGraphicRenderer {

    /**
     * Builds a <code>CustomLeafActivityCompositeGraphicRenderer</code>
     */
    public CustomLeafActivityCompositeGraphicRenderer() {
      setGraphic(new CustomLeafActivityCompositeGraphic());
    }

    /**
     * Overrides to update the label corresponding to the activity name.
     * @param ag The activity graphic.
     * @param t The current transformer.
     */
    Override
    public IlvRect computeBaseBounds(IlvActivityGraphic ag, IlvTransformer t) {
      CustomLeafActivityCompositeGraphic graphic = (CustomLeafActivityCompositeGraphic) getGraphic();
      IlvRect rect = super.computeBaseBounds(ag, t);
      graphic.setLabel(ag.getActivity().getName());
      return rect;
    }

    /**
     * Overrides to trigger a redraw when the name is updated.
     */
    Override
    public boolean isRedrawNeeded(IlvActivityGraphic ag, ActivityEvent evt) {
      if (super.isRedrawNeeded(ag, evt)) {
        return true;
      }
      return evt instanceof ActivityNameEvent;
    }

    /**
     * Overrides to customize the tooltip.
     * @param ag The activity graphic.
     * @param p The location of the mouse (in view coordinates).
     * @param t The transformer.
     * @return The tooltip text.
     */
    Override
    public String getToolTipText(IlvActivityGraphic ag, IlvPoint p,
        IlvTransformer t) {
      return ag.getActivity().getID() + ": " + ag.getActivity().getName();
    }

  }

  /**
   * Creates a gradient paint.
   * @param color1
   * @param color2
   * @param color3
   * @return The gradient paint.
   */
  static Paint getGradient(Color color1, Color color2, Color color3) {
    // Create a gradient.
    Color[] colors = { color1, color2, color3 };
    float[] stops = { 0, 0.25f, 1 };
    Point2D start = new Point2D.Double(0, 0);
    Point2D end = new Point2D.Double(0, 1);
    return new IlvLinearGradientPaint(start, end, stops, colors, true);
  }

  static final Color LEAF_ACTIVITY_COMPOSITE_COLOR_1 = new Color(246, 228, 151);

  static final Color LEAF_ACTIVITY_COMPOSITE_COLOR_2 = new Color(252, 250, 225);

  static final Color LEAF_ACTIVITY_COMPOSITE_COLOR_3 = new Color(189, 141, 70);

  /**
   * The composite graphic used to render leaf activities.
   */
  class CustomLeafActivityCompositeGraphic extends IlvCompositeGraphic {

    /**
     * The text graphic used to display the label.
     */
    private IlvText text;

    /**
     * A decoration.
     */
    private IlvRectangle rect;

    /**
     * Builds a <code>CustomLeafActivityCompositeGraphic</code>.
     */
    public CustomLeafActivityCompositeGraphic() {
      // The rectangle as the base of the composite graphic .
      IlvGeneralPath base = new IlvGeneralPath();
      base.setFillOn(true);
      base.setStrokeOn(false);
      base.setFillPaint(getGradient(LEAF_ACTIVITY_COMPOSITE_COLOR_1,
          LEAF_ACTIVITY_COMPOSITE_COLOR_2, LEAF_ACTIVITY_COMPOSITE_COLOR_3));
      // Create a text.
      text = new IlvText(new IlvPoint(), "");
      text.setForeground(FOREGROUND_COLOR);
      text.setWrappingMode(IlvText.WRAP_TRUNCATE);
      text.setFont(new Font("Arial", Font.PLAIN, 14));
      // Create a decoration.
      rect = new IlvRectangle(new IlvRect(0, 0, 5, 5));
      rect.setFillOn(true);
      rect.setStrokeOn(true);
      rect.setBackground(FOREGROUND_COLOR);
      rect.setForeground(LEAF_ACTIVITY_COMPOSITE_COLOR_1);
      // Add these graphic objects to the composite.
      addChild(base);
      setConstraints(0, new IlvAttachmentConstraint(
          IlvAttachmentLocation.TopLeft, IlvAttachmentLocation.TopLeft));
      addChild(text);
      setConstraints(1, new IlvAttachmentConstraint(
          IlvAttachmentLocation.LeftCenter, IlvAttachmentLocation.LeftCenter,
          14, 0));
      addChild(rect);
      setConstraints(2, new IlvAttachmentConstraint(
          IlvAttachmentLocation.LeftCenter, IlvAttachmentLocation.LeftCenter,
          3.0f, 0));
    }

    /**
     * Set a label on this graphic.
     * @param label The label to display.
     */
    Override
    public void setLabel(String label) {
      text.setLabel(label);
    }

    /**
     * Overrides to update graphics depending on the size changes to the composite.
     */
    Override
    public void moveResize(IlvRect size) {
      if (size.width > 0) {
        // Display the decoration if the activity graphic size is wide enough.
        if (size.width < 30) {
          text.setWrappingWidth(size.width);
          setConstraints(1, new IlvAttachmentConstraint(
              IlvAttachmentLocation.Center, IlvAttachmentLocation.Center));
          rect.setVisible(false);
        } else {
          int width = (int) (size.width - 18);
          text.setWrappingWidth(width);
          setConstraints(1, new IlvAttachmentConstraint(
              IlvAttachmentLocation.LeftCenter,
              IlvAttachmentLocation.LeftCenter, 14, 0));
          rect.setVisible(true);
        }
        super.moveResize(size);
      }
    }
  }

  /**
   * A custom parent activity renderer based on a composite graphic.
   */
  class CustomParentActivityCompositeGraphicRenderer extends
      IlvActivityCompositeGraphicRenderer {

    /**
     * Builds a <code>CustomParentActivityCompositeGraphicRenderer</code>.
     */
    public CustomParentActivityCompositeGraphicRenderer() {
      setGraphic(new CustomParentActivityCompositeGraphic());
    }

    /**
     * Overrides to customize the tooltip.
     * @param ag The activity graphic.
     * @param p The location of the mouse (in view coordinates).
     * @param t The transformer.
     * @return The tooltip text.
     */
    Override
    public String getToolTipText(IlvActivityGraphic ag, IlvPoint p,
        IlvTransformer t) {
      return ag.getActivity().getID() + ": " + ag.getActivity().getName();
    }

  }

  static final Color PARENT_ACTIVITY_COMPOSITE_COLOR_1 = FOREGROUND_COLOR;

  static final Color PARENT_ACTIVITY_COMPOSITE_COLOR_2 = LEAF_ACTIVITY_COMPOSITE_COLOR_2;

  static final Color PARENT_ACTIVITY_COMPOSITE_COLOR_3 = new Color(185, 18, 27);

  /**
   * The composite graphic used to render parent activities.
   */
  class CustomParentActivityCompositeGraphic extends IlvCompositeGraphic {

    /**
     * The rectangle.
     */
    private IlvGeneralPath rect;

    /**
     * Decoration 1.
     */
    private IlvRectangle sRect;

    /**
     * Decoration 2.
     */
    private IlvRectangle eRect;

    /**
     * Builds a <code>CustomParentActivityCompositeGraphic</code>.
     */
    public CustomParentActivityCompositeGraphic() {
      // An invisible rectangle as the base of the composite graphic.
      IlvRectangle base = new IlvRectangle();
      base.setFillOn(false);
      base.setStrokeOn(false);
      // A gradient-colored thinner rectangle
      rect = new IlvGeneralPath();
      rect.setFillOn(true);
      rect.setStrokeOn(false);
      rect
          .setFillPaint(getGradient(PARENT_ACTIVITY_COMPOSITE_COLOR_1,
              PARENT_ACTIVITY_COMPOSITE_COLOR_2,
              PARENT_ACTIVITY_COMPOSITE_COLOR_3));
      // Decorations
      sRect = new IlvRectangle();
      sRect.setFillOn(true);
      sRect.setStrokeOn(true);
      sRect.setBackground(FOREGROUND_COLOR);
      sRect.setForeground(PARENT_ACTIVITY_COMPOSITE_COLOR_2);
      eRect = new IlvRectangle();
      eRect.setFillOn(true);
      eRect.setStrokeOn(true);
      eRect.setBackground(FOREGROUND_COLOR);
      eRect.setForeground(PARENT_ACTIVITY_COMPOSITE_COLOR_2);
      // Add these graphic objects to the composite.
      addChild(base);
      setConstraints(0, new IlvAttachmentConstraint(
          IlvAttachmentLocation.TopLeft, IlvAttachmentLocation.TopLeft));
      addChild(rect);
      setConstraints(1, new IlvAttachmentConstraint(
          IlvAttachmentLocation.Center, IlvAttachmentLocation.Center));
      addChild(sRect);
      setConstraints(2, new IlvAttachmentConstraint(
          IlvAttachmentLocation.LeftCenter, IlvAttachmentLocation.LeftCenter));
      addChild(eRect);
      setConstraints(3, new IlvAttachmentConstraint(
          IlvAttachmentLocation.RightCenter, IlvAttachmentLocation.RightCenter));
    }

    /**
     * Overrides to update graphics depending on the size changes to the composite.
     */
    Override
    public void moveResize(IlvRect size) {
      int decorationWidth = 5;
      int height = (int) (size.height - 5);
      rect.resize(size.width, height);
      sRect.resize(decorationWidth, size.height);
      eRect.resize(decorationWidth, size.height);
      invalidate();
      super.moveResize(size);
    }

  }

  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(50, 300, 800, 500);
        CGORendererExample example = new CGORendererExample(frame);
        frame.getContentPane().add(example);
        frame.setVisible(true);
      }
    });
  }
}