package jp.agentec.sinaburocast.common.util.velocity;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Locale;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import jp.agentec.sinaburocast.common.SinaburoConstant;
import jp.agentec.sinaburocast.common.SinaburoConstant.AttrKey;
import jp.agentec.sinaburocast.common.util.PropertyUtil;
import jp.agentec.sinaburocast.common.util.SinaburoUtil;
import jp.agentec.sinaburocast.common.util.SinaburoViewUtil;
import jp.agentec.sinaburocast.dto.TestDto;
import jp.agentec.sinaburocast.entity.AdminUser;
import jp.agentec.sinaburocast.entity.Member;
import jp.agentec.sinaburocast.vo.AuthenticatedTokenVO;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.TokenProcessor;
import org.apache.velocity.tools.generic.ListTool;
import org.apache.velocity.tools.struts.StrutsUtils;
import org.apache.velocity.tools.view.context.ViewContext;
import org.seasar.framework.util.StringUtil;

/**
 * SinaburoCastプロジェクト用VelocityTools
 *
 * @author tsukada
 *
 */
public class VelocityTool {
	private static Logger LOGGER = Logger.getLogger(VelocityTool.class);

	protected ServletContext application;
	protected HttpServletRequest request;
	protected HttpSession session;
	protected HttpServletResponse response;

//	public static final boolean devmode = PropertyUtil.getBoolean(PropertyKey.DEVMODE);
	public static final int sslMode = PropertyUtil.getInt("sslMode");

	/**
	 * Initializes this tool.
	 *
	 * @param obj the current ViewContext
	 * @throws IllegalArgumentException if the param is not a ViewContext
	 */
	public void init(Object obj) {
		if (! (obj instanceof ViewContext)) {
			throw new IllegalArgumentException("Tool can only be initialized with a ViewContext");
		}

		ViewContext context = (ViewContext) obj;
		this.request = context.getRequest();
		this.response = context.getResponse();
		this.session = request.getSession();
		this.application = context.getServletContext();
	}

	/**
	 * コンテキストパスを返す。
	 * ROOTの場合から文字を返す。
	 *
	 * @return
	 * @deprecated request.getContextPath()自体'/'を含まないしROOT時は空文字列を返すはず。もし症状再発したら復活させる。
	 */
	@Deprecated
	public String getContextPath() {
		String contextPath = request.getContextPath();
		return contextPath.equals("/")? "": contextPath;
	}

	public String getContext() {
		String contextPath = request.getContextPath();
		return (contextPath.length() == 0 || contextPath.equals("/"))? "": contextPath.substring(1);
	}

	/**
	 * リクエストURLを返す。
	 *
	 * @return
	 */
	public String getRequestUrl() {
		String base = SinaburoUtil.extractRegexString(request.getRequestURL().toString(), "(http?://.+?)/", 1);
		String error_uri = (String)request.getAttribute("javax.servlet.error.request_uri");
		if (StringUtils.isNotEmpty(error_uri)) {
			/* HTTPエラーコードが発生した場合 */
			return	base + error_uri;
		}

		String orig_uri = (String)request.getAttribute("javax.servlet.forward.request_uri");
		if (StringUtils.isNotEmpty(orig_uri)) {
			/* 一度以上フォワードされている場合 */
			return	base + orig_uri;
		}

		// falldown
		return	request.getRequestURL().toString();
	}

	/**
	 * セキュアなURL(フルパス)をエンコードして返す。
	 *
	 * @param path
	 * @return
	 */
	public String getEncodeUrl(String path) {

		String urlpath = getUrl(path);

		urlpath = response.encodeURL(urlpath);

		return ( sslMode > 0	? new StringBuilder("https://").append(request.getServerName()).append(urlpath).toString() : urlpath);

//		String url = getSecureUrl(path);
//
//		String aaa = response.encodeURL(url);

//		return response.encodeURL(url);
	}

	/**
	 * セキュアなURL(フルパス)を生成して返す。
	 *
	 * @param path
	 * @return
	 */
	public String getSecureUrl(String path) {
		String urlpath = getUrl(path);

		return ( sslMode > 0	? new StringBuilder("https://").append(request.getServerName()).append(urlpath).toString() : urlpath);
	}

	/**
	 * TopページURLを生成して返す。
	 * エンドユーザ、契約事業者、サービスプロバイダそれぞれのトップページへのURLを返す。
	 * どの種別か判別できない場合は、エンドユーザのログインページに返す。
	 *
	 * @param path
	 * @return
	 */
	public String getTopUrl() {


		return request.getContextPath();
	}

	/**
	 * TopページURLを生成して返す。
	 * エンドユーザ、契約事業者、サービスプロバイダそれぞれのトップページへのURLを返す。
	 * どの種別か判別できない場合は、エンドユーザのログインページに返す。
	 *
	 * @param path
	 * @return
	 */
	public String getTopUrlAdmin() {
		return request.getContextPath()+"/admin/member/";
	}

