/**
 * 
 */
package it.mice.voila.runtime.web.restws;

import it.mice.voila.runtime.entity.EntityGeneric;
import it.mice.voila.runtime.exception.BusinessException;
import it.mice.voila.runtime.security.SecurityUtils;
import it.mice.voila.runtime.util.UserMessage;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 *
 */
public class GenericJsonController {
	private static Log logger = LogFactory.getLog(GenericJsonController.class);
	/**
	 * MESSAGE_GENERIC_NOT_FOUND
	 */
	protected static final String MESSAGE_GENERIC_NOT_FOUND = "message.genericNotFound";

	protected UserDetails getUserDetails() {
		return SecurityUtils.getCurrentUserDetail();
	}

	protected String getUserId() {
		UserDetails userDetails = getUserDetails();
		if (userDetails != null) {
			return userDetails.getUsername();
		}
		return null;
	}

	protected ModelMap getJsonResult(Object dataObject) {
	    ModelMap map = new ModelMap();
	    map.addAttribute("data", dataObject);
	    return map;
	}

	protected ModelMap getJsonException(Exception ex) {
		return getJsonException(ex, HttpStatus.BAD_REQUEST);
	}

	protected ModelMap getJsonException(Exception ex, HttpStatus status) {
		return getJsonException(ex, HttpStatus.BAD_REQUEST, HttpStatus.BAD_REQUEST.value() + "");
	}

	protected ModelMap getJsonException(Exception ex, HttpStatus status, String errorKey) {
		logger.warn(ex);
	    ModelMap map = new ModelMap();
	    map.addAttribute("error", new JsonCallError(status.value(), errorKey, ex.getMessage(), ex.getClass().getName()));
	    return map;
	}
	
	@ExceptionHandler(BusinessException.class)
	public @ResponseBody ModelMap handleNotAuthenticatedException(BusinessException ex,
			HttpServletRequest request) {
		
		if (logger.isInfoEnabled()){
			logger.info("", ex);
		}
		UserMessage msg = ex.getUserMessages().iterator().next();
		return getJsonException(ex, HttpStatus.BAD_REQUEST, msg.getMessageKey());
	}
	
	@ExceptionHandler(BadCredentialsException.class)
	public @ResponseBody ModelMap handleNotAuthenticatedException(BadCredentialsException ex,
			HttpServletRequest request) {
		return getJsonException(ex, HttpStatus.UNAUTHORIZED);
	}
	
	@ExceptionHandler(Exception.class)
	public @ResponseBody ModelMap handleNotAuthenticatedException(Exception ex,
			HttpServletRequest request) {
		
		logger.error("", ex);
		return getJsonException(ex);
	}
	
	protected String escapeNonAscii(String str) {
		StringBuilder retStr = new StringBuilder();
		for (int i = 0; i < str.length(); i++) {
			int cp = Character.codePointAt(str, i);
			int charCount = Character.charCount(cp);
			if (charCount > 1) {
				i += charCount - 1; // 2.
				if (i >= str.length()) {
					throw new IllegalArgumentException("truncated unexpectedly");
				}
			}
			if (cp < 128) {
				retStr.appendCodePoint(cp);
			} else {
				retStr.append(String.format("\\u%x", cp));
			}
		}
		return retStr.toString();
	}

	/**
	 * createCriteriaMapForUser.
	 * @param username
	 * @return
	 */
	protected Map<String, Object> createCriteriaMapForUser(String username) {
		Map<String, Object> criteria = new HashMap<String, Object>();
		criteria.put("preferitiForUsername", username);
		return criteria;
	}
	
	public static abstract class FindByFilterGenericRequest<E extends EntityGeneric> {
		private E filterFrom;
		private E filterTo;

		private Map<String, Object> criteriaMap = new HashMap<String, Object>();

		private Integer firstResultRow;
		private Integer searchResultPageSize;
		private String orderBy;

		public E getFilterFrom() {
			return filterFrom;
		}

		public void setFilterFrom(E filterFrom) {
			this.filterFrom = filterFrom;
		}

		public E getFilterTo() {
			return filterTo;
		}

		public void setFilterTo(E filterTo) {
			this.filterTo = filterTo;
		}

		public Map<String, Object> getCriteriaMap() {
			return criteriaMap;
		}

		public void setCriteriaMap(Map<String, Object> criteriaMap) {
			this.criteriaMap = criteriaMap;
		}

		public Integer getSearchResultPageSize() {
			return searchResultPageSize;
		}

		public void setSearchResultPageSize(Integer searchResultPageSize) {
			this.searchResultPageSize = searchResultPageSize;
		}

		public Integer getFirstResultRow() {
			return firstResultRow;
		}

		public void setFirstResultRow(Integer firstResultRow) {
			this.firstResultRow = firstResultRow;
		}

		public String getOrderBy() {
			return orderBy;
		}

		public void setOrderBy(String orderBy) {
			this.orderBy = orderBy;
		}
	}
}
