/*
 * 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 radar;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;

import javax.swing.JComponent;

import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.NumberFormat;

import ilog.views.chart.IlvColor;
import ilog.views.chart.IlvDisplayPoint;
import ilog.views.chart.IlvDoublePoints;
import ilog.views.chart.IlvLabelRenderer;
import ilog.views.chart.interactor.IlvChartEditPointInteractor;
import ilog.views.chart.util.IlvGraphicUtil;
import ilog.views.util.java2d.IlvPattern;

/**
 * A subclass of <code>IlvChartEditPointInteractor</code> that displays the
 * value of the point being edited next to the mouse cursor.
 * <p>
 * <b>Note:</b> The text displaying the value of the point is only visible when
 * the interactor is not in <i>opaque editing</i> mode.
 *
 * The <code>EditPointInteractor</code> interactor also ensures that the edited
 * points take values that are a multiple of the precision specified with the
 * {@link #setPrecision} method.
 *
 * @see IlvChartEditPointInteractor#isOpaqueEdit
 */
public class EditPointInteractor extends IlvChartEditPointInteractor {
  private Point mouseLocation = new Point();
  private IlvLabelRenderer editLabel;
  private NumberFormat fmt;
  private double precision;

  /** Creates new <code>EditPointInteractor</code>. */
  public EditPointInteractor() {
    super(MouseEvent.BUTTON1_DOWN_MASK, false);
    editLabel = new IlvLabelRenderer(Color.white, Color.black);
    fmt = NumberFormat.getNumberInstance();
    if (fmt instanceof DecimalFormat) {
      ((DecimalFormat) fmt).applyPattern("####.##");
    } else {
      fmt.setMaximumFractionDigits(2);
    }
  }

  /** Called when the interaction starts. */
  Override
  protected void startOperation(MouseEvent evt) {
    super.startOperation(evt);
    mouseLocation.setLocation(evt.getX(), evt.getY());
    IlvDisplayPoint dp = getEditPoint();
    Color bg = Color.white;
    if (dp != null) { // Should always be the case ...
      Paint p = dp.getRenderer().getStyle(0).getFillPaint();
      Color c = null;
      if (p instanceof Color)
        c = (Color) p;
      else if (p instanceof IlvPattern)
        c = ((IlvPattern) p).getBackground();
      if (c != null)
        bg = IlvColor.setAlpha(IlvColor.brighter(c), 1.f);
    }
    editLabel.setBackground(bg);
  }

  /** Handles the mouse motion events. */
  Override
  public void processMouseMotionEvent(MouseEvent evt) {
    super.processMouseMotionEvent(evt);
    mouseLocation.setLocation(evt.getX(), evt.getY());
  }

  /** Draws the ghost. */
  Override
  protected void drawGhost(Graphics g) {
    super.drawGhost(g);
    JComponent comp = getChart().getChartArea();
    String text = getValueText();
    Point p = getValueTextLocation();
    editLabel.paintLabel(comp, g, text, p.x, p.y);
  }

  /** Returns the ghost bounds. */
  Override
  protected Rectangle getGhostBounds() {
    Rectangle r = super.getGhostBounds();
    JComponent comp = getChart().getChartArea();
    String text = getValueText();
    Point p = getValueTextLocation();
    Rectangle2D labelBounds = editLabel.getBounds(comp, p.x, p.y, text, null);
    IlvGraphicUtil.addToRect(r, labelBounds);
    return r;
  }

  /** Returns the location of the text displaying the edited value */
  protected Point getValueTextLocation() {
    IlvDisplayPoint dp = getEditPoint();
    Point p = new Point(IlvGraphicUtil.toInt(dp.getXCoord()), IlvGraphicUtil.toInt(dp.getYCoord()) - 20);
    return p;
  }

  /** Returns the text corresponding to the edited value */
  protected String getValueText() {
    double yValue = getData(mouseLocation.x, mouseLocation.y).y;
    return fmt.format(yValue);
  }

  /**
   * Returns the precision used by the interactor to edit points.
   * 
   * @see #setPrecision
   */
  public final double getPrecision() {
    return this.precision;
  }

  /**
   * Sets the precision used by the interactor to edit points. The interator
   * ensures that the values of the edited points are a multiple of the
   * specified precision.
   * 
   * @see #getPrecision
   */
  public void setPrecision(double precision) {
    this.precision = precision;
  }

  /**
   * Called to validate the value of the edited point. This method ensures that
   * the coordinates of the edited point is a multiple of the interactor
   * precision.
   * 
   * @param pt
   *          The new position to validate (in data coordinate system).
   * @param dpt
   *          The display point being modified.
   * @see #setPrecision
   */
  Override
  protected void validate(IlvDoublePoints pt, IlvDisplayPoint dpt) {
    if (precision != 0) {
      pt.setX(0, Math.round(pt.getX(0) / precision) * precision);
      pt.setY(0, Math.round(pt.getY(0) / precision) * precision);
    }
  }
}