package jp.agentec.abook.abv.bl.acms.client.json;

import jp.agentec.abook.abv.bl.common.exception.ABVException;
import jp.agentec.abook.abv.bl.common.exception.ABVExceptionCode;
import jp.agentec.abook.abv.bl.common.exception.AcmsException;
import jp.agentec.abook.abv.bl.common.exception.JSONValidationException;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.adf.core.CloneableObject;
import jp.agentec.adf.util.DateTimeFormat;
import jp.agentec.adf.util.DateTimeUtil;
import jp.agentec.adf.util.StringUtil;

import org.json.adf.JSONException;
import org.json.adf.JSONObject;

import java.util.Date;

public abstract class AcmsJSONParser extends CloneableObject {
	/**
	 * {@link AcmsJSONParser} クラスのインスタンスを初期化します。
	 * @param jsonString このインスタンスが解析するJSON文字列を指定します。
	 * @throws ABVException 
	 * @since 1.0.0
	 */
	public AcmsJSONParser(String jsonString) throws AcmsException {
		try {
			parse(jsonString);
		} catch (Exception e) {
			Logger.e("AcmsJSONParser", "Invalid server response.", e);
			throw new AcmsException(ABVExceptionCode.S_E_ACMS_INVALID_RESPONSE, null);
		}
	}
	
	/**
	 * JSON文字列をこのクラスを継承するオブジェクトに変換します。
	 * @param jsonString 変換するJSON文字列です。
	 * @throws Exception JSON文字列が正しくありません。
	 * @since 1.0.0
	 */
	private void parse(String jsonString) throws JSONValidationException, JSONException {
		if (StringUtil.isNullOrWhiteSpace(jsonString)) {
			throw new JSONValidationException(jsonString, "jsonString not allowed null or white space.");
		}
		
		JSONObject json = new JSONObject(jsonString);
		parse(json);
	}
	
	/**
	 * {@link JSONObject} をこのクラスにマッピングします。
	 * @param json このクラスにマッピングする {@link JSONObject} です。
	 * @since 1.0.0
	 */
	protected abstract void parse(JSONObject json) throws JSONValidationException, JSONException;
	
	/**
	 * jsonからString型を取得する。キーがない場合defを返す。
	 * 
	 * @param json
	 * @param key
	 * @param def
	 * @return
	 */
	protected String getString(JSONObject json, String key, String def) {
		if (json.has(key)) {
			return json.getString(key);
		} else {
			return def;
		}
	}

	/**
	 * jsonからString型を取得する。キーがない場合JSONValidationExceptionを投げる。
	 * 
	 * @param json
	 * @param key
	 * @return
	 * @throws JSONValidationException
	 */
	protected String getString(JSONObject json, String key) throws JSONValidationException {
		if (json.has(key)) {
			return json.getString(key);
		} else {
			throw new JSONValidationException(json.toString(), key + " property not found.");
		}
	}

	/**
	 * jsonからString型を取得する。キーがない場合defを返す。
	 * 
	 * @param json
	 * @param key
	 * @param def
	 * @return
	 */
	protected int getInt(JSONObject json, String key, int def) throws JSONValidationException {
		if (json.has(key)) {
			return json.getInt(key);
		} else {
			return def;
		}
	}

	/**
	 * jsonからint型を取得する。キーがない場合JSONValidationExceptionを投げる。
	 * 
	 * @param json
	 * @param key
	 * @return
	 * @throws JSONValidationException
	 */
	protected int getInt(JSONObject json, String key) throws JSONValidationException {
		if (json.has(key)) {
			return json.getInt(key);
		} else {
			throw new JSONValidationException(json.toString(), key + " property not found.");
		}
	}

	/**
	 * jsonからlong型を取得する。キーがない場合JSONValidationExceptionを投げる。
	 * 
	 * @param json
	 * @param key
	 * @return
	 * @throws JSONValidationException
	 */
	protected long getLong(JSONObject json, String key) throws JSONValidationException {
		if (json.has(key)) {
			return json.getLong(key);
		} else {
			throw new JSONValidationException(json.toString(), key + " property not found.");
		}
	}

	protected long getLongOrZero(JSONObject json, String key) {
		if (json.has(key)) {
			return json.getLong(key);
		} else {
			return 0;
		}
	}

	protected Long getLongOrNull(JSONObject json, String key) {
		if (json.has(key)) {
			return json.getLong(key);
		} else {
			return null;
		}
	}

	protected int getIntOrZero(JSONObject json, String key) {
		if (json.has(key)) {
			return json.getInt(key);
		} else {
			return 0;
		}
	}

	protected int getIntOrDef(JSONObject json, String key, int def) {
		if (json.has(key)) {
			return json.getInt(key);
		} else {
			return def;
		}
	}

	protected Integer getIntOrNull(JSONObject json, String key) {
		if (json.has(key)) {
			return json.getInt(key);
		} else {
			return null;
		}
	}

	protected String getStringOrNull(JSONObject json, String key) {
		if (json.has(key)) {
			return json.getString(key);
		} else {
			return null;
		}
	}

	protected Date getDateOrNull(JSONObject json, String key, String timeZone) {
		if (json.has(key)) {
			return DateTimeUtil.toDate(json.getString(key), timeZone, DateTimeFormat.yyyyMMddHHmmss_hyphen);
		} else {
			return null;
		}
	}

	protected Date getDateOrNull(JSONObject json, String key) {
		return getDateOrNull(json, key, "UTC");
	}
}
