package com.kurukurupapa.tryandroid.fw.util;

import java.lang.reflect.Field;

import com.kurukurupapa.tryandroid.fw.FwException;
import com.kurukurupapa.tryandroid.fw.annotation.Exclude;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.preference.PreferenceManager;

public class PreferenceUtil {

	private static void copyPreferenceItem(SharedPreferences srcPreference,
			Object destObj, Field field) {
		String key = getPreferenceKeyName(field);
		if (field.getType() == boolean.class) {
			boolean defaultValue = ReflectionUtil.getBooleanFieldValue(destObj,
					field);
			boolean value = srcPreference.getBoolean(key, defaultValue);
			ReflectionUtil.setFieldValue(destObj, field, value);

		} else if (field.getType() == int.class) {
			int defaultValue = ReflectionUtil.getIntFieldValue(destObj, field);
			int value = srcPreference.getInt(key, defaultValue);
			ReflectionUtil.setFieldValue(destObj, field, value);

		} else if (field.getType() == long.class) {
			long defaultValue = ReflectionUtil
					.getLongFieldValue(destObj, field);
			long value = srcPreference.getLong(key, defaultValue);
			ReflectionUtil.setFieldValue(destObj, field, value);

		} else if (field.getType() == float.class) {
			float defaultValue = ReflectionUtil.getFloatFieldValue(destObj,
					field);
			float value = srcPreference.getFloat(key, defaultValue);
			ReflectionUtil.setFieldValue(destObj, field, value);

		} else if (field.getType() == String.class) {
			String defaultValue = (String) ReflectionUtil.getFieldValue(
					destObj, field);
			String value = srcPreference.getString(key, defaultValue);
			ReflectionUtil.setFieldValue(destObj, field, value);

		} else {
			throw new FwException(
					"The type of the field doesn't correspond. Type="
							+ field.getType());
		}
	}

	public static <T> T getPreferenceDto(Context context, Class<T> destDtoClass) {
		// DTOインスタンスを作成
		T obj = ReflectionUtil.newInstance(destDtoClass);

		// DTOに値を詰める
		copyPreferenceDto(context, obj);
		return obj;
	}

