<commit_before>package org.timepedia.chronoscope.client.overlays;

import org.timepedia.chronoscope.client.Cursor;
import org.timepedia.chronoscope.client.InfoWindow;
import org.timepedia.chronoscope.client.Overlay;
import org.timepedia.chronoscope.client.XYPlot;
import org.timepedia.chronoscope.client.canvas.Color;
import org.timepedia.chronoscope.client.canvas.Layer;
import org.timepedia.chronoscope.client.canvas.View;
import org.timepedia.chronoscope.client.gss.GssElement;
import org.timepedia.chronoscope.client.gss.GssProperties;
import org.timepedia.chronoscope.client.util.ArgChecker;
import org.timepedia.chronoscope.client.util.MathUtil;
import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.ExportPackage;
import org.timepedia.exporter.client.Exportable;

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by IntelliJ IDEA. User: ray Date: Apr 20, 2007 Time: 4:03:02 PM To
 * change this template use File | Settings | File Templates.
 *
 * @gwt.exportPackage chronoscope
 */
@ExportPackage("chronoscope")
public class Marker implements Overlay, GssElement, Exportable {

  private static enum MarkerShape {

    BALLOON, TEARDROP
  }

  ;

  // Determines how high (stretched-out) the marker is.
  private static final int MARKER_HEIGHT = 15;

  protected XYPlot plot = null;

  private ArrayList<OverlayClickListener> clickListeners;

  private int datasetIdx = -1;

  private final double domainX;

  private boolean isScreenPropsSet = false;

  private String label;

  private GssProperties markerProps;

  private MarkerShape markerShape;

  private double rangeY;

  private int labelWidth, labelHeight;

  public Marker(double domainX, String label, int datasetIdx) {
    this.domainX = domainX;
    this.label = label;

    // Silently fix an invalid dataset index
    this.datasetIdx = Math.max(0, datasetIdx);
  }

  /**
   * @gwt.export
   */
  @Export
  public Marker(String date, int datasetIdx, String label) {
    this(Date.parse(date), label, datasetIdx);
  }

  /**
   * @gwt.export addOverlayListener
   */
  @Export("addOverlayListener")
  public void addOverlayClickListener(OverlayClickListener ocl) {
    if (clickListeners == null) {
      clickListeners = new ArrayList<OverlayClickListener>();
    }
    clickListeners.add(ocl);
  }

  public void click(int x, int y) {
    if (clickListeners != null) {
      for (OverlayClickListener l : clickListeners) {
        l.onOverlayClick(this, x, y);
      }
    }
  }

  public void draw(Layer backingCanvas, String layer) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }

    if (!plot.getDomain().containsOpen(domainX)) {
      return;
    }

    lazyInitScreenProps(backingCanvas);

    double x = plot.domainToScreenX(domainX, datasetIdx);
    double yp = plot.rangeToScreenY(rangeY, datasetIdx);
    double y = yp;

    double proposedMarkerTop = y - MARKER_HEIGHT - labelHeight;
    if (proposedMarkerTop > plot.getInnerBounds().y) {
      y = proposedMarkerTop;
      markerShape = MarkerShape.BALLOON;
    } else {
      y += MARKER_HEIGHT;
      markerShape = MarkerShape.TEARDROP;
    }

    backingCanvas.save();
    int arcDirection = (y < yp) ? 1 : 0;
    x = drawOval(labelWidth, labelHeight, markerProps, backingCanvas, x, y, yp,
        arcDirection);

    backingCanvas.drawText(x, y, label, markerProps.fontFamily,
        markerProps.fontWeight, markerProps.fontSize, layer, Cursor.CLICKABLE);
    backingCanvas.restore();
  }

  public int getDatasetIndex() {
    return this.datasetIdx;
  }

  public double getDomainX() {
    return domainX;
  }

  public GssElement getParentGssElement() {
    return null;
  }

  public double getRangeY() {
    return rangeY;
  }

  public String getType() {
    return "marker";
  }


  public String getLabel() {
    return label;
  }

  public void setLabel(String label) {
    this.label = label;
  }

  public String getTypeClass() {
    return label;
  }

  public boolean isHit(int x, int y) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }

    final double mx = plot.domainToWindowX(domainX, datasetIdx);
    final double xPad = labelWidth / 2 + 3;
    final boolean isHitX = MathUtil.isBounded(x, mx - xPad, mx + xPad);

    final double my = plot.rangeToWindowY(rangeY, datasetIdx);
    boolean isHitY;
    if (markerShape == MarkerShape.BALLOON) {
      double topOfBalloon = my - MARKER_HEIGHT - labelHeight;
      isHitY = MathUtil.isBounded(y, topOfBalloon, my);
    } else { // assumed to be TEARDROP
      double bottomOfTeardrop = my + MARKER_HEIGHT + labelHeight;
      isHitY = MathUtil.isBounded(y, my, bottomOfTeardrop);
    }

    return isHitX && isHitY;
  }

  /**
   * @gwt.export
   */
  @Export
  public InfoWindow openInfoWindow(String html) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }
    return plot.openInfoWindow(html, domainX, rangeY, datasetIdx);
  }

  public void removeOverlayClickListener(OverlayClickListener listener) {
    if (clickListeners != null) {
      clickListeners.remove(listener);
    }
  }

  public void setDatasetIndex(int datasetIndex) {
    this.datasetIdx = datasetIndex;
  }

  public void setPlot(XYPlot plot) {
    ArgChecker.isNotNull(plot, "plot");
    this.plot = plot;
    rangeY = interpolateRangeY(domainX, datasetIdx);
  }
