
/**
 * Copyright (c) 2011-2019, James Zhan 詹波 (jfinal@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.tio.jfinal.template.expr.ast;

import org.tio.jfinal.kit.SyncWriteMap;
import org.tio.jfinal.template.expr.ast.FieldGetters.*;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * FieldKit
 */
public class FieldKit {
	
	private static FieldGetter[] getters = init();
	
	private static final HashMap<Object, FieldGetter> fieldGetterCache = new SyncWriteMap<Object, FieldGetter>(1024, 0.25F);
	
	/**
	 * 初始化官方默认 FieldGetter
	 * 
	 * 注意：
	 * 默认不启用 IsMethodFieldGetter，用户可以通过下面的代码启用：
	 * Engine.addLastFieldGetter(new FieldGetters.IsMethodFieldGetter());
	 * 
	 * 也可以通过直接调用 target.isXxx() 方法来达到与 target.xxx 表达式相同的目的
	 */
	private static FieldGetter[] init() {
		LinkedList<FieldGetter> ret = new LinkedList<FieldGetter>();
		
		ret.addLast(new GetterMethodFieldGetter(null));
		ret.addLast(new RealFieldGetter(null));
		ret.addLast(new ModelFieldGetter());
		ret.addLast(new RecordFieldGetter());
		ret.addLast(new MapFieldGetter());
		
		// 挪到第二的位置，addSharedObject(..., modelObj) 用法可以获取到 model 中的 public 属性
		// ret.addLast(new RealFieldGetter(null));
		ret.addLast(new ArrayLengthGetter());
		// ret.addLast(new IsMethodFieldGetter());
		
		return ret.toArray(new FieldGetter[ret.size()]);
	}
	
	public static FieldGetter getFieldGetter(Object key, Class<?> targetClass, String fieldName) {
		FieldGetter fieldGetter = fieldGetterCache.get(key);
		if (fieldGetter == null) {
			fieldGetter = doGetFieldGetter(targetClass, fieldName);	// 已确保不会返回 null
			fieldGetterCache.putIfAbsent(key, fieldGetter);
		}
		return fieldGetter;
	}
	
	private static FieldGetter doGetFieldGetter(Class<?> targetClass, String fieldName) {
		FieldGetter ret;
		for (FieldGetter fieldGetter : getters) {
			ret = fieldGetter.takeOver(targetClass, fieldName);
			if (ret != null) {
				return ret;
			}
		}
		return NullFieldGetter.me;
	}
	
	public static void addFieldGetter(int index, FieldGetter fieldGetter) {
		addFieldGetter(fieldGetter, index, true);
	}
	
	public static void addFieldGetterToLast(FieldGetter fieldGetter) {
		addFieldGetter(fieldGetter, null, true);
	}
	
	public static void addFieldGetterToFirst(FieldGetter fieldGetter) {
		addFieldGetter(fieldGetter, null, false);
	}
	
	// 当 Integer index 不为 null 时，boolean addLast 为无效参数
	private static synchronized void addFieldGetter(FieldGetter fieldGetter, Integer index, boolean addLast) {
		checkParameter(fieldGetter);
		
		LinkedList<FieldGetter> ret = getCurrentFieldGetters();
		if (index != null) {
			ret.add(index, fieldGetter);
		} else {
			if (addLast) {
				ret.addLast(fieldGetter);
			} else {
				ret.addFirst(fieldGetter);
			}
		}
		getters = ret.toArray(new FieldGetter[ret.size()]);
	}
	
	private static LinkedList<FieldGetter> getCurrentFieldGetters() {
		LinkedList<FieldGetter> ret = new LinkedList<FieldGetter>();
		for (FieldGetter fieldGetter : getters) {
			ret.add(fieldGetter);
		}
		return ret;
	}
	
	private static void checkParameter(FieldGetter fieldGetter) {
		if (fieldGetter == null) {
			throw new IllegalArgumentException("The parameter fieldGetter can not be null");
		}
		for (FieldGetter fg : getters) {
			if (fg.getClass() == fieldGetter.getClass()) {
				throw new RuntimeException("FieldGetter already exists : " + fieldGetter.getClass().getName());
			}
		}
	}
	
	public static synchronized void removeFieldGetter(Class<? extends FieldGetter> fieldGetterClass) {
		LinkedList<FieldGetter> ret = getCurrentFieldGetters();
		
		for (Iterator<FieldGetter> it = ret.iterator(); it.hasNext();) {
			if (it.next().getClass() == fieldGetterClass) {
				it.remove();
			}
		}
		
		getters = ret.toArray(new FieldGetter[ret.size()]);
	}
	
	public static void clearCache() {
		fieldGetterCache.clear();
	}
	
	/**
	 * 设置极速模式
	 * 
	 * 极速模式将生成代理对象来消除 java.lang.reflect.Method.invoke(...) 调用，
	 * 性能提升 12.9%
	 */
	public static synchronized void setFastMode(boolean fastMode) {
		if (fastMode) {
			if ( !contains(FastFieldGetter.class) ) {
				addFieldGetterToFirst(new FastFieldGetter());
			}
		} else {
			if (contains(FastFieldGetter.class)) {
				removeFieldGetter(FastFieldGetter.class);
			}
		}
	}
	
	/**
	 * 判断是否包含某个 FieldGetter
	 */
	public static boolean contains(Class<? extends FieldGetter> fieldGetterClass) {
		for (FieldGetter fg : getters) {
			if (fg.getClass() == fieldGetterClass) {
				return true;
			}
		}
		return false;
	}
}








