package scone.examples.rueckspiegel;


import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Enumeration;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFrame;
import javax.swing.JScrollPane;

import scone.Plugin;
import scone.Scone;
import scone.netobjects.AccessCache;
import scone.netobjects.AccessEvent;
import scone.netobjects.HtmlNode;
import scone.netobjects.HtmlNodeCache;
import scone.netobjects.SimpleUri;
import scone.robot.LinkClassifier;
import scone.robot.LinkFilter;
import scone.robot.NoHtmlNodeException;
import scone.robot.PageClassifier;
import scone.robot.QueueEntry;
import scone.robot.RobotHtmlNode;
import scone.robot.RobotLink;
import scone.robot.RobotTask;
import scone.robot.RobotUser;


/**
 * Rueckspiegel-Plugin for Scone
 * <P>
 * This Scone-Plugin uses the ability of the search-engine google to search for documents with links to a specified document.
 * Each time a new document is displayed in the browser google is asked for incoming links. These document are retrieved in the background and
 * displayed as thumbnail images.
 * <P>
 * <B>ATTENTION!</B> Google disallows the usage of its Web interface for robots.<BR>
 * Therefore we strongly, discourage from the usage of this plugin! If you use it, it is on your own risk and responsibility!
 *
 * @author Frank Wolenweber (Programming & Concept)
 * @author Harald Weinreich (Concept & Debugging)
 */


public class RueckspiegelPlugin extends Plugin implements Observer, RobotUser {

    private scone.robot.Robot robot; // Reference to the robot
    private JFrame f; // The visualization of the incoming links is displayed in this frame
    private JScrollPane scroller; // Used to scroll the visualization
    private DrawingArea drawingArea; // Displays the visualization
    private RobotTask rt = null; // This RobotTask is used to call google and retrive the documents
    private String currentUri = null; // The URI of the currently displayed document
    private String host = null; // Host of the currently displayed document
    private int thumbnails = 0; // Number of thumbnails

    private static final int MAX_THUMBNAILS = 5; // May be more, as Robot finishes crawling...

    /**
     * Default Constructor.
     */
    public RueckspiegelPlugin() {}

    /**
     * Scone requirements: Documents are parsed, Accessing is logged and Links and Incousions are considered...
     */
    public int getRequirements() {
        return PARSEDOCUMENT | ACCESSTRACKING | CONSIDERLINKS
                | CONSIDERINCLUSIONS;
    }

