package it.mice.voila.runtime.springmvc.interceptors;

import it.mice.voila.runtime.springmvc.controller.DefaultController;
import it.mice.voila.runtime.springmvc.util.SpringMvcUtil;

import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.servlet.HandlerInterceptor;

public class RequestSessionLoggerInterceptor implements HandlerInterceptor {

	Log log = LogFactory.getLog(RequestSessionLoggerInterceptor.class);

	private boolean logRequest = true;
	private boolean logSession = true;
	private boolean logParameter = true;
	
	public boolean isLogRequest() {
		return logRequest;
	}

	public void setLogRequest(boolean logRequest) {
		this.logRequest = logRequest;
	}

	public boolean isLogSession() {
		return logSession;
	}

	public void setLogSession(boolean logSession) {
		this.logSession = logSession;
	}

	public boolean isLogParameter() {
		return logParameter;
	}

	public void setLogParameter(boolean logParameter) {
		this.logParameter = logParameter;
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		Object handlerBean = SpringMvcUtil.getHandlerBean(handler);

		if (!(handlerBean instanceof DefaultController)) {
			return;
		}

		if (logSession && log.isDebugEnabled()) {
			sessionContentLogger();
		}
		if (logRequest && log.isDebugEnabled()) {
			requestContentLogger();
		}
		if (logParameter && log.isDebugEnabled()) {
			requestParameterContentLogger();
		}
	}

	public void sessionContentLogger() throws IOException {
    	int width = 90;
        java.util.List<String> en = getSortedList(SpringMvcUtil.getSession().getAttributeNames());
        log.debug(" List of objects present into 'SESSION' with related size in bytes: ");
        int tot = 0;
        for (String nome : en) {
            Object obj = SpringMvcUtil.getSession().getAttribute(nome);
            int size = writeObjectLine(width, nome, obj);
            tot = tot + size;
		}
        writeTotalLine(width, tot);
	}

	public void requestContentLogger() throws IOException {
    	int width = 90;
    	java.util.List<String> en = getSortedList(SpringMvcUtil.getRequest().getAttributeNames());
        log.debug(" List of objects present into 'REQUEST' with related size in bytes: ");
        int tot = 0;
        for (String nome : en) {
            Object obj = SpringMvcUtil.getRequest().getAttribute(nome);
            int size = writeObjectLine(width, nome, obj);
            tot = tot + size;
        }
        writeTotalLine(width, tot);
	}
	
	private void requestParameterContentLogger() throws IOException {
    	int width = 90;
    	java.util.List<String> en = getSortedList(SpringMvcUtil.getRequest().getParameterNames());
        log.debug(" List of parameters present into 'REQUEST' with related size in bytes: ");
        int tot = 0;
        for (String nome : en) {
            Object obj = SpringMvcUtil.getRequest().getParameter(nome);
            int size = writeObjectLine(width, nome, obj);
            tot = tot + size;
        }
        writeTotalLine(width, tot);
	}

	private int writeObjectLine(int width, String nome,
			Object obj) throws IOException {
		java.io.ObjectOutput out2;
		java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();

		out2 = new java.io.ObjectOutputStream(bos);
		int size = 0;
		try {
		    out2.writeObject(obj);
		    size = bos.toByteArray().length;
		} catch (java.io.NotSerializableException e) {
		    //log.error("Object name:" + nome + " of type:" + obj + " is not a serializable object !!!", e);
		}
		out2.close();
		int spazi = width - nome.length();
		String toString = obj != null ? obj.toString() : "";
		int carriagePos = -1;
		if (nome.equals("org.springframework.core.convert.ConversionService")) {
			carriagePos = toString.indexOf("\n");
		}
		if (toString.length() > carriagePos && carriagePos > -1) {
			toString = toString.substring(0, carriagePos) + "...";
		}
		log.debug("\t" + nome + org.apache.commons.lang.StringUtils.leftPad((size == 0 ? "??" : size) + "", spazi, '.') + " " + toString);
		return size;
	}

	private void writeTotalLine(int width, int tot) {
		log.debug("\t" + org.apache.commons.lang.StringUtils.leftPad("", width, '-'));
        log.debug("\t" + "TOTAL:" + org.apache.commons.lang.StringUtils.leftPad(tot + "", width - 6, '.'));
	}
	
	
	@SuppressWarnings("unchecked")
	private List<String> getSortedList(Enumeration<?> list) {
		List<String> result = Collections.list((Enumeration<String>)list);
		Collections.sort(result);
		return result;
	}

}
