/*********************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JKKSvcKeiNoSaiban
*	ソースファイル名：JKKSvcKeiNoSaiban.java
*	作成者			：FJ)藤本
*	日付			：2016年04月18日
*＜機能概要＞
*	サービス契約番号採番クラスです。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v23.00.00	2016/04/18	FJ)藤本	【ANK-2783-00-00】お客さまＩＤ重複障害対応：採番ロジック見直し
*
**********************************************************************/
package eo.common.util;

import java.util.HashMap;

/**
 * <p>
 * サービス契約番号採番クラスです。
 * </p>
 * @author FJ
 */
public class JKKSvcKeiNoSaiban
{
	/** 接頭語(C) */
	private static final String PREFIX_C = "C";

	/** 変換表Ａ */
	private static final HashMap<String, String> CHANGE_LIST_A = new HashMap<String, String>();

	/**
	 * 英字・記号のマッピング配列
	 */
	private static final HashMap<String, String> MAPPING = new HashMap<String, String>();

	static
	{
		// 変換配列設定
		CHANGE_LIST_A.put("0", "ABCDEFGHJK");
		CHANGE_LIST_A.put("1", "LMNPRSTUVW");
		CHANGE_LIST_A.put("2", "XYZABCDEFG");
		CHANGE_LIST_A.put("3", "HJKLMNPRST");
		CHANGE_LIST_A.put("4", "UVWXYZABCD");
		CHANGE_LIST_A.put("5", "EFGHJKLMNP");
		CHANGE_LIST_A.put("6", "RSTUVWXYZA");
		CHANGE_LIST_A.put("7", "BCDEFGHJKL");
		CHANGE_LIST_A.put("8", "MNPRSTUVWX");
		CHANGE_LIST_A.put("9", "YZABCDEFGH");
	}

	static
	{
		// 英字・記号のマッピング配列設定
		MAPPING.put("@", "0");
		MAPPING.put("a", "1");
		MAPPING.put("b", "2");
		MAPPING.put("c", "3");
		MAPPING.put("d", "4");
		MAPPING.put("e", "5");
		MAPPING.put("f", "6");
		MAPPING.put("g", "7");
		MAPPING.put("h", "8");
		MAPPING.put("i", "9");
		MAPPING.put("j", "0");
		MAPPING.put("k", "1");
		MAPPING.put("l", "2");
		MAPPING.put("m", "3");
		MAPPING.put("n", "4");
		MAPPING.put("o", "5");
		MAPPING.put("p", "0");
		MAPPING.put("q", "1");
		MAPPING.put("r", "2");
		MAPPING.put("s", "3");
		MAPPING.put("t", "4");
		MAPPING.put("u", "5");
		MAPPING.put("v", "6");
		MAPPING.put("w", "7");
		MAPPING.put("x", "8");
		MAPPING.put("y", "9");
		MAPPING.put("z", "0");
		MAPPING.put("A", "1");
		MAPPING.put("B", "2");
		MAPPING.put("C", "3");
		MAPPING.put("D", "4");
		MAPPING.put("E", "5");
		MAPPING.put("F", "6");
		MAPPING.put("G", "7");
		MAPPING.put("H", "8");
		MAPPING.put("I", "9");
		MAPPING.put("J", "0");
		MAPPING.put("K", "1");
		MAPPING.put("L", "2");
		MAPPING.put("M", "3");
		MAPPING.put("N", "4");
		MAPPING.put("O", "5");
		MAPPING.put("P", "0");
		MAPPING.put("Q", "1");
		MAPPING.put("R", "2");
		MAPPING.put("S", "3");
		MAPPING.put("T", "4");
		MAPPING.put("U", "5");
		MAPPING.put("V", "6");
		MAPPING.put("W", "7");
		MAPPING.put("X", "8");
		MAPPING.put("Y", "9");
		MAPPING.put("Z", "0");
	}