	public static boolean getValue(Context context, String key,
			boolean defaultValue) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		// 値の取得
		return sp.getBoolean(key, defaultValue);
	}

	public static int getValue(Context context, String key, int defaultValue) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		// 値の取得
		return sp.getInt(key, defaultValue);
	}

	public static long getValue(Context context, String key, long defaultValue) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		// 値の取得
		return sp.getLong(key, defaultValue);
	}

	public static float getValue(Context context, String key, float defaultValue) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		// 値の取得
		return sp.getFloat(key, defaultValue);
	}

	public static String getValue(Context context, String key,
			String defaultValue) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		// 値の取得
		return sp.getString(key, defaultValue);
	}

	public static boolean getValueWithGetterName(Context context,
			String methodName, boolean defaultValue) {
		return PreferenceUtil.getValue(context,
				getKeyWithGetterName(methodName), defaultValue);
	}

	public static int getValueWithGetterName(Context context,
			String methodName, int defaultValue) {
		return PreferenceUtil.getValue(context,
				getKeyWithGetterName(methodName), defaultValue);
	}

	public static long getValueWithGetterName(Context context,
			String methodName, long defaultValue) {
		return PreferenceUtil.getValue(context,
				getKeyWithGetterName(methodName), defaultValue);
	}

	public static float getValueWithGetterName(Context context,
			String methodName, float defaultValue) {
		return PreferenceUtil.getValue(context,
				getKeyWithGetterName(methodName), defaultValue);
	}

	public static String getValueWithGetterName(Context context,
			String methodName, String defaultValue) {
		return PreferenceUtil.getValue(context,
				getKeyWithGetterName(methodName), defaultValue);
	}

	public static String getKeyWithGetterName(String methodName) {
		return StringUtil.toUnderScore(StringUtil.trimStart(methodName, "get"));
	}

	public static String getKeyWithSetterName(String methodName) {
		return StringUtil.toUnderScore(StringUtil.trimStart(methodName, "set"));
	}

	public static void copyPreferenceDto(Context context, Object destDto) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);

		// DTOに値を詰める
		for (Field field : destDto.getClass().getFields()) {
			if (field.getAnnotation(Exclude.class) != null) {
				continue;
			}
			copyPreferenceItem(sp, destDto, field);
		}

		LogUtil.d(destDto.toString());
	}

	private static String getPreferenceKeyName(Field field) {
		return StringUtil.toUnderScore(field.getName());
	}

	public static void clear(Context context) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// クリア
		editor.clear();

		// コミット
		editor.commit();
		LogUtil.i("Committed");
	}

	public static void putPreferenceDto(Context context, Object dto) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		for (Field field : dto.getClass().getFields()) {
			putValue(dto, field, editor);
		}

		// コミット
		editor.commit();
		LogUtil.i("Committed");
	}

	public static void putPreferenceDto(Context context, Object dto,
			String fieldName) {
		Field field = ReflectionUtil.getField(dto, fieldName);
		putPreferenceDto(context, dto, field);
	}

	public static void putPreferenceDto(Context context, Object dto, Field field) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		putValue(dto, field, editor);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + field.getName());
	}

	public static void putValue(Context context, String key, boolean value) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		editor.putBoolean(key, value);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + key + "=" + value);
	}

	public static void putValue(Context context, String key, int value) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		editor.putInt(key, value);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + key + "=" + value);
	}

	public static void putValue(Context context, String key, long value) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		editor.putLong(key, value);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + key + "=" + value);
	}

	public static void putValue(Context context, String key, float value) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		editor.putFloat(key, value);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + key + "=" + value);
	}

	public static void putValue(Context context, String key, String value) {
		// プリファレンスの取得
		SharedPreferences sp = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = sp.edit();

		// 値を設定
		editor.putString(key, value);

		// コミット
		editor.commit();
		LogUtil.i("Committed " + key + "=" + value);
	}

	public static void putValueWithSetterName(Context context,
			String methodName, boolean value) {
		putValue(context, getKeyWithSetterName(methodName), value);
	}

	public static void putValueWithSetterName(Context context,
			String methodName, int value) {
		putValue(context, getKeyWithSetterName(methodName), value);
	}

	public static void putValueWithSetterName(Context context,
			String methodName, long value) {
		putValue(context, getKeyWithSetterName(methodName), value);
	}

	public static void putValueWithSetterName(Context context,
			String methodName, float value) {
		putValue(context, getKeyWithSetterName(methodName), value);
	}

	public static void putValueWithSetterName(Context context,
			String methodName, String value) {
		putValue(context, getKeyWithSetterName(methodName), value);
	}

	private static void putValue(Object srcObj, Field srcField,
			Editor destEditor) {
		String key = getPreferenceKeyName(srcField);
		if (srcField.getType() == boolean.class) {
			boolean value = ReflectionUtil.getBooleanFieldValue(srcObj,
					srcField);
			destEditor.putBoolean(key, value);
			LogUtil.i(key + "=[" + value + "]");
		} else if (srcField.getType() == int.class) {
			int value = ReflectionUtil.getIntFieldValue(srcObj, srcField);
			destEditor.putInt(key, value);
			LogUtil.i(key + "=[" + value + "]");
		} else if (srcField.getType() == long.class) {
			long value = ReflectionUtil.getLongFieldValue(srcObj, srcField);
			destEditor.putLong(key, value);
			LogUtil.i(key + "=[" + value + "]");
		} else if (srcField.getType() == float.class) {
			float value = ReflectionUtil.getFloatFieldValue(srcObj, srcField);
			destEditor.putFloat(key, value);
			LogUtil.i(key + "=[" + value + "]");
		} else if (srcField.getType() == String.class) {
			String value = ReflectionUtil.getStringFieldValue(srcObj, srcField);
			destEditor.putString(key, value);
			LogUtil.i(key + "=[" + value + "]");
		} else {
			throw new FwException(
					"The type of the field doesn't correspond. Type="
							+ srcField.getType());
		}
	}

}
