package de.snailshell.consensus.demo;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import de.uka.ipd.consensus.foundation.ConsensusFoundationManager;
import de.uka.ipd.consensus.foundation.logging.LoggingManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyManager;
import de.uka.ipd.consensus.foundation.ontology.OntologyManagerException;

/**
 * @author Thomas Much
 * @version 2006-06-14
 */
public class ConsensusFoundationFilter implements Filter {

	private static final TAWrapper ta = new TAWrapper();

	private ServletContext context;


	public void init(FilterConfig config) throws ServletException {
		this.context = config.getServletContext();
	}


	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		OntologyManager om;
		LoggingManager  logging;
		
		ConsensusFoundationManager cfm = ConsensusFoundationUtils.getConsensusFoundationManager( this.context );
		
		if (cfm != null) {
			om      = cfm.getOntologyManager();
			logging = cfm.getLoggingManager();
		}
		else {
			om      = null;
			logging = null;
		}

		long startMs = System.currentTimeMillis();

		ta.open( om, request );

		try {
			chain.doFilter(request,response);
		}
		finally {
			ta.close( logging, om, request );
			
			if ((logging != null) && (request instanceof HttpServletRequest)) {
				int ms = (int)(System.currentTimeMillis() - startMs);
				logging.debug( "Request for " + ((HttpServletRequest)request).getRequestURI() + " took " + ms + " ms" );
			}
		}
	}


//	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//		synchronized (lock) {
//			HttpServletRequest req;
//			User               user;
//			OntologyManager    om;
//			LoggingManager     logging;
//			
//			ConsensusFoundationManager cfm = ConsensusFoundationUtils.getConsensusFoundationManager( this.context );
//			
//			if (cfm != null) {
//				om      = cfm.getOntologyManager();
//				logging = cfm.getLoggingManager();
//			}
//			else {
//				om      = null;
//				logging = null;
//			}
//
//			if (request instanceof HttpServletRequest) {
//				req  = (HttpServletRequest)request;
//				user = ConsensusFoundationUtils.getUser( req );
//			}
//			else {
//				req  = null;
//				user = null;
//			}
//
//			Object txa     = null;
//			long   startMs = System.currentTimeMillis();
//			
//			try {
//				if (om != null) {
//					txa = om.openTransaction( user );
//				}
//
//				chain.doFilter(request,response);
//
//				if (om != null) {
//					om.commitTransaction( user, txa );
//				}
//			}
//			catch (IOException e) {
//				if (om != null) {
//					try {
//						om.rollbackTransaction( user, txa );
//					}
//					catch (OntologyManagerException et) { }
//				}
//				throw e;
//			}
//			catch (ServletException e) {
//				if (om != null) {
//					try {
//						om.rollbackTransaction( user, txa );
//					}
//					catch (OntologyManagerException et) { }
//				}
//				throw e;
//			}
//			catch (Exception e) {
//				if (om != null) {
//					try {
//						om.rollbackTransaction( user, txa );
//					}
//					catch (OntologyManagerException et) { }
//				}
//				throw new ServletException(e);
//			}
//			finally {
//				if ((logging != null) && (req != null)) {
//					int ms = (int)(System.currentTimeMillis() - startMs);
//					logging.debug( "Request for " + req.getRequestURI() + " took " + ms + " ms" );
//				}
//			}
//		}
//	}


	public void destroy() { }



	private static class TAWrapper {

		private int    count = 0;
		private Object txa   = null;


		public synchronized void open(OntologyManager om, Object scope) throws ServletException {
			if (om != null) {
				try {
					if (this.count == 0) {
						txa = om.openTransaction( scope );
					}
					// only increment count if openTransaction() did not throw an exception:
					this.count++;
				}
				catch (OntologyManagerException e) {
					throw new ServletException(e);
				}
			}
		}


		public synchronized void close(LoggingManager lm, OntologyManager om, Object scope) {
			// only call this method if open() did *not* throw an exception!
			if (om != null) {
				this.count--;
				if (this.count == 0) {
					try {
						// only commit (no rollback), since we don't know how many requests have used this TA for write actions
						om.commitTransaction( scope, txa );
					}
					catch (OntologyManagerException e) {
						if (lm != null) {
							lm.error("Error committing transaction: " + e);
						}
						om.abortTransaction( scope, txa );
					}
					finally {
						txa = null;
					}
				}
			}
		}
	}

}
