package jp.agentec.sinaburocast.common.util;

import java.io.StringWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.agentec.sinaburocast.common.SinaburoConstant;
import jp.agentec.sinaburocast.common.SinaburoConstant.AttrKey;
import jp.agentec.sinaburocast.common.SinaburoConstant.MesResKey;
import jp.agentec.sinaburocast.vo.AuthenticatedTokenVO;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.context.Context;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.tools.view.servlet.VelocityViewServlet;
import org.mobylet.core.Mobylet;
import org.mobylet.core.MobyletFactory;
import org.seasar.struts.util.RequestUtil;
import org.seasar.struts.util.ServletContextUtil;

public class AgtVelocityViewServlet extends VelocityViewServlet {
    private static final long serialVersionUID = 3202497865343082548L;

	private static final String PROPERTY_ERROR_TEMPLATE = "tools.view.servlet.error.template";

    private static final boolean __devmode = PropertyUtil.getBoolean("DEVMODE");

    protected String errorTemplate;
    private final Logger logger = Logger.getLogger(getClass());
	/* (非 Javadoc)
     * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet#init(javax.servlet.ServletConfig)
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        errorTemplate = getVelocityProperty(PROPERTY_ERROR_TEMPLATE, null);
    }

	@Override
	public Template getTemplate(String name) throws ResourceNotFoundException,
			ParseErrorException, Exception {
		Template retValue = super.getTemplate(deviceJudge(name));
		return retValue;
	}

	@Override
	public Template getTemplate(String name, String encoding)
			throws ResourceNotFoundException, ParseErrorException, Exception {
		int devType = getDevice();
		String prifix = ServletContextUtil.getViewPrefix();

		if (SinaburoConstant.AccessType.MOBILE == devType){
			name = name.replace(prifix, prifix + "/mb");
			encoding = "UTF-8";
		}else if (SinaburoConstant.AccessType.SMARTPHONE == devType){
			name = name.replace(prifix, prifix + "/sp");
		}

		//ユーザーのエラーページに遷移するけど、管理者でログインしている場合
		//パスを管理者ページに変更
		if(!name.contains("/admin/") && name.contains("/error/")){
			Object obj = RequestUtil.getRequest().getSession().getAttribute(AttrKey.AUTHENTICATED_TOKEN);
			if(obj != null && ((AuthenticatedTokenVO)obj).adminUser != null){//管理者
				name = name.replace("/error/", "/error/admin/");
			}
		}

		Template retValue = super.getTemplate(name, encoding);
		return retValue;
	}

	private String deviceJudge(String name){

		String prifix = ServletContextUtil.getViewPrefix();
		//携帯ユーザーだったら
		if(getDevice().equals(SinaburoConstant.AccessType.MOBILE)){
			//ServeletContextUtil s = null;
			return name.replace(prifix, prifix + "/mb");
		}else if(getDevice().equals(SinaburoConstant.AccessType.SMARTPHONE)){
			return name.replace(prifix, prifix + "/sp");
		}

		return name;
	}

	/**
	 * userAgentで携帯、(PC,スマートフォン)
	 * @return 携帯の場合true,その他false
	 */
	public Integer getDevice(){

		//final Log log = getVelocityEngine().getLog();
		try {

			Mobylet mobylet = MobyletFactory.getInstance();

			return RequestUtils.getCarrierType(mobylet);

		} catch (Exception e) {
			String userAgent = RequestUtil.getRequest().getHeader("user-agent");
			
			logger.error("AgtMobylet機種判別エラー: UserAgent=" + userAgent + " error=" + e.getMessage());

			if (StringUtils.isEmpty(userAgent)) {
				//nullの場合例外が発生するのでPCで返す
				return SinaburoConstant.AccessType.PC;
			}
			
			//スマートフォン
			if ((userAgent.indexOf("iPhone") > 0 && userAgent.indexOf("iPad") == -1)
					|| userAgent.indexOf("iPod") > 0
					|| userAgent.indexOf("Android") > 0){
				return SinaburoConstant.AccessType.SMARTPHONE;
			}

			if( userAgent.startsWith("Mozilla") || userAgent.startsWith("Opera")){
			//PC
				return SinaburoConstant.AccessType.PC;
			}
			return SinaburoConstant.AccessType.MOBILE;
		}
	}

	//choi-c ADD END

	/* (非 Javadoc)
     * @see org.apache.velocity.tools.view.servlet.VelocityViewServlet#error(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Exception)
     */
    @Override
	protected void error(HttpServletRequest request,
			HttpServletResponse response, Exception e) throws ServletException {
		if (__devmode || errorTemplate == null) {
			super.error(request, response, e);
			return;
		}

        final Log log = getVelocityEngine().getLog();
		try {
	        if (e instanceof ResourceNotFoundException) {
	    		log.warn("AgtVelocityViewServlet: some resources are not found. ", e);
	        	response.sendError(HttpServletResponse.SC_NOT_FOUND, request.getRequestURI());
	        	return;
	        }

	        // get a velocity context
            Context ctx = createContext(request, response);

            Throwable cause = e;

            // if it's an MIE, i want the real cause and stack trace!
            if (cause instanceof MethodInvocationException)
            {
                // get the real cause
                cause = ((MethodInvocationException)e).getWrappedThrowable();
            }

            // grab the cause's stack trace and put it in the context
            StringWriter sw = new StringWriter();
            cause.printStackTrace(new java.io.PrintWriter(sw));
    		log.error(sw.toString());

            final String errorCode = MesResKey.Errors.VelocityRenderError;
			ctx.put("ERROR_CODE", errorCode);
			ctx.put("ERROR_MSG", SinaburoViewUtil.getErrorMessage("errors.SystemException", errorCode));

            // retrieve and render the error template
            Template et = getTemplate(errorTemplate);
            mergeTemplate(et, ctx, response);
        } catch (Exception e2) {
			log.error("AgtVelocityViewServlet: Error during error template rendering", e2);

        	// 本番環境ではスタックトレースは出力しない
			throw new ServletException(e);
        }
    }
}