	/**
	 * <p>
	 * 通番からサービス契約番号への変換を行います。
	 * </p>
	 * @param serialNo 通番
	 * @return サービス契約番号
	 */
	public static String convSvcKeiNo(String serialNo)
	{
		// 変換処理
		StringBuffer buffer = new StringBuffer();

		// (1)接頭語を設定する
		buffer.append(PREFIX_C);
		// (2)シーケンスの2桁目,3桁目を元に変換表Ａ変換処理を呼び出す
		buffer.append(toAlphabetA(serialNo.substring(1, 2), serialNo.substring(2, 3)));
		// (3)シーケンスの4桁目,5桁目を元に変換表Ａ変換処理を呼び出す
		buffer.append(toAlphabetA(serialNo.substring(3, 4), serialNo.substring(4, 5)));
		// (4)シーケンスの5桁目を設定する
		buffer.append(serialNo.substring(4, 5));
		// (5)シーケンスの6桁目を設定する
		buffer.append(serialNo.substring(5, 6));
		// (6)シーケンスの1桁目,2桁目を元に変換表Ａ変換処理を呼び出す
		buffer.append(toAlphabetA(serialNo.substring(0, 1), serialNo.substring(1, 2)));
		// (7)シーケンスの3桁目,4桁目を元に変換表Ａ変換処理を呼び出す
		buffer.append(toAlphabetA(serialNo.substring(2, 3), serialNo.substring(3, 4)));
		// (8)シーケンスの7桁目を設定する
		buffer.append(serialNo.substring(6, 7));
		// (9)シーケンスの8桁目を設定する
		buffer.append(serialNo.substring(7, 8));
		// (10)設定された値からチェックデジットを算出して設定する
		buffer.append(getCheckDigit21(buffer.toString()));

		String rltValue = buffer.toString();
		return rltValue;
	}

	/**
	 * <p>
	 * チェックデジット算出処理21。<br>
	 * </p>
	 * @param targetNo チェックデジット算出対象の番号
	 * @return 算出されたチェックデジット
	 */
	public static String getCheckDigit21(String targetNo)
	{
		int total = 0;

		// 下位の桁から1桁ずつ処理を行う
		for (int i = 0; i < targetNo.length(); i++)
		{
			// 算出対象の番号に含まれる、英字・記号を数値に置換
			String strSub = String.valueOf(targetNo.charAt(i));

			if (MAPPING.containsKey(strSub))
			{
				strSub = MAPPING.get(strSub);
			}

			int one = Integer.valueOf(strSub);

			// 「1 * 10^偶数」の位の数値に、2の重みを付与する
			if ((targetNo.length() - i) % 2 == 1)
			{
				one = one * 2;
			}

			// 重みを掛けた数値の1の位と10の位をそれぞれ合計に加算する
			total = total + (one / 10);
			total = total + (one % 10);

		}

		// 合計値の1の位を10から減算した値の1の位をチェックデジットとして返却する
		total = 10 - (total % 10);

		return String.valueOf(total % 10);
	}

	/**
	 * <p>
	 * 変換表Ａを使用して英字変換を行います。
	 * </p>
	 * @param str1 変換元データの１桁目
	 * @param str2 変換元データの２桁目
	 * @return 変換した英字。
	 */
	private static String toAlphabetA(String str1, String str2)
	{
		// 変換表Ａを使用して英字変換を行う
		return toAlphabetTarget(str1, str2, CHANGE_LIST_A);
	}

	/**
	 * <p>
	 * 指定した変換表により、英字変換を行います。<br>
	 * </p>
	 * @param str1 変換元データの１桁目
	 * @param str2 変換元データの２桁目
	 * @param changeList 変換表
	 * @return 変換した英字
	 */
	private static String toAlphabetTarget(String str1, String str2, HashMap<String, String> changeList)
	{
		// 変換元データの１桁目から、英字変換対象行を取得
		String chgStr = changeList.get(str1);

		// 変換元データの２桁目から、変換した英字を取得
		chgStr = chgStr.substring(Integer.valueOf(str2), Integer.valueOf(str2) + 1);

		return chgStr;
	}
}
