package de.uka.ipd.consensus.test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.tm4j.topicmap.TopicMap;

import de.snailshell.consensus.demo.ConsensusFoundationUtils;
import de.uka.ipd.consensus.foundation.ConsensusFoundation;
import de.uka.ipd.consensus.foundation.logging.LoggingManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyManager;
import de.uka.ipd.consensus.foundation.query.QueryEngine;
import de.uka.ipd.consensus.foundation.schema.User;
import de.uka.ipd.consensus.impl.OntologyManagerImpl;

/**
 * <p>Warning: This performance test creates 1000 topics (ids "__test_id_N" for N=0..999),
 * so use it on a separate hibernate.connection.url (see hibernate.properties).
 * <p>Make sure that the servlet and its mapping are activated in web.xml.
 * <p>If you want to test without a single TA (but with a new TA for each request),
 * add the parameter "?nota" to the test URL.
 * <p>Note: The test deactivates logging for not measuring performance penalties due to slow console ouput.
 * @author Thomas Much
 * @version 2006-06-14
 */
public class PerfTestServlet extends HttpServlet {
	
	private static final String TESTID_PREFIX   = "__test_id_";
	private static final String TESTNAME_PREFIX = "Topic";
	
	private volatile static int numTopics = 0;


	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		boolean useTA = (req.getParameter("nota") == null);
		
		res.setContentType("text/plain");
		
		PrintWriter out = res.getWriter();

		ConsensusFoundation cf = ConsensusFoundationUtils.getConsensusFoundationManager( this.getServletContext() );
		OntologyManager     om = cf.getOntologyManager();
		QueryEngine         qe = om.getQueryEngine();
		TopicMap            tm = ((OntologyManagerImpl)om).getTopicMap();
		
		int oldlevel = cf.getLoggingManager().getLevel();
		
		cf.getLoggingManager().setLevel( LoggingManager.LEVEL_OFF );

		out.println( "Starting performance test, generating 1000 topics ... (TA: " + useTA + ")" );

		try {
			User user = cf.getUserManager().getUserByUsername( "thmuch" );
			
			out.println( "#Topics,CF 100 Topics,CF 1 Topic x100,TM4J 100 Topics,TM4J 1 Topic x100" );
			out.flush();

			for (int i = 0; i <= 20; i++) {
				if (i == 0) {
					out.print( numTopics + "," );
					out.flush();
				}
				else {
					this.generate50Topics( out, om, user );
				}

				this.cfRead100Topics( out, om, qe, user, req, useTA );
				this.cfRead1Topic( out, om, qe, user, req, useTA );
				this.tm4jRead100Topics( out, om, tm, req, useTA );
				this.tm4jRead1Topic( out, om, tm, req, useTA );
				
				out.println();
				out.flush();
			}
		}
		catch (IOException e) {
			throw e;
		}
		catch (Exception e) {
			throw new ServletException( e );
		}
		
		out.println( "... done." );
		out.flush();
		
		cf.getLoggingManager().setLevel( oldlevel );
	}


	private void generate50Topics(PrintWriter out, OntologyManager om, User user) throws Exception {
		for (int i = 0; i < 50; i++) {
			om.createTopic( user, TESTID_PREFIX + numTopics, TESTNAME_PREFIX + numTopics, null);
			numTopics++;
		}
		out.print( numTopics + "," );
		out.flush();
	}
	
	
	private void cfRead100Topics(PrintWriter out, OntologyManager om, QueryEngine qe, User user, HttpServletRequest req, boolean useTA) throws Exception {
		long startMs = System.currentTimeMillis();
		
		Object txa = null;
		if (useTA) {
			txa = om.openTransaction( req );
		}

		for (int i = 0 ; i < 100; i++) {
			qe.getTopicById( user, this.getRandomTopicId() );
		}
		
		if (useTA) {
			om.commitTransaction( req, txa );
		}
		
		int ms = (int)(System.currentTimeMillis() - startMs);
		out.print( ms + "," );
		out.flush();
	}
	
	
	private void tm4jRead100Topics(PrintWriter out, OntologyManager om, TopicMap tm, HttpServletRequest req, boolean useTA) throws Exception {
		long startMs = System.currentTimeMillis();
		
		Object txa = null;
		if (useTA) {
			txa = om.openTransaction( req );
		}
		
		for (int i = 0 ; i < 100; i++) {
			tm.getTopicByID( this.getRandomTopicId() );
		}
		
		if (useTA) {
			om.commitTransaction( req, txa );
		}

		int ms = (int)(System.currentTimeMillis() - startMs);
		out.print( ms + "," );
		out.flush();
	}


	private void cfRead1Topic(PrintWriter out, OntologyManager om, QueryEngine qe, User user, HttpServletRequest req, boolean useTA) throws Exception {
		String id = this.getRandomTopicId();
		long startMs = System.currentTimeMillis();
		
		Object txa = null;
		if (useTA) {
			txa = om.openTransaction( req );
		}
		
		for (int i = 0 ; i < 100; i++) {
			qe.getTopicById( user, id );
		}
		
		if (useTA) {
			om.commitTransaction( req, txa );
		}

		int ms = (int)(System.currentTimeMillis() - startMs);
		out.print( ms + "," );
		out.flush();
	}
	
	
	private void tm4jRead1Topic(PrintWriter out, OntologyManager om, TopicMap tm, HttpServletRequest req, boolean useTA) throws Exception {
		String id = this.getRandomTopicId();
		long startMs = System.currentTimeMillis();
		
		Object txa = null;
		if (useTA) {
			txa = om.openTransaction( req );
		}
		
		for (int i = 0 ; i < 100; i++) {
			tm.getTopicByID( id );
		}
		
		if (useTA) {
			om.commitTransaction( req, txa );
		}

		int ms = (int)(System.currentTimeMillis() - startMs);
		out.print( ms + "," );
		out.flush();
	}


	private String getRandomTopicId() {
		int nr = (int)(Math.random() * numTopics);
		return TESTID_PREFIX + nr;
	}

}
