/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：顧客管理システム
*   ソースファイル名：JCKLcsUtilCommon.java
*   作成者          ：富士通
*   日付            ：2011年12月05日
*＜機能概要＞
*   顧客(LCS)のAPI連携処理のうち、処理層に依存しない共通機能を提供します。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/12/05   FJ          新規作成
*
**********************************************************************/
package eo.common.util;

import static eo.common.constant.JCKStrConst.PMP_KATAKANA_CHOKUON;
import static eo.common.constant.JCKStrConst.PMP_KATAKANA_YOUON;
import static eo.common.constant.JCKStrConst.PMP_NAME_DELIMITER;
import static eo.common.constant.JCKStrConst.OPTINM_NO_HTML_MAIL_FOR_PMP;
import static eo.common.constant.JCKStrConst.OPTINM_NO_HTML_MAIL_FOR_EO;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;

/**
 * 顧客(LCS)のAPI連携処理のうち、処理層に依存しない共通機能を提供します。
 *
 */
public class JCKLcsCommonUtil extends JPCUtilCommon
{
	
	/**
	 * オブジェクトがNULL、または空文字か判定します。
	 * <br>
	 * @param val 判定するオブジェクト
	 * @return NULL または空文字の場合はtrue
	 */
	public static boolean isNullOrBlank(Object val)
	{
		return JPCCommonUtil.isNull(val);
	}

	/**
	 * リストがNULL、または０件か判定します。
	 * <br>
	 * @param list 判定するリストオブジェクト
	 * @return NULL または０件のリストの場合はtrue
	 */
	@SuppressWarnings("unchecked")
	public static boolean isNullOrEmpty(List list) 
	{
		return ((list == null) || (list.isEmpty())) ? true : false;
	}