<commit_msg>Changes to make InfoWindow follow marker<commit_after>package org.timepedia.chronoscope.client.overlays;

import org.timepedia.chronoscope.client.Cursor;
import org.timepedia.chronoscope.client.InfoWindow;
import org.timepedia.chronoscope.client.Overlay;
import org.timepedia.chronoscope.client.XYPlot;
import org.timepedia.chronoscope.client.canvas.Color;
import org.timepedia.chronoscope.client.canvas.Layer;
import org.timepedia.chronoscope.client.canvas.View;
import org.timepedia.chronoscope.client.gss.GssElement;
import org.timepedia.chronoscope.client.gss.GssProperties;
import org.timepedia.chronoscope.client.util.ArgChecker;
import org.timepedia.chronoscope.client.util.MathUtil;
import org.timepedia.exporter.client.Export;
import org.timepedia.exporter.client.ExportPackage;
import org.timepedia.exporter.client.Exportable;

import java.util.ArrayList;
import java.util.Date;

/**
 * Created by IntelliJ IDEA. User: ray Date: Apr 20, 2007 Time: 4:03:02 PM To
 * change this template use File | Settings | File Templates.
 *
 * @gwt.exportPackage chronoscope
 */
@ExportPackage("chronoscope")
public class Marker implements Overlay, GssElement, Exportable {

  private InfoWindow currentWindow;

  private InfoWindow wasOpenWindow;

  private static enum MarkerShape {

    BALLOON, TEARDROP
  }

  ;

  // Determines how high (stretched-out) the marker is.
  private static final int MARKER_HEIGHT = 15;

  protected XYPlot plot = null;

  private ArrayList<OverlayClickListener> clickListeners;

  private int datasetIdx = -1;

  private final double domainX;

  private boolean isScreenPropsSet = false;

  private String label;

  private GssProperties markerProps;

  private MarkerShape markerShape;

  private double rangeY;

  private int labelWidth, labelHeight;

  public Marker(double domainX, String label, int datasetIdx) {
    this.domainX = domainX;
    this.label = label;

    // Silently fix an invalid dataset index
    this.datasetIdx = Math.max(0, datasetIdx);
  }

  /**
   * @gwt.export
   */
  @Export
  public Marker(String date, int datasetIdx, String label) {
    this(Date.parse(date), label, datasetIdx);
  }

  /**
   * @gwt.export addOverlayListener
   */
  @Export("addOverlayListener")
  public void addOverlayClickListener(OverlayClickListener ocl) {
    if (clickListeners == null) {
      clickListeners = new ArrayList<OverlayClickListener>();
    }
    clickListeners.add(ocl);
  }

  public void click(int x, int y) {
    if (clickListeners != null) {
      for (OverlayClickListener l : clickListeners) {
        l.onOverlayClick(this, x, y);
      }
    }
  }