	/**
	 * MyページURLを生成して返す。
	 * エンドユーザ、契約事業者、サービスプロバイダそれぞれのトップページへのURLを返す。
	 * どの種別か判別できない場合は、エンドユーザのログインページに返す。
	 *
	 * @param path
	 * @return
	 */
	public String getMyPageUrl() {

		return request.getContextPath()+"/user/myPage/";
	}

	/**
	 * URLを生成して返す。
	 *
	 * @param path
	 * @return
	 */
	public String getUrl(Object path) {
		return request.getContextPath() + SinaburoUtil.nvl(path, "");
	}


	public String getPadId(Object contractId){
		if (contractId == null)	return	null;
		return SinaburoUtil.leftPad(Long.parseLong(contractId.toString()), 4, "0");
	}

	public String getCid(Object contractId){
		if (contractId == null)	return	null;
		return "C"+ getPadId(contractId.toString());
	}

	/**
	 * devmodeに応じてプロトコルを返す
	 *
	 * @return
	 */
	public String getProtocol() {
		return sslMode > 0? "https" : "http";
	}

	public boolean isWindows() {
		final String userAgent = request.getHeader("user-agent");
		if (StringUtils.isEmpty(userAgent)) {
			LOGGER.warn("user-agent is not found.");
			return	false;
		}

		return	userAgent.toLowerCase(Locale.ENGLISH).contains("win");
	}

	public String getOsDependCSS() {
		return	isWindows() ? "win.css" : "mac.css";
	}

	/**
	 * 文字列長が指定したmaxlengthを越えないように適宜省略する
	 * @param str 表示される文字列
	 * @param maxlength 許容される最大長
	 * @return
	 */
	public String getBrief(final String str, final int maxlength) {
		return	SinaburoUtil.getBrief(str, maxlength);
	}

	/**
	 * 2つの文字列を一行に並べて表示する。その際、合計の文字列長が指定したmaxlengthを越えないように適宜省略する
	 * @param str1 左側に表示される文字列
	 * @param str2 右側に表示される文字列
	 * @param maxlength 許容される最大長
	 * @return
	 */
	public static String getBrief2(final String str1, final String str2, final int maxlength) {
		return	SinaburoUtil.getBrief2(str1, str2, maxlength);
	}

	/**
	 * エラーメッセージを取得する
	 * @param property nameのID
	 * @return エラーメッセージ
	 */
	public String getMsg(String property) {
		return errorMarkup(property, null, request, request.getSession(false), application);
	}

	/**
	 * エラーメッセージを取得する
	 * @return エラーメッセージ
	 */
	public String getMsgs() {
		return errorMarkup(null, null, request, request.getSession(false), application);
	}

	@SuppressWarnings("unchecked")
	private static String errorMarkup(String property, String bundle, HttpServletRequest request, HttpSession session, ServletContext application) {

		ActionMessages errors = StrutsUtils.getErrors(request);
		if (errors == null) {
			return "";
		}

		Iterator reports = null;
		if (property == null) {
			reports = errors.get();
		}
		else {
			reports = errors.get(property);
		}

		if (!reports.hasNext()) {
			return "";
		}

		/* Render the error messages appropriately if errors have been queued */
		StringBuffer results = new StringBuffer();
		String header = null;
		String footer = null;
		String prefix = null;
		String suffix = null;
		Locale locale = SinaburoViewUtil.getLocale();

		MessageResources resources =
			StrutsUtils.getMessageResources(request, application, bundle);
		if (resources != null) {
			header = resources.getMessage(locale, "errors.header");
			footer = resources.getMessage(locale, "errors.footer");
			prefix = resources.getMessage(locale, "errors.prefix");
			suffix = resources.getMessage(locale, "errors.suffix");
		}
		if (header == null) {
			header = "errors.header";
		}
		if (footer == null) {
			footer = "errors.footer";
		}
		/* prefix or suffix are optional, be quiet if they're missing */
		if (prefix == null) {
			prefix = "";
		}
		if (suffix == null) {
			suffix = "";
		}

		results.append(header);
		results.append("\r\n");

		String message;
		SinaburoEscapeTool escapeTool = new SinaburoEscapeTool();

		while (reports.hasNext()) {
			message = null;
			ActionMessage report = (ActionMessage)reports.next();
			if (resources != null && report.isResource()) {
				message = resources.getMessage(locale, report.getKey(), report.getValues());
			}
			results.append(prefix);
			if (message != null) {
				results.append(message);
			} else {
				results.append(escapeTool.html(report.getKey()));
			}
			results.append(suffix);
			results.append("\r\n");
		}
		results.append(footer);
		results.append("\r\n");

		return results.toString();
	}

	public String getProperty(String key) {
		return PropertyUtil.getProperty(key);
	}

	/**
	 * ログインユーザー情報取得 Memberテーブルの情報
	 * @return ログインユーザー情報取得
	 */
	public Member getUserInfo(){
		AuthenticatedTokenVO token = (AuthenticatedTokenVO)session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
		if(token == null){
			return new Member();
		}

		return token.member;
	}

