package levik.weblet.lh;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import freemarker.template.*;
import levik.servlet.util.*;
import levik.util.*;
import levik.banner.*;

public class LoveHate extends HttpServlet {
    protected TemplateCache templateCache;
    ResourceBundle config= ResourceBundle.getBundle("LoveHate");
    protected FeelingServer server;
    protected Vector loveFeelings;
    protected Vector hateFeelings;
    protected Vector feelingStats;
    protected int maxFeelings;
    protected int globalLoveNum;
    protected int globalHateNum;
    protected BannerSource ads;
    protected SaveTimer timer;
    protected int topFeelings;
    protected JSEncoder encoder;

    public LoveHate() {
	super();
	init();
    }

    public void init() {
	try {
	    System.err.println("LoveHate servlet init...");
		if (config==null)
	    	    config = ResourceBundle.getBundle("LoveHate");
	    System.err.println("Got config bundle...");
	    server = new FeelingServer(config);
	    System.err.println("Started feeling server...");
	    System.err.println("Template path is "+config.getString("TEMPLATE_PATH"));
	    templateCache = new FileTemplateCache(config.getString("TEMPLATE_PATH"));
	    maxFeelings = Integer.parseInt(config.getString("MAX_FEELINGS"));
	    topFeelings = Integer.parseInt(config.getString("TOP_FEELINGS"));
	    ads = new LEBannerSource(config.getString("LE_ACCOUNT"));
	    FeelingSet temp = server.get();
	    loveFeelings = temp.getLoves();
	    hateFeelings = temp.getHates();
	    globalLoveNum = temp.getLoveNum();
	    globalHateNum = temp.getHateNum();
	    timer=new SaveTimer(1000*60*10);
	    feelingStats=new Vector();
	    encoder = new JSEncoder();
	    loadStats();
	    timer.start();
	}
	catch (Exception e) {
	    System.err.println("Error..");
	    e.printStackTrace();
	}
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException,IOException {
	if (request.getParameter("action")==null) {
	    showPage(request,response,request.getParameter("object"));
	} else if (request.getParameter("action").equals("save")) {
	    saveSelf();
	    response.getWriter().write("Saved.");
	} else if (request.getParameter("action").equals("synd")) {
	    syndicate(request, response);
	} else {
	    updateFeelings(request,response);
	    response.sendRedirect(config.getString("SERVLET_PATH")+"?");
	}
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
	throws ServletException,IOException {
	doGet(request,response);
    }	       

    protected void syndicate(HttpServletRequest request, 
			     HttpServletResponse response) throws IOException{
	SimpleHash root = new SimpleHash();
	if (request.getParameter("lc") != null) {
		root.put("lc", request.getParameter("lc"));
	}
	root.put("config",new RBHash(config));
	root.put("encode", encoder);
	String object = request.getParameter("object");
	String type = request.getParameter("feeling");
	Vector loves;
	Vector hates;
	if (object==null) {
	    loves=loveFeelings;
	    hates=hateFeelings;
	} else {
	    root.put("object",object);
	    root.put("encobject", java.net.URLEncoder.encode(object));
	    FeelingSet feelings = server.get(object);
	    loves=feelings.getLoves();
	    hates=feelings.getHates();
	    root.put("love_num", ""+feelings.getLoveNum());
	    root.put("hate_num", ""+feelings.getHateNum());
	}
	Feeling love = null;
	Feeling hate = null;
	if (loves.size() > 0) love = (Feeling)loves.get(0);
	if (hates.size() > 0) hate = (Feeling)hates.get(0);

	if (type == null) {
	    if (love != null && hate != null) {
		if (love.date.getTime() < hate.date.getTime()) {
		    root.put("feeling", hate);
		    root.put("f", "h");
		} else {
		    root.put("feeling", love);
		    root.put("f", "l");
		}
	    } else if (love == null && hate != null) {
		root.put("feeling", hate);
		root.put("f", "h");
	    } else if (love != null && hate == null) {
		root.put("feeling", love);
		root.put("f", "l");
	    }
	} else if (type.equals("l") && love != null) {
	    root.put("feeling", love);
	    root.put("f", "l");
	} else if (type.equals("h") && hate != null) {
	    root.put("feeling", hate);
	    root.put("f", "h");
	}
	response.setContentType("application/x-javascript");
	Template template = templateCache.getTemplate("syndicate.html");
	template.process(root, response.getWriter());
    }

    protected void updateFeelings(HttpServletRequest request, HttpServletResponse response) {
	String object = request.getParameter("object");
	if (object==null) return;
	String action = request.getParameter("action");
	if (action==null) return;
	Vector feelings;
	Vector topicFeelings;
	FeelingSet feelingSet = server.get(object);
	int loveNum = ServletUtil.getIntValueFromCookie(request,"love_num",0);
	int hateNum = ServletUtil.getIntValueFromCookie(request,"hate_num",0);
	if (action.equals("love")) {
	    feelings=loveFeelings;
	    topicFeelings=feelingSet.getLoves();
	    loveNum++;
	    feelingSet.incLoveNum();
	    globalLoveNum++;
	}
	else if (action.equals("hate")) {
	    feelings=hateFeelings;
	    topicFeelings=feelingSet.getHates();
	    hateNum++;
	    feelingSet.incHateNum();
	    globalHateNum++;
	}
	else return;
	processStats(feelingSet);
	feelingSet.setChanged(true);
	String name = request.getParameter("name");

	if (name!=null && name.length()>0) {
	    Cookie cookie = new Cookie("name",java.net.URLEncoder.encode(name));
	    cookie.setMaxAge(60*60*24*30);
	    System.err.println(cookie.getName()+" = "+cookie.getValue()+" to response object "+response.toString());
	    response.addCookie(cookie);
	}
	    
	Feeling feeling;
	try {
	    feeling= new Feeling(request.getParameter("name"),
				 object,
				 request.getParameter("reason"));	
	} catch (Exception e) {
	    feeling=null;
	}
	if (feeling!=null) {
	    feelings.insertElementAt(feeling,0);
	    topicFeelings.insertElementAt(feeling,0);
	    while (feelings.size()>maxFeelings)
		feelings.removeElementAt(feelings.size()-1);
	    while (topicFeelings.size()>maxFeelings)
		topicFeelings.removeElementAt(topicFeelings.size()-1);
	    Cookie loveCookie=new Cookie("love_num",""+loveNum);
	    loveCookie.setMaxAge(60*60*24*30);
	    response.addCookie(loveCookie);
	    Cookie hateCookie=new Cookie("hate_num",""+hateNum);
	    hateCookie.setMaxAge(60*60*24*30);
	    response.addCookie(hateCookie);
	}
    }

    protected void showPage(HttpServletRequest request, HttpServletResponse response) 
	throws IOException {
	showPage(request,response,null);
    }

    protected void showPage(HttpServletRequest request, HttpServletResponse response, String thing) 
	throws IOException {
	SimpleHash root = new SimpleHash();
	response.setContentType("text/html");

	Vector loves=null;
	Vector hates=null;
	if (thing==null) {
	    loves=loveFeelings;
	    hates=hateFeelings;
	} else {
	    root.put("object",thing);
	    FeelingSet feelings = server.get(thing);
	    processStats(feelings);
	    loves=feelings.getLoves();
	    hates=feelings.getHates();
	    root.put("topic_love_num",""+feelings.getLoveNum());
	    root.put("topic_hate_num",""+feelings.getHateNum());
	}
	root.put("global_love_num",""+globalLoveNum);
	root.put("global_hate_num",""+globalHateNum);

	int  loveNum = ServletUtil.getIntValueFromCookie(request,"love_num",0);
	int  hateNum = ServletUtil.getIntValueFromCookie(request,"hate_num",0);
	
	if (loveNum>hateNum)
	    root.put("def_action","love");
	if (hateNum>loveNum)
	    root.put("def_action","hate");
	root.put("cookies",new CookieHash(request,true));
	root.put("config",new RBHash(config));
	root.put("ads",ads);
	root.put("top", TemplateUtil.toSimpleList(feelingStats));
	root.put("loves",TemplateUtil.toSimpleList(loves));
	root.put("hates",TemplateUtil.toSimpleList(hates));
	Template template = templateCache.getTemplate("index.html");
	template.process(root, response.getWriter());
    }

    public void saveSelf() {
	System.err.println("Saving everything...");
	FeelingSet temp = new FeelingSet(Feeling.class,loveFeelings,hateFeelings);
	temp.setLoveNum(globalLoveNum);
	temp.setHateNum(globalHateNum);
	temp.setChanged(true);
	server.saveFeelings(temp);
	saveStats();
	server.saveAllCached();
    }

    public void processStats(FeelingSet fs) {
	for (int i=0; i<topFeelings; i++) {
	    FeelingStat oneStat=null;
	    try {
		oneStat=(FeelingStat)feelingStats.elementAt(i);
	    } catch (Exception e) {		
		feelingStats.insertElementAt(new FeelingStat(fs),i);
		return;
	    }
	    if (oneStat==null) {
		feelingStats.insertElementAt(new FeelingStat(fs),i);
		return;
	    }
	    if (oneStat.sameAs(fs)) {
		oneStat.update(fs);
		return;
	    }
	    if (oneStat.isLessThan(fs)) {
		feelingStats.insertElementAt(new FeelingStat(fs),i);
		for (int j=i+1; j<topFeelings; j++) {
		    try {
		    	oneStat=(FeelingStat)feelingStats.elementAt(j);
		    } catch (Exception e) {
		        break;
		    }
		    if (oneStat==null) break;
		    if (oneStat.sameAs(fs)) {
			feelingStats.removeElementAt(j);
			break;
		    }
		}
		while (feelingStats.size()>topFeelings)
		    feelingStats.removeElementAt(feelingStats.size()-1);
		return;
	    }
	}
    }

    public void destroy() {
	saveSelf();
	timer.die();
    }

    public void loadStats() {
	try {
	    String filePath=config.getString("STATS_FILE");
	    InputStream in=new FileInputStream(filePath);
	    ObjectInputStream objIn = new ObjectInputStream(in);
	    feelingStats=(Vector)objIn.readObject();
	    in.close();
	}
	catch (Exception e) {
	    e.printStackTrace();
	}
    }

    public void saveStats() {
	try {
	    String filePath=config.getString("STATS_FILE");
	    OutputStream out = new FileOutputStream(filePath);
	    ObjectOutputStream objOut = new ObjectOutputStream(out);
	    objOut.writeObject(feelingStats);
	    objOut.close();
	    out.close();
	}
	catch (Exception e) {
	    e.printStackTrace();
	}
    }

    class SaveTimer extends Thread {
	protected int timeOut;
	protected boolean keepRunning;

	SaveTimer(int timeOut) {
	    this.timeOut=timeOut;
	    keepRunning=true;
	}
	
	public void die() {
	    keepRunning=false;
	    interrupt();
	}

	public void run() {
	    while (true) {
		try {
		    Thread.sleep(timeOut);
		} catch (InterruptedException ie) {
		    if (!keepRunning) 
			break;
		}
		saveSelf();
	    }
	}
    }
}
