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

import it.mice.voila.runtime.springmvc.bean.ChooseInfoBean;
import it.mice.voila.runtime.springmvc.form.JfFormBean;
import it.mice.voila.runtime.springmvc.util.SpringMvcUtil;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.ParameterizedType;
import java.net.URLEncoder;

import org.apache.commons.lang.StringUtils;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;


public class DefaultFormController<F> extends DefaultController {
	private Class<F> persistentFormClass;

	@SuppressWarnings("unchecked")
	public DefaultFormController() {
		try {
			this.persistentFormClass = (Class<F>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		} catch (Exception e) {
			Class dc = (Class) getClass().getGenericSuperclass();
			this.persistentFormClass = (Class<F>) ((ParameterizedType) dc.getGenericSuperclass()).getActualTypeArguments()[0];
		}
	}

	/**
	 * canPrepareCrossEntityData.
	 * @param form the form.
	 * @return the result.
	 */
	protected boolean canPrepareCrossEntityData(JfFormBean form) {
		return form.getPageStatus() == null || (!form.getPageStatus().isNewMode() && !form.getPageStatus().isEditMode());
	}
	
	public Class<F> getPersistentFormClass() {
		return persistentFormClass;
	}

	@RequestMapping(value = "*popupOn")
	public String popupOn(F form, BindingResult errorResult, Model model) {
		ChooseInfoBean chooseInfoBean = ChooseInfoBean.newInstance();
		chooseInfoBean.setChooseTitle(getRequest().getParameter(ChooseInfoBean.POPUP_TITLE_NAME));

		// Build hashmap fo return parameters
		String[] outputParameters = getRequest().getParameterValues(ChooseInfoBean.POPUP_OUTPUT_PARAMETER_PREFIX);
		if (outputParameters == null) {
			outputParameters = new String[0];
		}
		for (int i = 0; i < outputParameters.length; i++) {
			String destOutputParameter = getRequest().getParameter(ChooseInfoBean.POPUP_OUTPUT_PARAMETER_PREFIX
					+ "." + outputParameters[i]);
			chooseInfoBean.getChooseOutputParmMap().put(outputParameters[i], destOutputParameter);
		}
		// Build target popup url with input parameters
		String targetUrl = getRequest().getParameter(ChooseInfoBean.POPUP_URL_NAME);
		if (targetUrl.indexOf("?") > -1) {
			targetUrl += "&";
		} else {
			targetUrl += "?";
		}
		String[] inputParameters = getRequest().getParameterValues(ChooseInfoBean.POPUP_INPUT_PARAMETER_PREFIX);
		for (int i = 0; i < inputParameters.length; i++) {
			String sourceInputParameter = getRequest().getParameter(ChooseInfoBean.POPUP_INPUT_PARAMETER_PREFIX
					+ "." + inputParameters[i]);
			try {
				targetUrl += inputParameters[i] + "="
						+ URLEncoder.encode(getRequest().getParameter(sourceInputParameter) == null ? "" : getRequest().getParameter(sourceInputParameter), "ISO-8859-15") + "&";
			} catch (UnsupportedEncodingException e) {
				throw new RuntimeException(e);
			}
		}
		targetUrl += "&popupNoClearFilterParameters=" + StringUtils.defaultString(getRequest().getParameter("popupNoClearFilterParameters"));
		
		return "redirect:" + targetUrl;
	}

	
	protected F resetForm() {
		return getFormInternal(true);
	}

	protected F getForm() {
		return getFormInternal(false);
	}

	@SuppressWarnings("unchecked")
	protected F getFormInternal(boolean resetForm) {
		F form = resetForm ? null : (F) getSession().getAttribute(getFormName());
		if (form == null) {
			try {
				form = persistentFormClass.newInstance();
//				ServletRequestDataBinder srdb = new ServletRequestDataBinder(form);
//				srdb.bind(getRequest());
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			saveFormIntoScope(getFormName(), form);
		}
		return form;
	}
	
	protected String finalizeModelAndView(String viewName, Model model, JfFormBean form, Object id) {
		model.addAttribute(OBJECT_ID, id);
		model.addAttribute(FORM_ID, getFormName());
		getSession().setAttribute(FORM_ID, getFormName());
		model.addAttribute(UNIQUE_OBJECT_ID, getUniqueObjectId(id));
		if (form != null) {
			model.addAttribute(getFormName(), form);
		} else {
			model.addAttribute(getFormName(), getForm());
		}
		if (viewName != null) {
			getSession().setAttribute(SpringMvcUtil.LAST_VIEW_NAME, viewName);
		}
		return viewName;
	}

	public String getUniqueObjectId(Object id) {
		return getFormName() + "@" + id;
	}

	public String getFormName() {
		return StringUtils.uncapitalize(getPersistentFormClass().getSimpleName());
	}
	
	protected void saveFormIntoScope(String formName, F form) {
		getSession().setAttribute(formName, form);
	}
}