	/**
	 * 指定された文字列が、配列に存在するかチェックします。
	 * @param val チェック対象の文字列
	 * @param strAry 存在チェックする文字列配列
	 * @return true:存在する、false:存在しない
	 */
	public static boolean inArray(String val, String...strAry)
	{
		val = (val != null) ? val : "";
		for (String chkStr : strAry)
		{
			chkStr = (chkStr != null) ? chkStr : "";
			if (chkStr.equals(val)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 日付を加算します。<br />
	 * @param targetDate
	 * @param day
	 * @return String
	 */
	public static String addDay(String targetDate, int day)
	{
		
		Calendar cal = new GregorianCalendar();

		cal.set(Calendar.YEAR, Integer.parseInt(targetDate.substring(0, 4)));
		cal.set(Calendar.MONTH, Integer.parseInt(targetDate.substring(4, 6)) - 1);
		cal.set(Calendar.DATE, Integer.parseInt(targetDate.substring(6, 8)));

		cal.add(Calendar.DATE, day);

		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		
		return sdf.format(cal.getTime());
	}

	/**
	 * 姓の取得(PMP連携用)。<br />
	 * <pre>お客様名を姓、名に分割し姓を返却します。
	 * ※PMP連携時にはFirstNameは名ではなく姓となる為、要注意。<pre>
	 * @param fullName 姓名
	 * @return 姓
	 */
	public static String getFirstNameForPmp(String fullName)
	{
		String[] custNameAry = ((fullName != null) ? fullName : "").split(PMP_NAME_DELIMITER, 2);
		return custNameAry[0];
	}

	/**
	 * 名の取得(PMP連携用)。<br />
	 * <pre>お客様名を姓、名に分割し姓を返却します。
	 * ※PMP連携時にはSecondNameは姓ではなく名となる為、要注意。</pre>
	 * @param fullName 姓名
	 * @return 名
	 */
	public static String getSecondNameForPmp(String fullName)
	{
		String[] custNameAry = ((fullName != null) ? fullName : "").split(PMP_NAME_DELIMITER, 2);
		return (custNameAry.length > 1) ? custNameAry[1] : "";
	}

	/**
	 * 年齢フラグ取得<br />
	 * @param birthday 生年月日
	 * @param opeDate 運用日付
	 * @return String 年齢フラグ
	 */
	public static String getAgeFlg(String birthday, String opeDate)
	{
		//運用日付を年（西暦）、月、日に分割
		int opeDateYear = Integer.parseInt(opeDate.substring(0, 4));
		int opeDateMonth = Integer.parseInt(opeDate.substring(4, 6));
		int opeDateDay = Integer.parseInt(opeDate.substring(6, 8));
		//年齢
		int nenrei = 0;
		//年齢フラグ（初期値を設定）
		String ageFlg = "";

		if(birthday == null || "".equals(birthday))
		{
			ageFlg = "0000";
			return ageFlg;
		}
		
		try
		{
			//生年月日を年（西暦）、月、日に分割
			int birthdayYear = Integer.parseInt(birthday.substring(0, 4));
			int birthdayMonth = Integer.parseInt(birthday.substring(4, 6));
			int birthdayDay = Integer.parseInt(birthday.substring(6, 8));

			//年齢の取得
			nenrei = opeDateYear - birthdayYear;
			if((birthdayMonth > opeDateMonth) || ((birthdayMonth == opeDateMonth) && (birthdayDay > opeDateDay)))
			{
				nenrei--;
			}
		}
		catch(Exception e)
		{
			ageFlg = "0000";
		}
		
		//年齢フラグの設定
		if("0000".equals(ageFlg))
		{
			
		}
		else if (nenrei < 12)
		{
			ageFlg = "1000";
		}
		else if(nenrei >= 12 && nenrei < 15)
		{
			ageFlg = "2000";
		}
		else if(nenrei >= 15 && nenrei < 18)
		{
			ageFlg = "3000";
		}
		else if(nenrei >= 18 && nenrei < 20)
		{
			ageFlg = "4000";
		}
		else if(nenrei >= 20 && nenrei < 21)
		{
			ageFlg = "5000";
		}
		else if(nenrei >= 21)
		{
			ageFlg = "6000";
		}

		return ageFlg;
	}

	/**
	 * 対象文字列の拗音を直音文字に変換して返します。<br />
	 * @param targetValue 対象文字列
	 * @return 変換後文字列
	 */
	public static String replaceYouonToChokuon(String targetValue)
	{
		// 引数の対象文字列がnullの場合
		if (targetValue == null)
		{
			// 空文字を返す
			return "";
		}

		for(int i = 0; i < PMP_KATAKANA_YOUON.length; i++)
		{
			targetValue = targetValue.replaceAll(PMP_KATAKANA_YOUON[i], PMP_KATAKANA_CHOKUON[i]);
		}
		
		// 変換後文字列を返す
		return targetValue;
	}

	/**
	 * 日時文字列フォーマット(AxM AdminAPI用)。<br />
	 * <style type="text/css">table { border-collapse:collapse; } th {background:#c0c0c0;} th,td { border:1px solid #000000; }</style>
	 * ≪編集例≫<br />
	 * <table cellspacing="0">
	 * <tr><th>編集前</th><th>編集後</th><th>補足</th></tr>
	 * <tr><td nowrap>20120216</td><td nowrap>20120216000000</td><td>不足桁は0埋めされる</td></tr>
	 * <tr><td nowrap>20120216174932</td><td nowrap>20120216174932</td><td>14桁丁度の場合はそのまま</td></tr>
	 * <tr><td nowrap>2012-02-16 17:49:32</td><td nowrap>20120216174932</td><td>一旦アンフォーマット後に再フォーマットされる</td></tr>
	 * <tr><td nowrap>2012-02-16 17:49:32.498000000</td><td nowrap>20120216174932</td><td>一旦アンフォーマット後に再フォーマットされる</td></tr>
	 * </table>
	 * @param datetime 日時文字列
	 * @return 日時文字列(形式 : YYYYMMDDHH24MISS) ※14桁
	 */
	public static String formatDtm4AxmAdminApi(String datetime)
	{
		// NULL または空文字の場合は空文字を返却
		if (isNullOrBlank(datetime))
		{
			return "";
		}

		// 数値以外は削除
		datetime = datetime.replaceAll("[^0-9]", "") + "00000000000000";

		return datetime.substring(0,14);
	}

	/**
	 * 日時文字列フォーマット(AxM レプリカ連携API用)。<br />
	 * <style type="text/css">table { border-collapse:collapse; } th {background:#c0c0c0;} th,td { border:1px solid #000000; }</style>
	 * ≪編集例≫<br />
	 * <table cellspacing="0">
	 * <tr><th>編集前</th><th>編集後</th><th>補足</th></tr>
	 * <tr><td nowrap>20120216174932498</td><td nowrap>2012-02-16 17:49:32.498000000</td><td>不足桁は0埋めされる</td></tr>
	 * <tr><td nowrap>20120216174932</td><td nowrap>2012-02-16 17:49:32.000000000</td><td>不足桁は0埋めされる</td></tr>
	 * <tr><td nowrap>2012-02-16 17:49:32.498000000</td><td nowrap>2012-02-16 17:49:32.498000000</td><td>一旦アンフォーマット後に再フォーマットされる</td></tr>
	 * <tr><td nowrap>2012-02-16 17:49:32</td><td nowrap>2012-02-16 17:49:32.000000000</td><td>一旦アンフォーマット後に再フォーマットされる</td></tr>
	 * </table>
	 * @param datetime 日時文字列(14桁以上)
	 * @return 日時文字列(形式 : YYYY-MM-DD HH24:MI:SS.FF9)
	 */
	public static String formatDtm4AxmReplicaApi(String datetime)
	{
		// NULLの場合は空文字を返却
		if (datetime == null)
		{
			return "";
		}

		// 14文字以下の場合はそのまま返却
		datetime = datetime.replaceAll("[^0-9]", "");
		if (datetime.length() < 14)
		{
			return datetime;
		}

		datetime = datetime + "000000000";
		String yyyy = datetime.substring(0,4);
		String mm   = datetime.substring(4,6);
		String dd   = datetime.substring(6,8);
		String hh   = datetime.substring(8,10);
		String mi   = datetime.substring(10,12);
		String ss   = datetime.substring(12,14);
		String ff   = datetime.substring(14,23);

		return yyyy + "-" + mm + "-" + dd + " " + hh + ":" + mi + ":" + ss + "." + ff;
	}

	/**
	 * リスト並び替え(マップキー指定)。<br />
	 * マップを持つリスト(List<Map>)を指定されたキーの値で並び替えます。<br />
	 * ※降順の並べ替えには対応していません。<br />
	 * <pre>
	 * 例)
	 *   [0] = { "id" : "A05", "age" : 10 }
	 *   [1] = { "id" : "A03", "age" : 5 }
	 *   [2] = { "id" : "A01", "age" : 10 }
	 *   
	 *   上記のリストに対して <i>sortMapList(list, "age", "id")</i> を使用すると、
	 *   リストは下記のように並び変わります。
	 *
	 *   [0] = { "id" : "A03", "age" : 5 }
	 *   [1] = { "id" : "A01", "age" : 10 }
	 *   [2] = { "id" : "A05", "age" : 10 }
	 * </pre>
	 * @param list 並び替えるリスト
	 * @param sortKeys 並び替えに使用するマップキー名(複数指定可)
	 */
	@SuppressWarnings("unchecked")
	public static void sortMapList(List list, String... sortKeys) throws ClassCastException
	{
		if (list != null)
		{
			MapListComparator comparator = new JCKLcsCommonUtil().new MapListComparator(sortKeys);
			Collections.sort(list, comparator);
		}
	}

	/**
	 * マップリスト並べ替え用のComparator。<br />
	 */
	@SuppressWarnings("unchecked")
	private class MapListComparator implements Comparator
	{
		/** 並べ替えに使用するマップキー名 */
		private String[] sortKeys = null;

		/**
		 * コンストラクタ
		 * @param sortKeys
		 */
		MapListComparator(String... sortKeys)
		{
			this.sortKeys = sortKeys;
		}

		/**
		 * 要素比較。<br />
		 */
		@Override
		public int compare(Object obj1, Object obj2)
		{
			Map map1 = (Map) obj1;
			Map map2 = (Map) obj2;
			StringBuffer mainSb1 = new StringBuffer();
			StringBuffer mainSb2 = new StringBuffer();
			for (String sortKey : sortKeys)
			{
				Object subObj1 = map1.get(sortKey);
				Object subObj2 = map2.get(sortKey);
				String subVal1 = (subObj1 != null) ? subObj1.toString() : "";
				String subVal2 = (subObj2 != null) ? subObj2.toString() : "";
				int maxlen = (subVal1.length() > subVal2.length()) ? subVal1.length() : subVal2.length();
				int loopCnt1 = maxlen - subVal1.length();
				int loopCnt2 = maxlen - subVal2.length();

				StringBuffer subSb1 = null;
				StringBuffer subSb2 = null;
				String sufStr1 = "";
				String sufStr2 = "";
				if ((subObj1 instanceof Integer) || (subObj2 instanceof Integer) || (subObj1 instanceof Long) || (subObj2 instanceof Long))
				{
					subSb1 = new StringBuffer();
					subSb2 = new StringBuffer();
					sufStr1 = subVal1;
					sufStr2 = subVal2;
				} else
				{
					subSb1 = new StringBuffer(subVal1);
					subSb2 = new StringBuffer(subVal2);
				}
				for (int i = 0; i < loopCnt1; i++)
				{
					subSb1.append(" ");
				}
				for (int i = 0; i < loopCnt2; i++)
				{
					subSb2.append(" ");
				}
				mainSb1.append(subSb1);
				mainSb2.append(subSb2);
				mainSb1.append(sufStr1);
				mainSb2.append(sufStr2);
			}
			if (mainSb1.toString().compareTo(mainSb2.toString()) > 0)
			{
				return 1;
			} else
			{
				return -1;
			}
		}
	}

	/**
	 * 文字列変換(文字列配列→文字列)。<br />
	 * ※文字列配列をカンマ区切りの１文字列に結合します。<br />
	 * @param strAry 文字列配列
	 * @return 変換後文字列
	 */
	public static String convert2String(String[] strAry)
	{
		return convert2String(strAry, "");
	}

	/**
	 * 文字列変換(文字列配列→文字列)。<br />
	 * ※文字列配列をカンマ区切りの１文字列に結合します。<br />
	 * @param strAry 文字列配列
	 * @param quote クォート文字
	 * @return 変換後文字列
	 */
	public static String convert2String(String[] strAry, String quote)
	{
		quote = (quote != null) ? quote : "";
		StringBuffer sb = new StringBuffer();
		for (String str : strAry)
		{
			if (sb.length() > 0)
			{
				sb.append(",");
			}
			sb.append(quote + str + quote);
		}
		return sb.toString();
	}

	/**
	 * 文字列結合。<br />
	 * 複数の文字列を1つの文字列に結合する。<br />
	 * @param str 結合する文字列
	 * @return 結合後文字列
	 */
	public static String concatString(String...strs)
	{
		StringBuffer sb = new StringBuffer();
		for (String str : strs)
		{
			String txt = (str != null) ? str : "";
			sb.append(txt);
		}
		return sb.toString();
	}

	/**
	 * 契約者住所を３分割します。(PMPへのデータ返却用)<br />
	 * @param stateNm 都道府県
	 * @param cityNm 市区町村
	 * @param oaztsuNm 大字通称名
	 * @param azchoNm 字丁目名
	 * @param bnchigo 番地号
	 * @param adrttm 建物名
	 * @param adrrm 部屋番号
	 * @return String[3] {住所(都道府県/市区町村), 住所(上記以外), 住所(マンション名等) }
	 */
	public static String[] convAdForPmp(String stateNm, String cityNm, String oaztsuNm, String azchoNm, String bnchigo, String adrttm, String adrrm)
	{
		return JZMCommonUtil.getPtn04(stateNm, cityNm, oaztsuNm, azchoNm, bnchigo, adrttm, adrrm);
	}

	/**
	 * コンテンツ住所を３分割します。(PMPへのデータ返却用)<br />
	 * @param bnchigo コンテンツ番地号
	 * @param adrttm コンテンツ建物名
	 * @param adrrm コンテンツ部屋番号
	 * @param strAdBnktPst コンテンツ住所分割位置
	 * @return String[3] {住所(都道府県/市区町村), 住所(上記以外), 住所(マンション名等) }
	 */
	public static String[] convAdForPmp(String bnchigo, String adrttm, String adrrm, String strAdBnktPst)
	{
		String[] address = null;
		if ((strAdBnktPst != null) && (!strAdBnktPst.isEmpty()))
		{
			address = JZMCommonUtil.getPtn03(bnchigo, adrttm, adrrm, Integer.parseInt(strAdBnktPst));
		}
		else
		{
			address = new String[3];
			address[0] = bnchigo;
			address[1] = "";
			address[2] = adrttm + adrrm;
		}
		return address;
	}

	/**
	 * 契約者住所を３分割します。(eo顧客基幹へのデータ登録用)<br />
	 * @param stateNm 都道府県
	 * @param cityNm 市区町村
	 * @param oaztsuNm 大字通称名
	 * @param azchoNm 字丁目名
	 * @param bnchigo 番地号
	 * @param adrttm 建物名
	 * @param adrrm 部屋番号
	 * @return String[3] { コンテンツ番地号, コンテンツ建物名, コンテンツ部屋番号, コンテンツ住所分割開始位置 }
	 */
	public static String[] convAdForEo(String stateNm, String cityNm, String oaztsuNm, String azchoNm, String bnchigo, String adrttm, String adrrm)
	{
		return JZMCommonUtil.getPtn05(stateNm, cityNm, oaztsuNm, azchoNm, bnchigo, adrttm, adrrm);
	}

	/**
	 * オプトインメール番号をPMP用に変換します。<br />
	 * @param columnNumber 項番
	 * @return String PMP用項番
	 */
	public static String convOptinmNoForPmp(String columnNumber)
	{
		String retCd = columnNumber;
		
		if (OPTINM_NO_HTML_MAIL_FOR_EO.equals(columnNumber))
		{
			retCd = OPTINM_NO_HTML_MAIL_FOR_PMP;
		}
		
		return retCd;
	}

	/**
	 * オプトインメール番号をeo用に変換します。<br />
	 * @param columnNumber 項番
	 * @return String eo用項番
	 */
	public static String convOptinmNoForEo(String columnNumber)
	{
		String retCd = columnNumber;
		
		if (OPTINM_NO_HTML_MAIL_FOR_PMP.equals(columnNumber))
		{
			retCd = OPTINM_NO_HTML_MAIL_FOR_EO;
		}
		
		return retCd;
	}

}
