/*
 * Scone - The Web Enhancement Framework
 * Copyright (C) 2009 Harald Weinreich, Volkert Buchmann, Frank Wollenweber, Torsten Haß
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package scone.examples.servlink;

import java.util.Enumeration;
import java.util.Vector;

import scone.netobjects.HtmlNode;
import scone.netobjects.HtmlNodeCache;
import scone.netobjects.LinkCache;
import scone.netobjects.LinkToken;
import scone.netobjects.NetNode;
import scone.proxy.HtmlTokenEditor;
import scone.util.ErrorLog;
import scone.util.Google;
import scone.util.tokenstream.HtmlTagToken;
import scone.util.tokenstream.HtmlTextToken;
import scone.util.tokenstream.SconePipe;
import scone.util.tokenstream.Token;
import scone.util.tokenstream.TokenInputStream;
import scone.util.tokenstream.TokenOutputStream;

/**
 * is a Sscone-plugin, that creates ``multilink´´-tags to allow multiple destinations
 * for World Wide Web links. These ``multilinks´´ are requested from Google. To let this
 * plugin work, please get a valid key from http://www.google.com/apis/ and store it
 * in the plugins configuration file.
 * <P>
 * You can use this plugin either on server- or on client side. If you use it on server side 
 * please enable and configure the ServerSide-Plugin as well. 
 * <P>
 * The BuildPopupClientside-Plugin is needed to visualize these multilinks.
 * <P>
 * ATTENTION: This plugin is sloooow, as for the many requests to Google! Please be patient!
 *
 * @author Volkert Buchmann
 */
public class MultilinkExpander extends scone.Plugin{
   public static final String COPYRIGHT="(C) Volkert Buchmann";

   String googleKey=null;

   public final static int MAXLINKS=4;

   //requirements
   public int getRequirements(){
      return PARSEDOCUMENT | CONSIDERLINKS ;
   }

    public void init(){
        try{
            googleKey=getProperties().get("Google key");
            System.out.println("\n   Google key found:"+googleKey);

            Expander x=new Expander();
            x.setup("Expander",HTDOCCONDITION,60);
            addMeg(x);

        } catch(Exception e) {
            ErrorLog.log(this,"init()","Could not init MultilinkExpander plugin!",e);
            System.out.println("Could not init MultilinkExpander plugin! Please check if valid Google key exists in config-file");
        }
    }

    public void terminate(){
        ErrorLog.print(":-) it worked!");
    }


    /**
     * expands links
     */
    class Expander extends HtmlTokenEditor{

        public void handleRequest(SconePipe pipe){
            try{
                TokenInputStream in=pipe.getTokenInputStream();
                TokenOutputStream out=pipe.getTokenOutputStream();

                LinkToken lt=null;
                HtmlTagToken tag=null;
                Token t=null;
                boolean inLink=false;
                String linkText="";
                while((t=in.read())!=null){

                    // Openeing links
                    if((t instanceof LinkToken)){
                        lt=(LinkToken)t;
                        if(lt.getTagType()==tag.T_A && 
                             lt.getParam("href") != null &&
                             !lt.getParam("href").startsWith("mailto:") &&
                             !lt.getParam("href").startsWith("ftp:") &&
                             !lt.getParam("href").startsWith("#") ){
                            inLink=true;
                            linkText="";
                            continue;
                        }
                    }//instanceof LinkToken

                    // closing links
                    if(inLink){
                        //we simply assume that a-elements are not nested
                        //and that there are no area-elements
                        if((t instanceof HtmlTagToken)){
                            tag=(HtmlTagToken)t;
                            if(tag.getTagType()==tag.T_A) {
                                //now generate the multiple link
                                out.write(new HtmlTextToken("&nbsp;"));
                                out.write(new HtmlTagToken("multilink"));
                                out.write(new HtmlTagToken("starting_resource"));
                                out.write(new HtmlTextToken(linkText));
                                out.write(new HtmlTagToken("/starting_resource"));
                                tag=new HtmlTagToken("original");
                                tag.setParam("xlink:href",lt.getParam("href"));
                                out.write(tag);
                                out.write(new HtmlTagToken("title"));
                                out.write(new HtmlTextToken(linkText));
                                out.write(new HtmlTagToken("/title"));
                                out.write(new HtmlTagToken("/original"));

                                addRelated(lt.getLink().getToNode(),out);

                                out.write(new HtmlTagToken("/multilink"));
                                out.write(new HtmlTextToken("&nbsp;"));

                                inLink=false;
                                continue;
                            }
                        }
                        linkText+=t.toString();
                        continue;
                    }

                    out.write(t);
                }//while
            } catch(Exception exc) {
                 ErrorLog.log(this,"handleRequest()","",exc);
            }
        }

        /**
         *
         */
        public void addRelated(NetNode node, TokenOutputStream out){

            // System.out.println("addRelated:"+node.getUri());

            scone.netobjects.Link link=null;
            HtmlNode hNode=null;
            NetNode n=null;
            Enumeration en=null;
            Vector nodes=null;

            try{
                //now this is some evil stuff, do not do this at home!
                //get all the related-links
                Vector links=LinkCache.getLinks("where fromNodeId='"+node.getNodeId()+"' and rel='related'");

                //if we can't get any links from the db, fetch the documents from google and create the links
                if(links.size()==0){
                    System.out.println("addRelated: request ->"+node.getUri());
                    Google google=new Google(googleKey);
                    nodes=google.getRelated(node.getUri(),MAXLINKS);
                    for (en = nodes.elements() ; en.hasMoreElements() ;) {
                        hNode=(HtmlNode)en.nextElement();
                        link=LinkCache.get(node,hNode.getNode(),"");
                        //set the rel type to "related", this is not in the spec though
                        link.setRel("related");
                    }
                } else {
                    nodes=new Vector();
                    for (en = links.elements() ; en.hasMoreElements() ;) {
                        link=(scone.netobjects.Link)en.nextElement();
                        if(link!=null && (n=link.getToNode())!=null)
                            if(HtmlNodeCache.check(n)!=null)
                                nodes.addElement(HtmlNodeCache.check(n));
                    }
                }


                //now nodes contains a list of htmlnodes
                HtmlTagToken tag=null;
                for (en = nodes.elements() ; en.hasMoreElements() ;) {
                    hNode=(HtmlNode)en.nextElement();
                    if(!node.getUri().equals(hNode.getUri())){
                        tag=new HtmlTagToken("alternative");
                        tag.setParam("xlink:href",hNode.getUri());
                        out.write(tag);
                        out.write(new HtmlTagToken("title"));
                        out.write(new HtmlTextToken(hNode.getTitle()));
                        out.write(new HtmlTagToken("/title"));
                        out.write(new HtmlTagToken("/alternative"));
                    }
                }

            } catch(Exception ex2) {
                ex2.printStackTrace();
            }
            // System.out.println("addRelated: related done");
        }
    }
}
