package org.jcon.ui.comp;

import org.jcon.ui.VisualLib;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JComponent;

/**
* This class simulates a hyperlink. Features include an
* underline, mouseover effect, mouseover event, click
* event, click cue.
*
* @author Jack Harich
*/  

// NOTE - id no longer needed,
//        mouseover event not yet implemented ***
public class Hyperlink extends JComponent
    implements DoClickable {

//---------- Private Fields ------------------------------
// Properties
private String         text;
private String         infoText;
private String         command;
private String         id;
private ActionListener actionListener;
private ImageIcon      icon;
// Internal
private boolean        mouseOver;
private boolean        mousePressed;
private Component      mousePressedComponent;
private boolean        initialized;

private static final   int VGAP = 20; 
private static final   int START_GAP = 3;
private static final   int END_GAP = 4;
private static final   int ICON_GAP = 6;

//---------- Initialization ------------------------------
public Hyperlink() {
    enableEvents(AWTEvent.MOUSE_EVENT_MASK);
    enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
//---------- Superclass Overrides ------------------------
public void paint(Graphics g) {
    //----- Prep
    Rectangle b = getBounds();
    int myWidth = b.width;
    int myHeight = b.height;
    g.clearRect(0, 0, myWidth, myHeight);
    int offset = (mousePressed ? 2 : 0);
    int iconOffset = 0;
    //----- Mouseover rectangle
    if (mouseOver) {
        g.setColor(getBackground().darker());
        g.drawRect(0, 0, myWidth - 1, myHeight - 1);
    }  
    //----- Icon
    if (icon != null) {
        int y = (myHeight - icon.getIconHeight()) / 2;
        icon.paintIcon((Component)this, g,
            START_GAP + offset, y + offset); 
        iconOffset = icon.getIconWidth() + ICON_GAP;
    }    
    //----- Text
    FontMetrics metrics = g.getFontMetrics();
    Color foreColor = Color.blue;
    if (mouseOver) foreColor = foreColor.darker();
    g.setColor(foreColor);
    int yOffset = (VGAP / 2) - 1;
    // drawString(String, x, y)
    g.drawString(text, offset + iconOffset, metrics.getLeading()
        + metrics.getAscent() + offset + yOffset);
    // Underline to simulate hyperlink (x1, y1, x2, y2)
    int y = metrics.getHeight() - metrics.getDescent()
        + 2 + offset + yOffset;
    int startX = offset + iconOffset + 4;
    g.drawLine(startX, y, 
        startX + metrics.stringWidth(text) - 5, y);
}
public Dimension getPreferredSize() {
    if (! initialized) {
       this.setFont(VisualLib.createLargerFont(this, 2));
       initialized = true;
    }
    Font font = getFont();
    if (font == null) {
         return new Dimension(100, 15); // A guess
    } else {
         FontMetrics metrics = getFontMetrics(font);
         int width = metrics.stringWidth(text) + END_GAP;
         int height = metrics.getHeight() + VGAP;
         if (icon != null) {
             width += icon.getIconWidth() + ICON_GAP;
             if (icon.getIconHeight() + VGAP > height) {
                 height = icon.getIconHeight() + VGAP;
             }
         }
         return new Dimension(width, height);
      }    
}
public Dimension getMinimumSize() {
    return getPreferredSize();
}
//---------- MouseEvents ---------------------------------
public void processMouseEvent(MouseEvent evt) {
    if (evt.getID() == MouseEvent.MOUSE_PRESSED) {
        //requestFocus();
        mousePressedComponent = evt.getComponent();
        mousePressed = true;
        repaint();

    } else if (evt.getID() == MouseEvent.MOUSE_RELEASED) {
        mousePressedComponent = null;
        if (mousePressed == true) {
            fireActionEvent("Command", evt);  
        }
        mousePressed = false;  
        repaint();

    } else if (evt.getID() == MouseEvent.MOUSE_ENTERED) { 
        mouseOver = true;        
        if (mousePressedComponent == evt.getComponent()
                && mousePressed == false) {    
            mousePressed = true;
        }
        repaint();
        fireActionEvent("MouseEntered", evt);
        
    } else if (evt.getID() == MouseEvent.MOUSE_EXITED) {
        mouseOver = false;
        if (mousePressed == true) {
            mousePressed = false;
        }
        repaint();
        fireActionEvent("MouseExited", evt);
    }
    super.processMouseEvent(evt);
}
private void fireActionEvent(String option, MouseEvent evt) {
    if (actionListener == null) {
        print(".fireActionEvent() - No actionListener");
    } else {
        //print(".fireActionEvent() - Firing option " + option);
        ActionEvent event = new ActionEvent(
            this, ActionEvent.ACTION_PERFORMED,
            option, evt.getModifiers());
        actionListener.actionPerformed(event);
    }
}
public void processMouseMotionEvent(MouseEvent evt) {
    if (evt.getID() == MouseEvent.MOUSE_DRAGGED) {
        if (mousePressedComponent == evt.getComponent() &&
                ! contains(evt.getX(), evt.getY()) &&
                mousePressed == true) {
                
           mousePressed = false;
           repaint();
           
        } else if (mousePressedComponent == evt.getComponent()
                && contains(evt.getX(), evt.getY()) &&
                mousePressed == false) {
        
           mousePressed = true;
           repaint();
        }
    }
    super.processMouseMotionEvent(evt);
}
//---------- DoClickable Implementation ------------------
public void doClick(int pressTime) {
    MouseEvent evt;
    Dimension size = getSize();
    // Simulate Mouseover with slight pause
    evt = createMouseEvent(MouseEvent.MOUSE_ENTERED);
    processMouseEvent(evt);
    paintImmediately(0, 0, size.width, size.height); 
    sleep(100);
    // Before pressTime
    evt = createMouseEvent(MouseEvent.MOUSE_PRESSED);
    processMouseEvent(evt);
    paintImmediately(0, 0, size.width, size.height);
    // Do pressTime
    sleep(pressTime);
    // After pressTime  
    evt = createMouseEvent(MouseEvent.MOUSE_RELEASED);
    processMouseEvent(evt);
    paintImmediately(0, 0, size.width, size.height);
    sleep(100);
    // Simulate mouse exit
    evt = createMouseEvent(MouseEvent.MOUSE_EXITED);
    processMouseEvent(evt);
    paintImmediately(0, 0, size.width, size.height); 
    sleep(100);    
}
private MouseEvent createMouseEvent(int eventType) {
    MouseEvent evt = new MouseEvent(
        this, // Component source
        eventType, // int id
        System.currentTimeMillis(), // long when
        0, // int modifiers, a guess ******
        0, 0, // int x, y for position
        1, // int clickCount
        false // boolean popupTrigger
        );
    return evt;
}
private void sleep(int time) {
    try {
        Thread.currentThread().sleep(time);
    } catch(InterruptedException ie) {
        // Ignore
    }

}
//---------- Properties ----------------------------------
public void setActionListener(ActionListener listener) {
    actionListener = listener;
}
public void setText(String text) {
    this.text = text;
}
public void setIcon(ImageIcon icon) {
    this.icon = icon;
}
public Component getComponent() {
    return (Component)this;
}
//----- command
public void setCommand(String command) {
    this.command = command;
}
public String getCommand() {
    return command;
}
//----- id
public void setID(String id) {
    this.id = id;
}
public String getID() {
    return id;
}
//----- infoText
public void setInfoText(String infoText) {
    this.infoText = infoText;
}
public String getInfoText() {
    return infoText;
}
//---------- Private Methods -----------------------------
//--- Std
private static void print(String text) {
    System.out.println("Hyperlink" + text);
}

} // End class