	/**
	 * ログインユーザー情報取得 Memberテーブルの情報
	 * @return ログインユーザー情報取得
	 */
	public AdminUser getAdminUserInfo(){
		AuthenticatedTokenVO token = (AuthenticatedTokenVO)session.getAttribute(AttrKey.AUTHENTICATED_TOKEN);
		if(token == null){
			return new AdminUser();
		}

		return token.adminUser;
	}



	/**
	 * 数字変換可能valueにコンマを追加する。
	 * @param value 数字変換可能value
	 * @return valueにコンマ追加
	 */
    public static String getNumberFormatStr(Object value){
    	if(!StringUtil.isNumber((value+""))){
    		return "0";
    	}
    	return String.format("%1$,3d", Long.parseLong(value.toString()));
    }

    /**
     * application_ja.propertiesから値を取得する。
     * @return
     */
    public String getMessage(String key){
    	return SinaburoViewUtil.getMessage(key);

    }

    public void saveToken(){
    	TokenProcessor.getInstance().saveToken(request);
    }

//    public String makeToken(){
//    		session.getAttribute("Globals.TRANSACTION_TOKEN_KEY");
//    	return "";
//
//    }


    public TestDto sessionkey(){
    	request.getAttribute("testDto");
    	return (TestDto)session.getAttribute("testDto");
    }

    /**
     * 改行コードをBRに変換する。
     * @param arg
     * @return
     */
    public String newLineToBr(String arg){
    	return StringUtil.isBlank(arg) ? arg : arg.replace(SinaburoConstant.newLine.SYSTEM, "</BR>");
    }

    public String addSlashDate(String arg){
    	if(arg == null){
    		return arg;
    	}
    	String val = arg;

    	if (arg.length() == 8) {
    		val =  SinaburoUtil.convertStringDateToFormat(arg, "/");
    	}
    	if (arg.length() == 6) {
    		val =  SinaburoUtil.convertStringDateToFormat2(arg, "/");
    	}
    	return val;
    }

    public String addSlashTime(String arg){
    	if(arg == null){
    		return arg;
    	}
    	String val = arg;

    	val =  SinaburoUtil.convertStringTimeToFormat(arg, "/");

    	return val;
    }

    /**
     * 今日の日付をyyyy/MM/ddで返す。
     * @return
     */
    public String getToDay(){
    	return  addSlashDate(SinaburoUtil.getToDayString());

    }

    /**
     * クリップボードを取得する。
     * @return
     */
    public static String getClipboardString() {
		Toolkit kit = Toolkit.getDefaultToolkit();
		Clipboard clip = kit.getSystemClipboard();

		try {
			return (String) clip.getData(DataFlavor.stringFlavor);
		} catch (UnsupportedFlavorException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
	}

    /**
     * クリップボードを設定する。
     * @return
     */
    public static void setClipboardString(String str) {
		Toolkit kit = Toolkit.getDefaultToolkit();
		Clipboard clip = kit.getSystemClipboard();

		StringSelection ss = new StringSelection(str);
		clip.setContents(ss, ss);
	}

    /**
     * フルパスから、ファイル名だけ取得する。
     * @return
     */
    public static String getFileName(String fullPath/*,String split*/){
    	String split= "/";//split==null ? "/" : split;
    	if(fullPath.lastIndexOf(split) == -1){
    		return fullPath;
    	}
    	return fullPath.substring(fullPath.lastIndexOf(split)+1);
    }

    public Boolean isNotEmpty(Object list){

    	Boolean isEmplty = new ListTool().isEmpty(list);
    	if(isEmplty == null){
    		return false;
    	}
    	return  !isEmplty;
    }

    public Boolean isEmpty(String arg){
    	return StringUtil.isBlank(arg);
    }

    public String addNewLine(String arg){
    	return addNewLine(arg,30);
    }

    public String addNewLine(String arg,Integer count){
    	StringBuffer result = new StringBuffer();
    	String [] lines = arg.split("\r\n");
    	for (int i = 0; i < lines.length; i++) {
    		StringBuffer sb= new StringBuffer(lines[i]);
    		for(int j=count; j < sb.length();j+=count+2){
    			sb.insert(j,"\r\n");
    		}
    		result.append(sb);
		}
    	return result.toString();

    }

    public  String getSubStringByte(String arg){
    	return getSubStringByte(arg,12);
    }

    public  String getSubStringByte(String src,int len){
    	  int dstlen = 0;
    	  for(int i = 0;i < src.length() ;i++){
    	    dstlen += (src.charAt(i) <= 0xff ? 1 : 2);
    	    if(dstlen > len)
    	    return src.substring(0,i)+"..";
    	  }
    	  return src;
    }
    
    
    public String toShiftKARA() throws UnsupportedEncodingException{
    	return new String("~".getBytes(), "Shift_JIS");
    	
    }
//    public static void main(String[] args) {
//		System.out.println(getSubStringByte("指名指"));
//	}

}