/**
 * Copyright 2014 Hanei Management Co.,Ltd. 
 * 
 * This file is part of Jaxcel
 * 
 *  Jaxcel is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Jaxcel is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.hanei.jaxcel.report;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * EL式の解析、解析で使用するパラメータオブジェクトの保持を行う。<br>
 * 式言語エンジンにはJEXLを使用。
 * 
 * @version 1.00.00
 * @author noboru saito
 *
 */
public class ELManager {

	private static final Logger log = LoggerFactory.getLogger(ELManager.class);

	private final JexlEngine elEngine = new JexlEngine();
	private final JexlContext elContext = new MapContext();
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
	
	/**
	 * コンストラクタ
	 */
	public ELManager() {}

	/**
	 * コンストラクタ
	 * 
	 * @param parameter テンプレートに挿入するデータ
	 */
	public ELManager(Map<String, Object> parameter) {
		setParameter(parameter);
	}
	
	/**
	 * EL式解析で使用するオブジェクトをパラメータとしてセット
	 * 
	 * @param	parameter テンプレートに挿入するデータ
	 */
	public void setParameter(Map<String, Object> parameter) {
		log.trace("setParameter start");
		
		if(parameter != null) {
			if(parameter.entrySet().size() == 0) {
				log.debug("parameter is no entry");
			}
			else {
				for(Entry<String, Object> p : parameter.entrySet()) {
					elContext.set(p.getKey(), p.getValue());
					log.debug("parameter set: [{}]: {} {}", p.getKey(), p.getValue() == null ? "null" : p.getValue().getClass().getName(), p.getValue() == null ? "" : p.getValue().toString());
				}
			}
	    }
		else {
			log.debug("parameter is null");
		}

		log.trace("setParameter end");
	}
	
	/**
	 * EL式を解析。結果を返却する
	 * 
	 * @param expression	EL式
	 * @return				EL式の解析結果
	 */
	public Object evaluate(String expression) {
		log.trace("evaluate start");
		
		Object object = null;
		
		if(expression == null) {
			log.debug("expression is null");
		}
		else {
			log.debug("expression: {}", expression);
			Expression expr;
			try {
				expr = elEngine.createExpression(expression);
				object = expr.evaluate(elContext);
			}
			catch(Exception e) {
				log.error("evaluate error: {}", e.getLocalizedMessage(), e);
			}
		}
		
		if(object == null) {
			log.debug("evaluate result is null");
		}
		else {
			if(log.isDebugEnabled()) {
				log.debug("evaluate result: {}", object.toString());
				log.debug("evaluate result type: {}", object.getClass().getName());
			}
			// Date、Calendarならデフォルトフォーマットに置換
			if(object instanceof Date) {
				object = sdf.format(object);
			}
			else if(object instanceof Calendar) {
				// デフォルトロケールで文字列に置き換え
				object = sdf.format(((Calendar)object).getTime());
			}
		}
		
		log.trace("evaluate end");
		return object;
	}
}
