package gov.va.vss.web;

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

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.ModelAndView;

import gov.va.shared.model.AppUser;
import gov.va.shared.util.SecurityUtil;
import gov.va.vss.model.facility.Facility;
import gov.va.vss.web.interceptor.CommonReferenceDataInterceptor;
import gov.va.vss.web.interceptor.SingleSessionConversationInterceptor.SessionConversationInterruptedException;

public abstract class AbstractAppController extends AbstractCommonAppController {
	private static final Logger log = LoggerFactory.getLogger(AbstractAppController.class);

	protected AppUser getCurrentUser() {
		return SecurityUtil.getCurrentUserAs(AppUser.class);
	}

	@ExceptionHandler(Throwable.class)
	public ModelAndView processError(Throwable ex, HttpServletRequest request, HttpServletResponse response) {
		if (isAjax(request)) {
			/*
			 * Necessary to trigger the jQuery error() handler as opposed to the
			 * success() handler - CPB
			 */
			response.setStatus(HttpStatus.BAD_REQUEST.value());
			return ajaxRequestHandler.getExceptionModelAndView(ex, request);
		} else {
			ModelAndView mv = new ModelAndView("error", "exceptionStackTrace", ExceptionUtils.getFullStackTrace(ex));
			CommonReferenceDataInterceptor.populateBasicGlobalReferenceData(mv.getModel(), velocityService, env);
			return mv;
		}
	}
	
	@ExceptionHandler(AccessDeniedException.class)
	public ModelAndView processAuthorizationException(AccessDeniedException ex) {
		AppUser au = getCurrentUser();
		Facility facilityContext = getFacilityContext();
		if (au != null && facilityContext == null)
			return new ModelAndView("redirect:/selectStation.htm");

		ModelAndView mv = new ModelAndView("authorizationException", "exceptionStackTrace",
				ExceptionUtils.getFullStackTrace(ex));
		CommonReferenceDataInterceptor.populateBasicGlobalReferenceData(mv.getModel(), velocityService, env);
		return mv;
	}

	@ExceptionHandler({ OptimisticLockException.class, OptimisticLockingFailureException.class })
	public ModelAndView processOptimisticLockException(OptimisticLockException ex) {
		ModelAndView mv = new ModelAndView("optimisticLockException", "exceptionStackTrace",
				ExceptionUtils.getFullStackTrace(ex));
		CommonReferenceDataInterceptor.populateBasicGlobalReferenceData(mv.getModel(), velocityService, env);
		return mv;
	}

	@ExceptionHandler({ SessionConversationInterruptedException.class })
	public ModelAndView processSessionConversationInterruptedException(SessionConversationInterruptedException ex) {
		ModelAndView mv = new ModelAndView("sessionConversationInterruptedException");
		CommonReferenceDataInterceptor.populateBasicGlobalReferenceData(mv.getModel(), velocityService, env);
		return mv;
	}

	@InitBinder
	public final void initBinder(WebDataBinder binder) {
		binder.setDisallowedFields(getDisallowedBinderFields());
	}

	protected String[] getDisallowedBinderFields() {
		return new String[] {};
	}

	protected void appendCommonReportParams(ModelMap model) {
		model.put("username", getCurrentUserName());
		model.put("userPasswordHash", appUserDAO.findRequiredByUsername(getCurrentUserName(), false).getPassword());
		model.put("siteContextId", getRequiredSiteContext().getId());
	}

}