  public void draw(Layer backingCanvas, String layer) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }

    // if no longer visible, close window
    if (!plot.getDomain().containsOpen(domainX)) {
      if (currentWindow != null) {
        wasOpenWindow = currentWindow;
        currentWindow.close();
      }
      return;
    }

    // if window was hidden, and marker is now visible, show it
    if (currentWindow == null && wasOpenWindow != null) {
      currentWindow = wasOpenWindow;
      wasOpenWindow = null;
      currentWindow.open();
    }

    lazyInitScreenProps(backingCanvas);

    double x = plot.domainToScreenX(domainX, datasetIdx);
    double yp = plot.rangeToScreenY(rangeY, datasetIdx);
    double y = yp;

    double proposedMarkerTop = y - MARKER_HEIGHT - labelHeight;
    if (proposedMarkerTop > plot.getInnerBounds().y) {
      y = proposedMarkerTop;
      markerShape = MarkerShape.BALLOON;
    } else {
      y += MARKER_HEIGHT;
      markerShape = MarkerShape.TEARDROP;
    }

    backingCanvas.save();
    int arcDirection = (y < yp) ? 1 : 0;
    if (currentWindow != null) {
      currentWindow.setPosition(plot.domainToWindowX(domainX, datasetIdx),
          plot.rangeToWindowY(rangeY, datasetIdx) + 5);
    }
    x = drawOval(labelWidth, labelHeight, markerProps, backingCanvas, x, y, yp,
        arcDirection);

    backingCanvas.drawText(x, y, label, markerProps.fontFamily,
        markerProps.fontWeight, markerProps.fontSize, layer, Cursor.CLICKABLE);
    backingCanvas.restore();

  }

  public int getDatasetIndex() {
    return this.datasetIdx;
  }

  public double getDomainX() {
    return domainX;
  }

  public GssElement getParentGssElement() {
    return null;
  }

  public double getRangeY() {
    return rangeY;
  }

  public String getType() {
    return "marker";
  }


  public String getLabel() {
    return label;
  }

  public void setLabel(String label) {
    this.label = label;
  }

  public String getTypeClass() {
    return label;
  }

  public boolean isHit(int x, int y) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }

    final double mx = plot.domainToWindowX(domainX, datasetIdx);
    final double xPad = labelWidth / 2 + 3;
    final boolean isHitX = MathUtil.isBounded(x, mx - xPad, mx + xPad);

    final double my = plot.rangeToWindowY(rangeY, datasetIdx);
    boolean isHitY;
    if (markerShape == MarkerShape.BALLOON) {
      double topOfBalloon = my - MARKER_HEIGHT - labelHeight;
      isHitY = MathUtil.isBounded(y, topOfBalloon, my);
    } else { // assumed to be TEARDROP
      double bottomOfTeardrop = my + MARKER_HEIGHT + labelHeight;
      isHitY = MathUtil.isBounded(y, my, bottomOfTeardrop);
    }

    return isHitX && isHitY;
  }

  /**
   * @gwt.export
   */
  @Export
  public InfoWindow openInfoWindow(String html) {
    if (plot == null) {
      throw new IllegalStateException("plot not set");
    }
    if (currentWindow != null) {
      currentWindow.close();
    }
    wasOpenWindow = null;
    currentWindow = plot.openInfoWindow(html, domainX, rangeY, datasetIdx);
    currentWindow
        .addInfoWindowClosedHandler(new InfoWindow.InfoWindowClosedHandler() {
          public void onInfoWindowClosed(InfoWindow.InfoWindowEvent event) {
            currentWindow = null;
          }
        });
    return currentWindow;
  }

  public void removeOverlayClickListener(OverlayClickListener listener) {
    if (clickListeners != null) {
      clickListeners.remove(listener);
    }
  }

  public void setDatasetIndex(int datasetIndex) {
    this.datasetIdx = datasetIndex;
  }

  public void setPlot(XYPlot plot) {
    ArgChecker.isNotNull(plot, "plot");
    this.plot = plot;
    rangeY = interpolateRangeY(domainX, datasetIdx);
  }

{'fraction_non_alphanumeric': 0.10113213923622845, 'fraction_numerical': 0.0032950321054410273, 'mean_word_length': 3.4003717472118957, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '261971', 'n_tokens_mistral': 3794, 'n_tokens_neox': 3673, 'n_words': 883}