package org.broad.igv.ui;

import org.broad.igv.util.BrowserLauncher;
import org.broad.igv.util.HttpUtils;

import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;

/**
 * @author Jim Robinson
 * @date 11/7/11
 */
public class TooltipTextFrame extends JFrame {


    private static final DataFlavor[] supportedFlavors;

    static {
        try {
            supportedFlavors = new DataFlavor[]{
                    new DataFlavor("text/html;class=java.lang.String"),
                    new DataFlavor("text/plain;class=java.lang.String")
            };
        } catch (ClassNotFoundException e) {
            throw new ExceptionInInitializerError(e);
        }
    }


    public TooltipTextFrame(String title, String text) throws HeadlessException {

        setTitle(title);

        //setUndecorated(true);
        setAlwaysOnTop(true);


        setLayout(new BorderLayout());

        JEditorPane pane = new JEditorPane("text/html", text);
        pane.setEditable(false);
        pane.setTransferHandler(new MyTransferHandler());

        Dimension d = pane.getPreferredSize();
        int w = (int) (1.1 * d.width);
        int h = (int) (1.1 * d.height);

        h = h > 600 ? 600 : (h < 100 ? 100 : h);
        w = w > 800 ? 800 : (w < 100 ? 100 : w);
        setSize(w, h);


        JScrollPane scrollPane = new JScrollPane(pane);

        MouseAdapter mouseAdapter = new MouseAdapter() {

            private Point point = new Point();

            @Override
            public void mouseDragged(MouseEvent e) {
                Point p = getLocation();
                final int dx = e.getX() - point.x;
                final int dy = e.getY() - point.y;
                setLocation(p.x + dx, p.y + dy);
            }

            @Override
            public void mousePressed(MouseEvent e) {
                point.x = e.getX();
                point.y = e.getY();
            }
        };

        pane.addMouseListener(mouseAdapter);

        pane.addMouseMotionListener(mouseAdapter);

        pane.addHyperlinkListener(new HyperlinkListener() {
            public void hyperlinkUpdate(HyperlinkEvent e) {
                try {
                    if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
                        BrowserLauncher.openURL(e.getURL().toExternalForm());
                } catch (IOException e1) {
                    e1.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }
        });

        getContentPane().add(scrollPane, BorderLayout.CENTER);
    }


    /**
     * Custom transfer handler that preserves line breaks in html when copying to clipboard
     */
    class MyTransferHandler extends TransferHandler {

        protected Transferable createTransferable(JComponent c) {
            final JEditorPane pane = (JEditorPane) c;
            final String htmlText = pane.getText();
            final String plainText = extractText(new StringReader(htmlText));
            return new MyTransferable(plainText, htmlText);
        }

        public String extractText(Reader reader) {
            final ArrayList<String> list = new ArrayList<String>();

            HTMLEditorKit.ParserCallback parserCallback = new HTMLEditorKit.ParserCallback() {
                public void handleText(final char[] data, final int pos) {
                    list.add(new String(data));
                }

                public void handleStartTag(HTML.Tag tag, MutableAttributeSet attribute, int pos) {
                }

                public void handleEndTag(HTML.Tag t, final int pos) {
                }

                public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, final int pos) {
                    if (t.equals(HTML.Tag.BR)) {
                        list.add("\n");
                    }
                }

                public void handleComment(final char[] data, final int pos) {
                }

                public void handleError(final String errMsg, final int pos) {
                }
            };
            try {
                new ParserDelegator().parse(reader, parserCallback, true);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String result = "";
            for (String s : list) {
                result += s;
            }
            return result;
        }


        @Override
        public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException {
            if (action == COPY) {
                clip.setContents(this.createTransferable(comp), null);
            }
        }

        @Override
        public int getSourceActions(JComponent c) {
            return COPY;
        }

    }

    class MyTransferable implements Transferable {


        private final String plainData;
        private final String htmlData;

        public MyTransferable(String plainData, String htmlData) {
            this.plainData = plainData;
            this.htmlData = htmlData;
        }

        public DataFlavor[] getTransferDataFlavors() {
            return supportedFlavors;
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            for (DataFlavor supportedFlavor : supportedFlavors) {
                if (supportedFlavor == flavor) {
                    return true;
                }
            }
            return false;
        }

        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if (flavor.equals(supportedFlavors[0])) {
                return htmlData;
            }
            if (flavor.equals(supportedFlavors[1])) {
                return plainData;
            }
            throw new UnsupportedFlavorException(flavor);
        }
    }


    public static void main(String[] args) throws IOException {

        test3();
        //omaTest();

    }

    private static void test3() {

        JFrame frame = new JFrame();
        frame.setSize(300, 300);
        JLabel label = new JLabel("Hello");
        label.setToolTipText("<html><b><i>Hello Word</b></i><br> " +
                "<a href=\"http://www.google.com\">Google</a><br>\n");
        frame.add(label);
        frame.setVisible(true);

    }

    private static void test1() {
        StringBuffer text = new StringBuffer("<html><b><i>Hello Word</b></i><br> " +
                "<a href=\"http://www.google.com\">Google</a><br>\n");
        for (int i = 0; i < 100; i++) {
            for (int j = 0; j < 40; j++) {
                text.append("blah ");
            }
            text.append("<div style=\"color:red\"> .....</div>");
            text.append("<br>\n");
        }
        text.append("</html>");

        TooltipTextFrame frame = new TooltipTextFrame("test", text.toString());
        frame.setVisible(true);

    }

    public static void omaTest() throws IOException {
        String url = "http://mutationassessor.org/v1/?cm=var&var=hg18,7,55178574,G,A&frm=txt";
        String result = HttpUtils.getInstance().getContentsAsString(new URL(url));

        BufferedReader br = new BufferedReader(new StringReader(result));
        String[] headers = br.readLine().split("\t");
        String[] values = br.readLine().split("\t");

        StringBuffer buf = new StringBuffer();
        buf.append("<html>");

        buf.append("<table>");
        int n = Math.min(headers.length, values.length);
        for (int i = 0; i < n; i++) {
            buf.append("<tr>");
            buf.append("<td>");
            final String header = headers[i];
            buf.append(header);
            buf.append("</td>");

            if (header.equals("MSA") || header.equals("PDB")) {
                buf.append("<a href=\"http://" + values[i] + "\">");
                buf.append(header);
                buf.append("</a>");
            } else if (header.equals("Uniprot")) {
                buf.append("<a href=\"http://www.uniprot.org/uniprot/" + values[i] + "\">");
                buf.append(values[i]);
                buf.append("</a>");
            } else if (header.equals("Refseq")) {
                buf.append("<a href=\"http://www.ncbi.nlm.nih.gov/sites/entrez?db=protein&cmd=search&term=" + values[i] + "\">");
                buf.append(values[i]);
                buf.append("</a>");
            } else {
                buf.append(values[i]);
            }
            buf.append("</td></tr>");
        }
        buf.append("</table>");


        TooltipTextFrame frame = new TooltipTextFrame("test", buf.toString());
        frame.setVisible(true);

    }
}
