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 it.mice.voila.runtime.web.json.JSONObject;

import java.beans.PropertyEditor;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.RequestMapping;

public class PopupController<F extends JfFormBean> extends DefaultFormController<F> {

	@RequestMapping(value="undoSelection")
	public ResponseEntity<String>  undoSelection(Model model, HttpServletResponse response) {
		return returnEmptyJsonResult(model, response);
	}

	protected int getPopupFirstResult(JfFormBean form, String displayTagTableName) {
		int pageSize = getPopupPageSize(form, displayTagTableName);
		return getFirstResult(pageSize, displayTagTableName);
	}

	protected int getPopupPageSize(JfFormBean form, String displayTagTableName) {
		if (isExportListRequested()) {
			return 0;
		}
		return form.getPopupPageSize();
	}

	public String getFormName() {
		return "popup" + getPersistentFormClass().getSimpleName();
	}

	protected ResponseEntity<String> returnJsonResult(Model model, Object obj, HttpServletResponse response) {
		if (ChooseInfoBean.getCurrent() != null) {
			return returnRedirectResult(model, obj, response);
		}
		
		ServletRequestDataBinder binder = new ServletRequestDataBinder(null);
		try {
			initBinder(getRequest(), binder);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.TEXT_HTML);
		JSONObject result = prepareJsonResult(model, obj, binder);
		getSession().removeAttribute(getFormName());

		return new ResponseEntity<String>("<script type=\"text/JavaScript\">var dialogArguments = eval(" + result + ");parent.closePopupDialog(true, dialogArguments);</script>",
				headers, HttpStatus.OK);
	}

	protected ResponseEntity<String> returnEmptyJsonResult(Model model, HttpServletResponse response) {
		return returnJsonResult(model, null, response);
	}

	protected JSONObject prepareJsonResult(Model model, Object obj, ServletRequestDataBinder binder) {
		BeanWrapper bw = null;
		if (obj != null) {
			bw = PropertyAccessorFactory.forBeanPropertyAccess(obj);
		}
		F form = getForm();
		
		Map<String, Object> result = new HashMap<String, Object>();
		String[] attrName = form.getPopupReturnParametersArray();
		for (int i = 0; i < attrName.length; i++) {
			populateMap(result, bw, attrName[i], binder);
		}
		JSONObject jsonResult = new JSONObject(result);
		return jsonResult;
	}

	protected JSONObject prepareEmptyJsonResult(Model model) {
		return prepareJsonResult(model, null, null);
	}
	
	@SuppressWarnings("unchecked")
	private void populateMap(Map<String, Object> result, BeanWrapper bw, String attrName, ServletRequestDataBinder binder) {
		int dotPos = attrName.indexOf(".");
		if (dotPos == -1) {
			Object value = bw != null ? bw.getPropertyValue(attrName) : "";
			if (binder != null && value != null) {
				PropertyEditor pe = binder.findCustomEditor(value.getClass(), null);
				if (pe != null) {
					pe.setValue(value);
					value = pe.getAsText();
				}
			}
			result.put(attrName, value);
		} else {
			String beanName = attrName.substring(0, dotPos);
			String otherName = attrName.substring(dotPos + 1);
			Map<String, Object> subResult = (Map<String, Object>)result.get(beanName);
			if (subResult == null) {
				subResult = new HashMap<String, Object>();
				result.put(beanName, subResult);
			}
			BeanWrapper otherBw = null;
			if (bw != null) {
				Object otherObject = bw.getPropertyValue(beanName);
				otherBw = PropertyAccessorFactory.forBeanPropertyAccess(otherObject);
			}
			populateMap(subResult, otherBw, otherName, binder);
		}
	}

	private ResponseEntity<String> returnRedirectResult(Model model, Object obj, HttpServletResponse response) {
		ChooseInfoBean chooseInfoBean = ChooseInfoBean.popCurrent();
		String requestURI = "?";
		
		// Gather all output partameters and bind to the target url
		Iterator<String> i = chooseInfoBean.getChooseOutputParmMap().keySet().iterator();
		//MessageResources resource = getResources(ctx.getRequest());
		while (i.hasNext()) {
			String property = i.next();
			String targetProperty = (String) chooseInfoBean.getChooseOutputParmMap().get(property);
			Object value;
			try {
				value = obj != null ? PropertyUtils.getProperty(obj, property) : "";
				requestURI += targetProperty
						+ "="
						+ ((value != null) ? URLEncoder.encode(value.toString(), "UTF-8") : "") + "&";
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		
		SpringMvcUtil.doLastPathRedirect(getRequest(), response, requestURI, 1);
		return null;
	}
}
