/**
 * MouseController.java
 * (c) Peter Bielik and Radek Burget, 2011-2012
 *
 * SwingBox is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *  
 * SwingBox is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public License
 * along with SwingBox. If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package org.fit.cssbox.swingbox.util;

import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.JEditorPane;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.text.AttributeSet;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.Position;
import javax.swing.text.Position.Bias;
import javax.swing.text.StyledDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;

import org.fit.cssbox.layout.TextBox;
import org.fit.cssbox.swingbox.SwingBoxDocument;

/**
 * This class adds the "mouse support" to BrowserPane - generates
 * HyperlinkEvents.
 * 
 * @author Peter Bielik
 * @author Radek Burget
 */
public class MouseController extends MouseAdapter
{
    private static final Cursor defaultCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
    private static final Cursor textCursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
    
    private Element prevElem;
    private Anchor prevAnchor;

    @Override
    public void mouseClicked(MouseEvent e)
    {
        JEditorPane editor = (JEditorPane) e.getSource();

        if (!editor.isEditable() && SwingUtilities.isLeftMouseButton(e))
        {
            Bias[] bias = new Bias[1];
            Point pt = new Point(e.getX(), e.getY());
            int pos = editor.getUI().viewToModel(editor, pt, bias);

            if (bias[0] == Position.Bias.Backward && pos > 0) pos--;

            //Point pt = new Point(e.getX(), e.getY());
            //int pos = editor.viewToModel(pt);
            // System.err.println("found position : " + pos);
            if (pos >= 0)
            {
                Element el = ((SwingBoxDocument) editor.getDocument()).getCharacterElement(pos);
                AttributeSet attr = el.getAttributes();
                Anchor anchor = (Anchor) attr.getAttribute(Constants.ATTRIBUTE_ANCHOR_REFERENCE);

                if (anchor != null && anchor.isActive())
                    createHyperLinkEvent(editor, el, anchor, EventType.ACTIVATED);
            }
        }

    }

    @Override
    public void mouseMoved(MouseEvent e)
    {
        JEditorPane editor = (JEditorPane) e.getSource();

        if (!editor.isEditable())
        {
            Bias[] bias = new Bias[1];
            Point pt = new Point(e.getX(), e.getY());
            int pos = editor.getUI().viewToModel(editor, pt, bias);

            if (bias[0] == Position.Bias.Backward && pos > 0) pos--;

            if (pos >= 0 && (editor.getDocument() instanceof StyledDocument))
            {
                Element elem = ((StyledDocument) editor.getDocument()).getCharacterElement(pos);
                Object bb = elem.getAttributes().getAttribute(Constants.ATTRIBUTE_BOX_REFERENCE);
                Anchor anchor = (Anchor) elem.getAttributes().getAttribute(Constants.ATTRIBUTE_ANCHOR_REFERENCE);
                //System.out.println("Pos: " + pos);
                //System.out.println("Elem: " + elem.getAttributes().getAttribute(Constants.ATTRIBUTE_BOX_REFERENCE));
                //System.out.println("Anchor: " + anchor);

                if (elem != prevElem)
                {
                    prevElem = elem;
                    if (!anchor.isActive())
                    {
                        if (bb != null && bb instanceof TextBox)
                            setCursor(editor, textCursor);
                        else
                            setCursor(editor, defaultCursor);
                    }
                }
                
                if (anchor != prevAnchor)
                {
                    if (prevAnchor == null)
                    {
                        if (anchor.isActive())
                        {
                            createHyperLinkEvent(editor, elem, anchor, EventType.ENTERED);
                        }
                        prevAnchor = anchor;
                    }
                    else if (!prevAnchor.equalProperties(anchor.getProperties()))
                    {
                        if (prevAnchor.isActive())
                        {
                            createHyperLinkEvent(editor, prevElem, prevAnchor, EventType.EXITED);
                        }

                        if (anchor.isActive())
                        {
                            createHyperLinkEvent(editor, elem, anchor, EventType.ENTERED);
                        }
                        prevAnchor = anchor;
                    }

                }
            }
            else //nothing found
            {
                prevElem = null;
                if (prevAnchor != null && prevAnchor.isActive())
                {
                    createHyperLinkEvent(editor, prevElem, prevAnchor, EventType.EXITED);
                    prevAnchor = null;
                }   
                setCursor(editor, defaultCursor);
            }
        }
    }
    
    private void createHyperLinkEvent(JEditorPane editor, Element elem, Anchor anchor, EventType type)
    {
        HyperlinkEvent linkEvent;
        String href = anchor.getProperties().get(Constants.ELEMENT_A_ATTRIBUTE_HREF);
        String target = anchor.getProperties().get(Constants.ELEMENT_A_ATTRIBUTE_TARGET);
        URL url;
        URL base = (URL) editor.getDocument().getProperty(DefaultStyledDocument.StreamDescriptionProperty);
        try {
            url = new URL(base, href);
        } catch (MalformedURLException ignored) {
            url = null;
        }

        linkEvent = new HTMLFrameHyperlinkEvent(editor, type, url, href, elem, target);
        editor.fireHyperlinkUpdate(linkEvent);
    }
    
    protected void setCursor(JEditorPane editor, Cursor cursor)
    {
        if (editor.getCursor() != cursor)
        {
            editor.setCursor(cursor);
        }
    }
    
}