package demo.view.viewmode;

import y.view.*;
import y.geom.YRectangle;
import demo.view.DemoBase;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.View;
import javax.swing.text.html.HTML;
import javax.swing.plaf.basic.BasicHTML;
import java.awt.*;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;


/**
 * Demonstrates how to detect a double click on a hyperlink that is part of a  HTML label.
 */
public class HyperlinkHitDemo extends DemoBase {
  public HyperlinkHitDemo() {

    String text = "<html>I<br>love<br><a href=\"http://www.yworks.com\">yWorks</a><br>and<br><a href=\"http://www.yfiles.com\">yFiles</a>";
    NodeRealizer nr = view.getGraph2D().getDefaultNodeRealizer();
    nr.getLabel().setBackgroundColor(Color.ORANGE);
    nr.getLabel().setFontSize(16);
    nr.setSize(200,200);
    nr.setLabelText(text);
  }

  protected EditMode createEditMode() {
    EditMode editMode = new EditMode() {

      public void mouseClicked(double x, double y) {
        super.mouseClicked(x, y);

        if(lastClickEvent.getClickCount() != 2) return;

        HitInfo hitInfo = new HitInfo(getGraph2D(),x,y, HitInfo.NLABEL);
        NodeLabel nl = hitInfo.getHitNodeLabel();
        if(nl != null) {
          String text = nl.getText();
          if((BasicHTML.isHTMLString(text))) {
            JLabel label = new JLabel();
            label.setText(nl.getText());
            label.setFont(nl.getFont().deriveFont(nl.getFont().getSize2D()*(float)view.getZoom()));
            Dimension dim = label.getPreferredSize();
            label.setSize(dim.width, dim.height);
            YRectangle box = nl.getBox();
            int vx = view.toViewCoordX(x);
            int vy = view.toViewCoordX(y);
            Rectangle bounds = new Rectangle(view.toViewCoordX(box.x),view.toViewCoordY(box.y),label.getWidth(), label.getHeight());
            View htmlView = BasicHTML.createHTMLView(label, text);
            Document doc = htmlView.getDocument();

            Element[] rootElements = doc.getRootElements();
            ArrayList hrefElements = new ArrayList();
            for(int i = 0; i < rootElements.length; i++) {
              traceHREFs(rootElements[i], 0, hrefElements);
            }


            for(int i = 0; i < hrefElements.size(); i++) {
              Element element = (Element) hrefElements.get(i);
              Object href = getAttrValue(element.getAttributes(), HTML.Attribute.HREF);
              try {
                Shape shape = htmlView.modelToView(element.getStartOffset(), Position.Bias.Forward, element.getEndOffset(), Position.Bias.Forward, bounds);
                //System.out.println("shape = " + shape + " href=" + href);
                if(shape.contains(vx,vy)) {
                  System.out.println("hit href = " + href);
                }
              } catch (BadLocationException e) {
                e.printStackTrace();
              }
            }
          }
        }
      }
    };
    return editMode;
  }

  void traceHREFs(Element element, int depth, List hrefElements) {
    Object href = getAttrValue(element.getAttributes(), HTML.Attribute.HREF);
    if(href != null) {
      hrefElements.add(element);
    }
    for(int i = 0; i < element.getElementCount(); i++) {
      traceHREFs(element.getElement(i), depth+1, hrefElements);
    }
  }

  /**
   * Returns the object in an AttributeSet matching a key
   */
  private static Object getAttrValue(AttributeSet attr, HTML.Attribute key) {
    Enumeration names = attr.getAttributeNames();
    while (names.hasMoreElements()) {
      Object nextKey = names.nextElement();
      Object nextVal = attr.getAttribute(nextKey);
      if (nextVal instanceof AttributeSet) {
        Object value = getAttrValue((AttributeSet) nextVal, key);
        if (value != null) {
          return value;
        }
      } else if (nextKey == key) {
        return nextVal;
      }
    }
    return null;
  }

  public static void main( String[] args ) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        initLnF();
        (new HyperlinkHitDemo()).start();
      }
    });
  }
}
