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

import it.mice.voila.runtime.springmvc.controller.DefaultFormController;
import it.mice.voila.runtime.springmvc.flashmap.FlashMap;
import it.mice.voila.runtime.springmvc.util.SpringMvcUtil;
import it.mice.voila.runtime.util.UserMessage;
import it.mice.voila.runtime.util.UserMessages;
import it.mice.voila.runtime.validator.ValidatorUtils;

import java.util.Iterator;
import java.util.Map;

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

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindingResult;
import org.springframework.validation.BindingResultUtils;
import org.springframework.validation.FieldError;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class FlashMapManagerInterceptor extends HandlerInterceptorAdapter {
	Log log = LogFactory.getLog(FlashMapManagerInterceptor.class);

	@SuppressWarnings("unchecked")
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {

		HttpSession session = request.getSession(false);
		Map<String, ?> flash = null;
		if (session != null) {
			flash = (Map<String, ?>) session.getAttribute(FlashMap.FLASH_MAP_ATTRIBUTE);
			if (flash != null) {
				request.setAttribute(FlashMap.FLASH_MAP_ATTRIBUTE, flash);
				session.removeAttribute(FlashMap.FLASH_MAP_ATTRIBUTE);
				for (Map.Entry<String, ?> entry : flash.entrySet()) {
					Object currentValue = request.getAttribute(entry.getKey());
					if (currentValue == null) {
						request.setAttribute(entry.getKey(), entry.getValue());
					}					
				}
			}
		}

		return super.preHandle(request, response, handler);
	}

	
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		handleFieldErrors(handler, modelAndView);

		if (modelAndView != null && modelAndView.isReference() && modelAndView.getViewName().startsWith("redirect:")) {
			FlashMap.recycleIntoSession();
		}
		super.postHandle(request, response, handler, modelAndView);
	}


	/**
	 * @param handler
	 * @param modelAndView
	 */
	private void handleFieldErrors(Object handler, ModelAndView modelAndView) {
		Object handlerBean = SpringMvcUtil.getHandlerBean(handler);
		if (handlerBean instanceof DefaultFormController) {
			String formName = ((DefaultFormController)handlerBean).getFormName();
			if (formName != null && modelAndView != null && !modelAndView.getViewName().startsWith("redirect:")) {
				BindingResult bindingResult = BindingResultUtils.getBindingResult(modelAndView.getModel(), formName);
				if (bindingResult != null) {
					Iterator<UserMessage> i = FlashMap.getMessages().iterator();
					UserMessages removedMsgs = new UserMessages();
					while (i.hasNext()) {
						UserMessage userMessage = (UserMessage) i.next();
						if (userMessage.isFieldError()) {
							Object[] args = new Object[] { new DefaultMessageSourceResolvable(
									ValidatorUtils.getCodes(null, userMessage.getFieldPath())
									, userMessage.getFieldPath()) };
							
							bindingResult.addError(new FieldError(formName, userMessage.getFieldPath(), userMessage.getRejectedValue(),
									false, new String[] { userMessage.getMessageKey() },
									ArrayUtils.addAll(args, userMessage.getMessageParams()), userMessage.getMessageText()));
							removedMsgs.add(userMessage);
						}
					}
					FlashMap.getMessages().removeAll(removedMsgs);
				}
			}
		}
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {

		super.afterCompletion(request, response, handler, ex);
	}

}
