package online.struts;

import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

import core.config.Factory;

/**
 * BeanUtil
 *
 * @author Tadashi Nakayama
 */
public final class BeanUtil {

	/**
	 * コンストラクタ
	 */
	private BeanUtil() {
		throw new AssertionError();
	}

	/**
	 * プロパティ設定
	 * @param bean 設定対象Bean
	 * @param prop プロパティ
	 */
	public static void setPropertiesTo(final Object bean, final Map<String, String> prop) {
		Stream.of(bean.getClass().getMethods()).filter(Factory::isSetter).forEach(
			mt -> Stream.of(getObject(prop, mt)).filter(Objects::nonNull).forEach(
				o -> Factory.invoke(bean, mt, o)
			)
		);
	}

	/**
	 * プロパティオブジェクト取得
	 * @param prop プロパティマップ
	 * @param mt メソッド
	 * @return プロパティオブジェクト
	 */
	private static Object getObject(final Map<String, String> prop, final Method mt) {
		Object obj = getPropertyValue(prop, mt.getName().substring("set".length()));
		if (obj != null) {
			final var cls = mt.getParameterTypes()[0];
			if (!String.class.equals(cls)) {
				obj = Factory.construct(Factory.getConstructor(cls, String.class), obj);
			}
		}
		return obj;
	}

	/**
	 * プロパティ値取得
	 * @param prop プロパティマップ
	 * @param name 名前
	 * @return プロパティ値
	 */
	private static String getPropertyValue(final Map<String, String> prop, final String name) {
		var ret = prop.get(name);
		if (ret == null) {
			final var loc = name.offsetByCodePoints(0, 1);
			final var head = name.substring(0, loc);
			final var tail = name.substring(loc);
			ret = prop.get(head.toLowerCase(Locale.ENGLISH) + tail);
		}
		return ret;
	}
}