    /**
     * Setup Rueckspiegel
     *
     */
    public void init() {
        robot = scone.robot.Robot.instance();
        AccessCache.putObserver(this);
        f = new JFrame();
        f.setSize(230, Toolkit.getDefaultToolkit().getScreenSize().height - 40);
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                f.setVisible(false);
                // Now terminate Scone/WBI 10000 ms = 10s
                Scone.shutdownWBI(10000);
            }
        }
        );
        f.setBackground(Color.white);
        drawingArea = new DrawingArea();
        JScrollPane scroller = new JScrollPane(drawingArea);

        scroller.setBackground(Color.white);
        scroller.setOpaque(true);
        f.getContentPane().add(scroller);
        f.setTitle("Rueckspiegel 1.2");
        f.show();
    }

    /**
     * An Access-event occured: Clean Drawingarea and restart Robot.
     *
     */
    public void update(Observable o, Object arg) {

        if (o instanceof AccessCache) {
            AccessEvent e = (AccessEvent) arg;
            HtmlNode hNode = HtmlNodeCache.check(e.getNode());

            if (hNode == null) {
                System.out.println("Rueckspiegel -> hm, that wasn't a html page");
            } else {
//                if (e.getAccess().getAction() == 0
//                        && e.getAccess().getStayTime() == 0) { // Only consider first Access-Event
				if (!e.getAccess().getShown()) {  // Was this event already displayed?
                    e.getAccess().setShown(true); // Now it was... :-)
                    System.out.println("\nRueckspiegel ---> " + e.getUser().getUserName() + ": " + e.getNode().toString());
                    currentUri = e.getNode().toString();
                    try {
                        // Cleanup...
                        drawingArea.clean();
                        if (rt != null) {
                            // System.out.println(rt.getStartURI().toString() + " stopped");
                            robot.stopRobotTask(rt);
                        }
                        // Restart...
                        host = hNode.getSUri().getHost();
                        String googleSuche = "http://www.google.de/search?q=link:"
                                + hNode.getSUri().toString()
                                + "&hl=de&ie=ISO-8859-1&safe=off&btnG=Google-Suche&num=20";
                        SimpleUri uri = new SimpleUri(googleSuche);

                        thumbnails = 0;
                        // Go..
                        rt = new RobotTask(uri, 1, RobotTask.ALL, this);
                        rt.addPageClassifier(new RueckspiegelPageClassifier());
                        rt.addLinkClassifier(new RueckspiegelLinkClassifier());
                        rt.addLinkFilter(new RueckspiegelLinkFilter(host));
                        robot.scan(rt);
                    } catch (Exception ex) {
                        System.out.println("Rueckspiegel -> Invalid URL");
                    }
                }
            }
        }
    }

    /**
     * The robot calls this method for every new document
     * If it's not the Google result page the new thumbnail is added to the drawingArea.
     * @param robotHtmlNode the new htmlNode with some properties set by the robot
     * @param robotTask identifies the task which causes the robot to download robotHtmlNode.
     */
    public void robotNewPage(RobotHtmlNode robotHtmlNode, RobotTask robotTask) {
        if (robotTask == rt) {
            if (robotHtmlNode.getAttribute("GoogleResult") == "No") { // No Google-Result returned...
                if (thumbnails <= MAX_THUMBNAILS) {
                    thumbnails++;
                } else {
                    robot.stopRobotTask(rt); // Enough for this time...
                    System.out.println("Rueckspiegel -> Enough thumbnails...");
                }
                try {
                    drawingArea.newNode(robotHtmlNode.getHtmlNode());
                } catch (NoHtmlNodeException e) {}
            }
        }
    }

    /**
     * This method is called by the robot, if the task was completely finished
     * @param robotTask the robot finished this task
     */
    public void robotTaskFinished(RobotTask robotTask) {
        System.out.println("\nRueckspiegel -> Incoming Links for " + currentUri);
        Enumeration downloadedNodes = robotTask.getResultNodes();

        while (downloadedNodes.hasMoreElements()) {
            RobotHtmlNode robotHtmlNode = (RobotHtmlNode) downloadedNodes.nextElement();

            if (robotHtmlNode.getAttribute("GoogleResult") == "No") { // No Google-Result returned...
                System.out.println("Found:"+robotHtmlNode.getSimpleUri().toString());
            } else {
                System.out.println("Skipped:"+robotHtmlNode.getSimpleUri().toString());

            }
        }
        System.out.println("");
    }

    /**
     * This classifier checks for a link, if it is an internal google Link, or a link of the search result.
     */
    private class RueckspiegelLinkClassifier implements LinkClassifier {

        public void classify(RobotLink robotLink, RobotHtmlNode robotHtmlNode, QueueEntry qe) {
            String urlText = robotLink.getLink().getToNode().getUri();
            if (urlText.indexOf("google") != -1 || // And some well-known IP-Adress spaces that belong to Google...
            		urlText.indexOf("http://72")!=-1 || urlText.indexOf("http://66")!=-1 || urlText.indexOf("http://64")!=-1 || urlText.indexOf("http://209")!=-1) {
				// System.out.println("Google link:"+urlText);
                robotLink.setAttribute("GoogleLink", "Yes");
            }
        }
    }


    /**
     * Links, classified as google links, and links to documents on the same host
     * as the document currently displayed are filtered
     */
    private class RueckspiegelLinkFilter implements LinkFilter {

        private String host;

        public RueckspiegelLinkFilter(String host) {
            this.host = host;
        }

        public boolean filter(RobotLink robotLink, RobotHtmlNode robotHtmlNode, QueueEntry qe) {
            if (robotLink.getAttribute("GoogleLink") == "Yes") {
                return false;
            }
            if (robotLink.getLink().getToNode().getHost().equals(host)) {
                return false;
            } else {
                return true;
            }
        }
    }


    /**
     * Checks, if the documents currently processed by the robot is a google result page.
     */
    private class RueckspiegelPageClassifier implements PageClassifier {

        public void classify(RobotHtmlNode robotHtmlNode, QueueEntry qe) {
            String urlText = robotHtmlNode.getNetNode().getUri();

            if (urlText.indexOf("google") != -1) {
                robotHtmlNode.setAttribute("GoogleResult", "Yes");
            } else {
                robotHtmlNode.setAttribute("GoogleResult", "No");
            }
        }
    }
}
