/*********************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JZEbatMaskSyori
*	ソースファイル名：JZEbatMaskSyori.java
*	作成者			：富士通
*	日付			：2012年02月02日
*＜機能概要＞
*	マスク処理関連部品
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2012/02/02   富士通		新規作成
*
**********************************************************************/
package eo.business.common;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import eo.common.constant.JZEStrConst;

import eo.framework.application.JBSbatBusinessException;
import eo.framework.item.JBSbatCommonItem;

/**
 * マスク処理関連部品<p>
 * <BR>
 * @author 富士通
 */
public class JZEbatMaskSyori
{
	
	// 定数

	/** 検索文字列の取得キー **/
	/** マスク種別取得キー **/
	private static final String MASKSYUBETU  = "MASKSYUBETU";
	/** 検索文字取列取得キー **/
	private static final String KENSAKUMOJI  = "KENSAKUMOJI";
	/** マスク方向取得キー **/
	private static final String MASKHOUKOU   = "MASKHOUKOU";
	/** 全角文字取得キー **/
	private static final String ZENKAKUMOJI  = "ZENKAKUMOJI";
	/** 半角文字取得キー **/
	private static final String HANKAKUMOJI  = "HANKAKUMOJI";
	/** 置換除外文字列取得キー **/
	private static final String CHIKANJOGAI  = "CHIKANJOGAI";
	/** 検索除外文字列取得キー **/
	private static final String KENSAKUJOGAI = "KENSAKUJOGAI";
	/** マスク除外文字列取得キー **/
	private static final String MASKJOGAI    = "MASKJOGAI";
	/** マスク文字数取得キー **/
	private static final String MASKMOJISU   = "MASKMOJISU";
	/** 優先度取得キー **/
	private static final String YUUSENDO     = "YUUSENDO";

	/** 数値以外の文字列指定 **/
	private static final String NUMERIC      = "<>NUMERIC";

	/** マスク文字数の一行指定 **/
	private static final String MASKMOJISU_ALL = "ALL";

	/** マスク方向前を示す定数 **/
	private static final String MASKHOUKOU_MAE      = "1";

	
	/**
	 * マスク条件精査処理
	 * 
	 * マスク条件を種別ごとにまとめてリストに格納する<br>
	 * @param commonItem バッチ共通パラメータ電文
	 * @param maskJokenList マスク条件リスト
	 * @return マスク条件ファイルの内容を格納したMap
	 * @throws Exception 例外
	 */
	public static Map<String, Object> maskJokenSeisa(JBSbatCommonItem commonItem,
														ArrayList<ArrayList<String>> maskJokenList) throws Exception
	{

		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		Map<String, Object> resultMap = new HashMap<String, Object>();

		Map<String, Object> maskJokenWorkMap = new HashMap<String, Object>();
		List<Object> kensakuMojiList = new ArrayList<Object>();
		List<Object> mailAddressList = new ArrayList<Object>();
		List<Object> taiokrkList = new ArrayList<Object>();
		List<Object> telList = new ArrayList<Object>();
		List<String> chikanJogaiList = new ArrayList<String>();
		List<String> kensakuJogaiList = new ArrayList<String>();
		List<String> maskJogaiList = new ArrayList<String>();
		
		String syubetu = null;
		String kensakuMoji = "";
		String maskHoukou = "";
		String zenkakuMoji = "";
		String hankakuMoji = "";
		String chikanJogai = "";
		String kensakuJogai = "";
		String maskJogai = "";
		String maskMojiCnt = "";
		String yuusen = "";

		for(int i = 0; i < maskJokenList.size(); i++)
		{
			List<String> maskJokenWorkList = maskJokenList.get(i);

			if(maskJokenWorkList.get(0).equals(syubetu) &&
				maskJokenWorkList.get(1).equals(kensakuMoji) &&
				maskJokenWorkList.get(2).equals(maskHoukou) &&
				maskJokenWorkList.get(3).equals(zenkakuMoji) &&
				maskJokenWorkList.get(4).equals(hankakuMoji))
			{
				if(maskJokenWorkList.get(5) != null && !"".equals(maskJokenWorkList.get(5)))
				{
					chikanJogaiList.add(maskJokenWorkList.get(5));
				}
				
				if(maskJokenWorkList.get(6) != null && !"".equals(maskJokenWorkList.get(6)))
				{
					kensakuJogaiList.add(maskJokenWorkList.get(6));
				}

				if(maskJokenWorkList.get(7) != null && !"".equals(maskJokenWorkList.get(7)))
				{
					maskJogaiList.add(maskJokenWorkList.get(7));
				}
			}
			// マスク種別、検索文字、マスク方向、全角置換文字、半角置換文字のいずれかが
			// 前の行と一致しない場合
			
			else
			{
				if(syubetu != null)
				{
					// Mapにマスク条件を格納する
					maskJokenWorkMap.put(MASKSYUBETU, syubetu);				// 種別
					maskJokenWorkMap.put(KENSAKUMOJI, kensakuMoji);			// 検索文字
					maskJokenWorkMap.put(MASKHOUKOU,  maskHoukou);			// マスク方向
					maskJokenWorkMap.put(ZENKAKUMOJI, zenkakuMoji);			// 全角置換文字
					maskJokenWorkMap.put(HANKAKUMOJI, hankakuMoji);			// 半角置換文字
					maskJokenWorkMap.put(CHIKANJOGAI, chikanJogaiList);		// 置換除外文字　
					maskJokenWorkMap.put(KENSAKUJOGAI, kensakuJogaiList);	// 検索除外文字
					maskJokenWorkMap.put(MASKJOGAI, maskJogaiList);			// マスク除外文字
					maskJokenWorkMap.put(MASKMOJISU, maskMojiCnt);			// マスク文字数
					maskJokenWorkMap.put(YUUSENDO, yuusen);					// 優先度
					
					
					// 各リストの初期化
					chikanJogaiList  = new ArrayList<String>();
					kensakuJogaiList = new ArrayList<String>();
					maskJogaiList   = new ArrayList<String>();

					resultList.add(maskJokenWorkMap);
					
					// 種別コードが001 検索文字条件リストに格納
					if(JZEStrConst.ZE_MASK_KBN_KENSAKUMOJI.equals(syubetu))
					{
						kensakuMojiList.add(maskJokenWorkMap);
					}
					// 種別コードが002 電話番号条件リストに格納
					else if(JZEStrConst.ZE_MASK_KBN_TEL.equals(syubetu))
					{
						telList.add(maskJokenWorkMap);
					}
					// 種別コードが003 メールアドレスリストに格納
					else if(JZEStrConst.ZE_MASK_KBN_MAILADDRESS.equals(syubetu))
					{
						mailAddressList.add(maskJokenWorkMap);
					}
					// 種別コードが004 対応記録履歴リストに格納
					else if(JZEStrConst.ZE_MASK_KBN_TAIOKRK_RIREKI.equals(syubetu))
					{
						taiokrkList.add(maskJokenWorkMap);
					}
					maskJokenWorkMap = new HashMap<String, Object>();
				}
				
				syubetu = maskJokenWorkList.get(0);
				kensakuMoji = maskJokenWorkList.get(1);
				maskHoukou = maskJokenWorkList.get(2);
				zenkakuMoji = maskJokenWorkList.get(3);
				hankakuMoji = maskJokenWorkList.get(4);
				chikanJogai = maskJokenWorkList.get(5);
				kensakuJogai = maskJokenWorkList.get(6);
				maskJogai = maskJokenWorkList.get(7);
				maskMojiCnt = maskJokenWorkList.get(8);
				yuusen = maskJokenWorkList.get(9);

				if(chikanJogai != null && !"".equals(chikanJogai))
				{
					chikanJogaiList.add(chikanJogai);
				}
				
				if(kensakuJogai != null && !"".equals(kensakuJogai))
				{
					kensakuJogaiList.add(kensakuJogai);
				}

				if(maskJogai != null && !"".equals(maskJogai))
				{
					maskJogaiList.add(maskJogai);
				}
			}
		}
		
		// Mapにマスク条件を格納する
		maskJokenWorkMap.put(MASKSYUBETU, syubetu);				// 種別
		maskJokenWorkMap.put(KENSAKUMOJI, kensakuMoji);			// 検索文字
		maskJokenWorkMap.put(MASKHOUKOU,  maskHoukou);			// マスク方向
		maskJokenWorkMap.put(ZENKAKUMOJI, zenkakuMoji);			// 全角置換文字
		maskJokenWorkMap.put(HANKAKUMOJI, hankakuMoji);			// 半角置換文字
		maskJokenWorkMap.put(CHIKANJOGAI, chikanJogaiList);		// 置換除外文字　
		maskJokenWorkMap.put(KENSAKUJOGAI, kensakuJogaiList);	// 検索除外文字
		maskJokenWorkMap.put(MASKJOGAI, maskJogaiList);			// マスク除外文字
		maskJokenWorkMap.put(MASKMOJISU, maskMojiCnt);			// マスク文字数
		maskJokenWorkMap.put(YUUSENDO, yuusen);					// 優先度
		
		resultList.add(maskJokenWorkMap);
		
		// 種別コードが001 検索文字条件リストに格納
		if(JZEStrConst.ZE_MASK_KBN_KENSAKUMOJI.equals(syubetu))
		{
			kensakuMojiList.add(maskJokenWorkMap);
		}
		// 種別コードが002 電話番号条件リストに格納
		else if(JZEStrConst.ZE_MASK_KBN_TEL.equals(syubetu))
		{
			telList.add(maskJokenWorkMap);
		}
		// 種別コードが003 メールアドレスリストに格納
		else if(JZEStrConst.ZE_MASK_KBN_MAILADDRESS.equals(syubetu))
		{
			mailAddressList.add(maskJokenWorkMap);
		}
		// 種別コードが004 対応記録履歴リストに格納
		else if(JZEStrConst.ZE_MASK_KBN_TAIOKRK_RIREKI.equals(syubetu))
		{
			taiokrkList.add(maskJokenWorkMap);
		}
		
		// Mapに種別ごとの各リストを格納する
		resultMap.put(JZEStrConst.ZE_MASK_KBN_KENSAKUMOJI, kensakuMojiList);
		resultMap.put(JZEStrConst.ZE_MASK_KBN_TEL, telList);
		resultMap.put(JZEStrConst.ZE_MASK_KBN_MAILADDRESS, mailAddressList);
		resultMap.put(JZEStrConst.ZE_MASK_KBN_TAIOKRK_RIREKI, taiokrkList);
		
		return resultMap;
	}

	
	/**
	 * 検索文字マスク処理
	 * 
	 * 検索対象外文字列、マスク除外文字列、置換除外文字列が存在する場合、
	 * 各除外文字列ごとにマスク処理を行う。
	 * 
	 * @param commonItem バッチ共通パラメータ電文
	 * @param maskData マスク対象データ
 	 * @param maskJokenList マスク条件リスト
	 * @return String マスク後の文字列データ
	 * @throws Exception 例外
	**/
	public static String maskKensakuMoji(JBSbatCommonItem commonItem,
			String maskData, List<Map<String, Object>> maskJokenList) throws Exception
	{
		List<String> chikanJogaiList = new ArrayList<String>();
		List<String> kensakuJogaiList = new ArrayList<String>();
		List<String> maskJogaiList = new ArrayList<String>();
		Map<String, Object> maskJokenMap = new HashMap<String, Object>();

		StringBuilder sb = new StringBuilder();
		String lineData = null;
		String sarchMoji = null;
		String maskHoukou = null;
		String zenReplaceMoji = null;
		String hanReplaceMoji = null;
		String maskMojiSu = null;
		
		if(maskData == null)
		{
			return "";
		}
		
		// 検索文字からマスク対象文字を抽出する。
		List<String> masklineDataList = maskDataToList(maskData);

		for(int i = 0; i < masklineDataList.size(); i++)
		{
			// マスク対象行数の数ループ
			lineData = masklineDataList.get(i);
			
			for(int j = 0; j < maskJokenList.size(); j++)
			{
				// 一行分の条件データ
				maskJokenMap = maskJokenList.get(j);
				sarchMoji = (String)maskJokenMap.get(KENSAKUMOJI);
				maskHoukou = (String)maskJokenMap.get(MASKHOUKOU);
				zenReplaceMoji = (String)maskJokenMap.get(ZENKAKUMOJI);
				hanReplaceMoji = (String)maskJokenMap.get(HANKAKUMOJI);
				maskMojiSu = (String)maskJokenMap.get(MASKMOJISU);
				chikanJogaiList = (List<String>)maskJokenMap.get(CHIKANJOGAI);
				kensakuJogaiList = (List<String>)maskJokenMap.get(KENSAKUJOGAI);
				maskJogaiList = (List<String>)maskJokenMap.get(MASKJOGAI);

				// 検索除外文字が存在する
				if(kensakuJogaiList != null && kensakuJogaiList.size() > 0)
				{
					// 検索除外文字マスク処理実施
					lineData = kensakuJogaiSyori(commonItem, lineData, sarchMoji,
							maskHoukou, zenReplaceMoji, hanReplaceMoji, maskMojiSu, kensakuJogaiList, maskJogaiList, chikanJogaiList);
				}
				else
				{
					
					lineData = sarchMojiReplace(commonItem, sarchMoji, lineData,
								maskHoukou, zenReplaceMoji, hanReplaceMoji, maskMojiSu, chikanJogaiList,
								kensakuJogaiList, maskJogaiList);
				}
			}

			sb.append(lineData);

			// 最終行以外改行を付加する
			if(i + 1  < masklineDataList.size())
			{
				sb.append(JZEStrConst.KAIGYO_CD);
			}
		}
		
		return sb.toString();
	}
	
	
	/**
	 * 検索除外処理
	 * 
	 * マスク対象文字列から検索対象外文字列の検索を行い、存在する場合
	 * マスク検索対象として扱わない、その後、マスク除外文字列かどうかの
	 * 判定を行い、マスク除外文字列でない場合、マスク置換処理を行う。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param lineData       一行分のマスク検索対象データ
	 * @param sarchMoji      検索文字列
	 * @param maskHoukou     マスク方向
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param maskMojiSu マスク文字数
	 * @param kensakuJogaiList  検索除外条件List
	 * @param maskJogaiList  マスク除外条件List
	 * @param chikanJogaiList  置換除外条件List
	 * @return String        マスク置換済み文字列
	 * @throws Exception     例外
	**/
	public static String kensakuJogaiSyori(JBSbatCommonItem commonItem,
											String lineData,
											String sarchMoji, 
											String maskHoukou, 
											String zenReplaceMoji, 
											String hanReplaceMoji, 
											String maskMojiSu, 
											List<String> kensakuJogaiList,
											List<String> maskJogaiList,
											List<String> chikanJogaiList) throws Exception
	{
		// 検索文字列を抽出する。
		int startIndex = 0;
		int endIndex = 0;
		int maskMojiCnt = 0;
		int sarchIndex = 0;
		int index = 0;
		
		String maskTarget = null;
		String targetStr = lineData;
		StringBuilder sb = new StringBuilder();

		endIndex = targetStr.indexOf(sarchMoji, sarchIndex);

		try
		{
			if(endIndex == -1)
			{
				// 検索文字列が存在しない場合、文字列をそのまま返す
				return lineData;
			}
	
			
			while(endIndex != -1)
			{
			// マスク検索対象データから検索文字列が存在するかチェックを行う。
			// 後ろから検索文字列を探す
				// マスク文字数チェック
				if(maskMojiSu.equals(MASKMOJISU_ALL))
				{
					maskTarget = targetStr;
				}
				// マスク文字数が数値の場合
				else if(JCCBatCommon.isHannkakuSuuji1(maskMojiSu))
				{
					maskMojiCnt = Integer.parseInt(maskMojiSu);
	
					// 見つかった場合、マスク文字数が指定する文字列を抜き出す
					// マスク方向前方
					if(maskHoukou.equals(MASKHOUKOU_MAE))
					{
						if(endIndex - maskMojiCnt < 0)
						{
							index = startIndex;
						}
						else
						{
							index = endIndex - maskMojiCnt;
						}
						
						maskTarget = lineData.substring(index, endIndex + 1);
					}
	
					// マスク方向後方
					else
					{
						if(endIndex + maskMojiCnt > lineData.length())
						{
							index = lineData.length();
						}
						else
						{
							index = endIndex + maskMojiCnt;
						}
						maskTarget = lineData.substring(endIndex, index);
					}
					
				}
				
				// 検索除外文字が含まれているか判定
				if(kensakuTaisyougaiMojiHantei(commonItem, maskTarget, kensakuJogaiList))
				{
					// マスク処理を行う。
					sb.append(lineData.substring(sarchIndex, endIndex));
					sb.append(sarchMoji);
					sarchIndex = endIndex + sarchMoji.length();
					startIndex = endIndex + sarchMoji.length();
				}
				// マスク除外文字列検索
				else if(maskTaisyougaiMojiHantei(commonItem, maskTarget, maskJogaiList))
				{
					// commonItem.getLogPrint().printDebugLog("マスク除外文字を含む");
					// マスク対象外
					sb.append(lineData.substring(sarchIndex, endIndex));
					// マスク対象文字列全体を置換対象外とする。
					sb.append(sarchMoji);
					sarchIndex = endIndex + sarchMoji.length();
					startIndex = endIndex + sarchMoji.length();
				}
				else
				{
					maskTarget = lineData.substring(index, endIndex);
					// マスク処理を行う。
					// commonItem.getLogPrint().printDebugLog("マスク対象文字:" + maskTarget);

					// 対象文字を渡しマスクを行う。
					String work = maskReplace(commonItem, maskTarget,  zenReplaceMoji, hanReplaceMoji, chikanJogaiList);
					if (startIndex < index) {
						sb.append(lineData.substring(startIndex, index));
					}
					sb.append(work);
					sb.append(sarchMoji);
					sarchIndex = endIndex + sarchMoji.length();
					startIndex = endIndex + sarchMoji.length();
				}
				
				endIndex = targetStr.indexOf(sarchMoji, sarchIndex);
	
			}
			sb.append(lineData.substring(sarchIndex, lineData.length()));

		}
		catch(JBSbatBusinessException ex)
		{
			throw ex;
		}
		// 
		return sb.toString();
	}

	/**
	 * 検索対外文字列判定処理
	 * 
	 * 検索対象文字列からマスク対象外文字列の検索を行い、存在する場合
	 * 検索検索対象として扱わない、その後、検索除外文字列かどうかの
	 * 判定を行い、検索除外文字列でない場合、マスク置換処理を行う。
	 * 
	 * @param commonItem バッチ共通パラメータ電文
	 * @param targetStr 検索対象文字列
 	 * @param maskJogaiList マスク除外リスト
	 * @return boolean 検索除外文字列が存在する場合 true/存在しない場合 false
	**/
	
	public static boolean kensakuTaisyougaiMojiHantei(JBSbatCommonItem commonItem,
												String targetStr,
												List<String> maskJogaiList)
	{
		String kensakuWork = null;
		
		if(maskJogaiList == null || maskJogaiList.size() == 0)
		{
			return false;
		}
		
		for(int i = 0; i < maskJogaiList.size(); i++)
		{	
			int index = 0;
			kensakuWork = maskJogaiList.get(i);
		
			index = targetStr.indexOf(kensakuWork);

			// 検索除外文字列を含むかどうかを判定
			if(index  != -1)
			{
				// commonItem.getLogPrint().printDebugLog("検索除外文字 " + kensakuWork +" を含む");
				return true;
			}
		}
		
		// 検索除外文字列を含まない場合falseを返す。
		return false;
	}

	
	
	/**
	 * マスク対象外文字列判定処理
	 * 
	 * マスク対象文字列からマスク対象外文字列の検索を行い、存在する場合
	 * マスク検索対象として扱わない、その後、マスク除外文字列かどうかの
	 * 判定を行い、マスク除外文字列でない場合、マスク置換処理を行う。
	 * 
	 * @param  commonItem 共通
	 * @param targetStr 検索対象文字列
 	 * @param maskJogaiList マスク除外リスト
	 * @return boolean 検索除外文字列が存在する場合 true/存在しない場合 false
	**/
	
	public static boolean maskTaisyougaiMojiHantei(JBSbatCommonItem commonItem,
												String targetStr,
												List<String> maskJogaiList)
	{
		String kensakuWork = null;
		
		if(maskJogaiList == null || maskJogaiList.size() == 0)
		{
			return false;
		}
		
		for(int i = 0; i < maskJogaiList.size(); i++)
		{	
			int index = 0;
			kensakuWork = maskJogaiList.get(i);
		
			index = targetStr.indexOf(kensakuWork);

			// マスク除外文字列を含むかどうかを判定
			if(index  != -1)
			{
				// commonItem.getLogPrint().printDebugLog("マスク除外文字 " + kensakuWork +" を含む");
				return true;
			}
		}
		
		// マスク除外文字列を含まない場合falseを返す。
		return false;
	}


	/**
	 * 検索文字列置換処理
	 * 
	 * 引数で指定された対応記録テーブルの一行データのマスク処理を行う。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param serchMoji      検索文字列
	 * @param lineData       一行分のマスク検索対象データ
	 * @param maskHoukou     マスク方向
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param maskMojiSu     マスク文字数
	 * @param chikanJogaiList  置換除外条件List
	 * @param kensakuJogaiList  検索除外条件List
	 * @param maskJogaiList  マスク除外条件List
	 * @return String        マスク置換済み文字列
	 * @throws Exception     例外
	 **/
	public static String sarchMojiReplace(JBSbatCommonItem commonItem,
										String serchMoji,
										String lineData,
										String maskHoukou,
										String zenReplaceMoji,
										String hanReplaceMoji,
										String maskMojiSu,
										List<String> chikanJogaiList,
										List<String> kensakuJogaiList,
										List<String> maskJogaiList) throws Exception
	{
		// 検索文字列を抽出する。
		int startIndex = 0;
		int endIndex = 0;
		String targetStr = lineData;

		while(endIndex != -1)
		{
			// マスク検索対象データから検索文字列が存在するかチェックを行う。
			// 後ろから検索文字列を探す
			endIndex = targetStr.indexOf(serchMoji, startIndex);

			if(endIndex == -1)
			{
				// 検索文字列が存在しない場合、文字列をそのまま返す
				return lineData;
			}
			else
			{
				break;
			}
		}

		// 検索文字列が見つかった場合
		String workData = lineData.substring(0, endIndex);
		
		startIndex = endIndex + serchMoji.length();
		// マスク対象範囲確定
		if(maskMojiSu.equals(MASKMOJISU_ALL))
		{
			targetStr = lineData.substring(startIndex, lineData.length());
			
		}
		else if(JCCBatCommon.isHannkakuSuuji1(maskMojiSu))
		{
			int maskMojiCnt = Integer.parseInt(maskMojiSu);
			int index = 0;
			// マスク方向前方
			if(maskHoukou.equals(MASKHOUKOU_MAE))
			{
				if(endIndex - maskMojiCnt < 0)
				{
					index = 0;
				}
				else
				{
					index = endIndex - maskMojiCnt;
				}
				
				targetStr = lineData.substring(index , endIndex + 1);
				startIndex = index;
			}

			// マスク方向後方
			else
			{
				if(endIndex + maskMojiCnt > lineData.length())
				{
					index = targetStr.length();
				}
				else
				{
					index = endIndex + maskMojiCnt;
				}
				targetStr = lineData.substring(endIndex, index);
				startIndex = index;
			}
		}
		
		// マスク除外文字列検索
		if(maskTaisyougaiMojiHantei(commonItem, targetStr, maskJogaiList))
		{
			// commonItem.getLogPrint().printDebugLog("マスク除外文字を含む");
			// マスク対象外
			return lineData;
		}

		

		// 対象文字を渡しマスクを行う。
		String result = maskReplace(commonItem, targetStr,  zenReplaceMoji, hanReplaceMoji, chikanJogaiList);

		if(maskMojiSu.equals(MASKMOJISU_ALL))
		{
			result = lineData.substring(0, startIndex) + result;
		}
		
		// マスク対象外文字列(前)とマスク後文字列とマスク対象外文字列(後)を連結する。
		else if(maskHoukou.equals(MASKHOUKOU_MAE))
		{
			result = result + lineData.substring(endIndex + 1 , lineData.length());
		}
		else
		{
			result = workData + result + lineData.substring(endIndex + targetStr.length(), lineData.length());

		}

		return result;
	}

	/**
	 * 電話番号マスク処理
	 * 
	 * @param commonItem バッチ共通パラメータ電文
	 * @param maskData マスク対象データ
 	 * @param maskJokenList マスク条件リスト
	 * @return String マスク後の文字列データ
	 * @throws Exception 例外
	**/
	public static String maskTelNamber(JBSbatCommonItem commonItem,
										String maskData,
										List<Map<String,
										Object>> maskJokenList) throws Exception
	{
		List<String> chikanJogaiList = new ArrayList<String>();
		Map<String, Object> maskJokenMap = new HashMap<String, Object>();

		// commonItem.getLogPrint().printDebugLog("電話番号検索");
		StringBuilder resultBuilder = new StringBuilder();
		String lineData = null;
		String sarchMoji = null;
		String maskHoukou = null;
		String zenReplaceMoji = null;
		String hanReplaceMoji = null;

		// マスク対象行がnullの場合
		if(maskData == null)
		{
			return "";
		}
		
		List<String> masklineDataList = maskDataToList(maskData);

		for(int i = 0; i < masklineDataList.size(); i++)
		{
			// マスク対象行数の数ループ
			lineData = masklineDataList.get(i);
			
			for(int j = 0; j < maskJokenList.size(); j++)
			{
				// 一行分の条件データ
				maskJokenMap = maskJokenList.get(j);
				sarchMoji = (String)maskJokenMap.get(KENSAKUMOJI);
				maskHoukou = (String)maskJokenMap.get(MASKHOUKOU);
				zenReplaceMoji = (String)maskJokenMap.get(ZENKAKUMOJI);
				hanReplaceMoji = (String)maskJokenMap.get(HANKAKUMOJI);
				chikanJogaiList = (List<String>)maskJokenMap.get(CHIKANJOGAI);
				
				lineData = telNumberReplace(commonItem, sarchMoji, lineData,
							maskHoukou, zenReplaceMoji, hanReplaceMoji, chikanJogaiList);
			}
			
			resultBuilder.append(lineData);

			// 最終行以外改行を付加する
			if(i + 1  < masklineDataList.size())
			{
				resultBuilder.append(JZEStrConst.KAIGYO_CD);
			}
		}
		return resultBuilder.toString();
	}
	
	/**
	 * メールアドレスマスク処理
	 * 
	 * マスク対象データからメールアドレスの判定を行い、メールアドレスと判定した場合マスク処理を行う。
	 * 
	 * @param commonItem バッチ共通パラメータ電文
	 * @param maskData マスク対象データ
 	 * @param maskJokenList マスク条件リスト
	 * @return String マスク後の文字列データ
	 * @throws Exception 例外
	**/
	public static String maskMailAddress(JBSbatCommonItem commonItem,
											String maskData,
											List<Map<String,
											Object>> maskJokenList) throws Exception
	{
		List<String> chikanJogaiList = new ArrayList<String>();
		Map<String, Object> maskJokenMap = new HashMap<String, Object>();

		String lineData = null;
		String sarchMoji = null;
		String maskHoukou = null;
		String zenReplaceMoji = null;
		String hanReplaceMoji = null;

		if(maskData == null)
		{
			return "";
		}
		
		List<String> masklineDataList = maskDataToList(maskData);
		StringBuilder resultBuilder = new StringBuilder();

		try
		{
			for(int i = 0; i < masklineDataList.size(); i++)
			{
				// マスク対象行数の数ループ
				lineData = masklineDataList.get(i);
				
				for(int j = 0; j < maskJokenList.size(); j++)
				{
					// 一行分の条件データ
					maskJokenMap = maskJokenList.get(j);
					sarchMoji = (String)maskJokenMap.get(KENSAKUMOJI);
					maskHoukou = (String)maskJokenMap.get(MASKHOUKOU);
					zenReplaceMoji = (String)maskJokenMap.get(ZENKAKUMOJI);
					hanReplaceMoji = (String)maskJokenMap.get(HANKAKUMOJI);
					chikanJogaiList = (List<String>)maskJokenMap.get(CHIKANJOGAI);
					
					lineData = JZEBatCommon.sarchReplace(commonItem, sarchMoji, lineData,
								maskHoukou, zenReplaceMoji, hanReplaceMoji, chikanJogaiList);
				}
				resultBuilder.append(lineData);
	
				// 最終行以外改行を付加する
				if(i + 1  < masklineDataList.size())
				{
					resultBuilder.append(JZEStrConst.KAIGYO_CD);
				}
			}
		}
		catch (JBSbatBusinessException ex)
		{
			throw ex;
		}
		
		return resultBuilder.toString();
	}


	/**
	 * マスク対象文字列リスト格納処理
	 * 
	 * マスク対象文字列を行ごとにListに格納する。
	 * 
	 * @param maskData 一行分のCSVデータ
	 * @return List 項目ごとにCSVデータを格納したList
	 * @throws Exception 例外
	 * 
	**/
	private static List<String> maskDataToList(String maskData) throws Exception
	{
		List<String> maskDataList = new ArrayList<String>();
		
		// 改行コードを揃える \r\n → \nへ
		String henkanZumiMaskData = maskData.replaceAll(JZEStrConst.KAIGYO_CD, JZEStrConst.LF_CD);
		
		// 改行コードごとにリストに格納
		String[] maskDataWrok = henkanZumiMaskData.split(JZEStrConst.LF_CD);
	
		for(int i = 0; i < maskDataWrok.length; i++)
		{
			maskDataList.add(maskDataWrok[i]);
		}
		return maskDataList;
	}
	
	
	/**
	 * 電話番号マスク置換処理
	 * 
	 * 検索対象データから検索文字列を検索し、マスク対象データを探す。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param serchMoji      検索文字列
	 * @param lineData       一行分のマスク検索対象データ
	 * @param maskHoukou     マスク方向
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param chikanJogaiList  マスク除外条件List
	 * @return String        マスク置換済み文字列
	 * @throws Exception     例外
	 **/
	public static String telNumberReplace(JBSbatCommonItem commonItem,
										String serchMoji,
										String lineData,
										String maskHoukou,
										String zenReplaceMoji,
										String hanReplaceMoji,
										List<String> chikanJogaiList) throws Exception
	{
		int sarchIndex = 0;
		int startIndex = 0;
		int endIndex = 0;
		String targetStr = lineData;
		String maskWork = null;
		StringBuilder sb = new StringBuilder();
		
		// マスク検索対象データから検索文字列が存在するかチェックを行う。
		// 検索文字列を探す
		sarchIndex = targetStr.indexOf(serchMoji);

		// 検索文字列が存在しない場合、検索対象文字列をそのまま返す。
		if(sarchIndex == -1)
		{
			return lineData;
		}
		
		int numberCount = 0;
		while(sarchIndex != -1)
		{
			// 検索文字列から数値が10桁以上続くかどうかを判定
			numberCount = telNumberHantei(lineData, sarchIndex, chikanJogaiList);

			// 電話番号が見つかる前までの文字列を保持する
			if(numberCount >= 10)
			{
				// 電話番号の場合
				// マスク処理を行う

				sb.append(lineData.substring(endIndex, sarchIndex));
				endIndex = sarchIndex + numberCount;
				maskWork = maskReplace(commonItem, lineData.substring(sarchIndex, endIndex), zenReplaceMoji, hanReplaceMoji, chikanJogaiList);
				sb.append(maskWork);
			}
			else
			{
				endIndex = sarchIndex + numberCount;
				sb.append(lineData.substring(startIndex, endIndex));
			}
			startIndex = endIndex;
			sarchIndex = targetStr.indexOf(serchMoji, endIndex);
		}
		
		// 検索文字列が見つかった最後の文字を連結する。
		sb.append(lineData.substring(endIndex));
		return sb.toString();
	}
	

	/**
	 * 電話番号判定処理
	 * 
	 * 検索対象データから検索文字列を検索し、マスク対象データを探す。
	 * 
	 * @param lineData       	一行分のマスク検索対象データ
	 * @param sarchIndex       	検索対象インデックス
	 * @param chikanJogaiList  マスク除外条件List
	 * @return 数値が続いた数
	 **/
	public static int telNumberHantei(String lineData,
									int sarchIndex,
									List<String> chikanJogaiList)
	{
		int result = 0;
		
		String sarchNumber = lineData.substring(sarchIndex);
		String mojiStr = null;
	
		char moji;
		for(int i = 0; i < sarchNumber.length(); i++)
		{
			moji = sarchNumber.charAt(i);

			if (moji >= '０' && moji <= '９')
			{
				mojiStr = String.valueOf((char)(moji - '０' + '0'));
			}
			else
			{
				mojiStr = String.valueOf(moji);
			}
			// 数値もしくは、置換除外文字でない場合
			if(!JCCBatCommon.isHannkakuSuuji1(mojiStr) && !isJogaiMoji(mojiStr, chikanJogaiList))
			{
				break;
			}
			result++;
		}
		// 数値が続いた数を返す。
		return result;
	}

	/**
	 * 置換除外文字列判定処理
	 * 
	 * 検索対象データから検索文字列を検索し、マスク対象データを探す。
	 * 
	 * @param targetData     
	 * @param maskJogaiList  マスク除外条件List
	 * @return String        マスク置換済み文字列
	 **/
	public static boolean isJogaiMoji(String targetData,
										List<String> maskJogaiList)
	{
		String jogaiMoji = null;
		for(int i = 0; i < maskJogaiList.size(); i++)
		{
			jogaiMoji = maskJogaiList.get(i);
			if(targetData.equals(jogaiMoji))
			{
				
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * メール検索置換処理
	 * 
	 * 検索対象データから検索文字列を検索し、マスク対象データを探す。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param serchMoji      検索文字列
	 * @param lineData       一行分のマスク検索対象データ
	 * @param maskHoukou     マスク方向
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param maskJogaiList  マスク除外条件List
	 * @return String        マスク置換済み文字列
	 * @throws Exception     例外
	 **/
	public static String sarchMailReplace(JBSbatCommonItem commonItem,
										String serchMoji,
										String lineData,
										String maskHoukou,
										String zenReplaceMoji,
										String hanReplaceMoji,
										List<String> maskJogaiList) throws Exception
	{
		int endIndex = 0;
		String targetStr = lineData;

		while(endIndex != -1)
		{
			// マスク検索対象データから検索文字列が存在するかチェックを行う。
			// 後ろから検索文字列を探す
			endIndex = targetStr.lastIndexOf(serchMoji);

			if(endIndex == -1)
			{
				// 検索文字列が存在しない場合、文字列をそのまま返す
				return lineData;
			}

			if(endIndex == 0)
			{
				// 検索文字列が先頭場合、文字列をそのまま返す(マスク処理必要なし)
				return lineData;
			}

			// 検索文字列が2つ続く場合のチェック
			if(targetStr.subSequence(endIndex - serchMoji.length(), endIndex  + serchMoji.length()).equals(serchMoji + serchMoji))
			{
				// 検索文字列が2つ続く場合は、メールアドレスとしない。
				return lineData;
			}
			else
			{
				// マスク対象文字が確定した場合
				break;
			}
		}

		// 検索文字が見つからない場合
		if(endIndex == -1)
		{
			// 検索
			return lineData;
		}

		// 検索文字列が見つかった場合
		int startIndex = lineData.substring(0, endIndex).lastIndexOf(serchMoji);
		
		// 見つからなかった場合
		if(startIndex == -1)
		{
			startIndex = 0;
			targetStr = lineData.substring(startIndex, endIndex);
		}

		// 2つ目の検索文字列が見つかった場合
		else
		{
			startIndex = startIndex + serchMoji.length();
			targetStr = lineData.substring(startIndex, endIndex);
		}
		
		// 対象文字を渡しマスクを行う。
		String result = maskReplace(commonItem, targetStr,  zenReplaceMoji, hanReplaceMoji, maskJogaiList);
		// マスク対象外文字列(前)とマスク後文字列とマスク対象外文字列(後)を連結する。
		result = lineData.substring(0, startIndex) +  result + lineData.substring(endIndex, lineData.length());

		return result;
	}
	
	/**
	 * フォームメールマスク処理
	 * 
	 * 検索文字列からフォームメールに該当する文字列を判定し、フォームメールマスク処理を行う。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param serchMoji      検索文字列
	 * @param maskData       マスク検索対象データ
	 * @param maskHoukou     マスク方向
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param maskJogaiList  マスク除外条件List
	 * @return String        マスク置換済み文字列
	 * @throws Exception     例外
	 **/
	public static String sarchFormMailReplace(JBSbatCommonItem commonItem,
										String serchMoji,
										String maskData,
										String maskHoukou,
										String zenReplaceMoji,
										String hanReplaceMoji,
										List<String> maskJogaiList) throws Exception
	{
		if(maskData == null)
		{
			return "";
		}
		
		List<String> masklineDataList = maskDataToList(maskData);
		StringBuilder resultBuilder = new StringBuilder();
		String maskWorkData = null;
		int maskIndex = 0;
		
		for(int i = 0; i < masklineDataList.size(); i++)
		{
			maskWorkData = masklineDataList.get(i);
			resultBuilder.append(maskWorkData + JZEStrConst.KAIGYO_CD);

			maskIndex = maskWorkData.indexOf(serchMoji);
			if(maskIndex != -1)
			{
				if(i + 4 > masklineDataList.size())
				{
					// その後の4行が存在しないためフォームメールでない
					break;
				}
				
				// フォームメール対象行の次の行の文字(加入者フラグ)が"0"、または"1"の場合、
				// フォームメール対象とする。
				if((masklineDataList.get(i + 1).equals("0") ||
								masklineDataList.get(i + 1).equals("1")))
				{
					resultBuilder.append(masklineDataList.get(i + 1) + JZEStrConst.KAIGYO_CD);
					resultBuilder.append(masklineDataList.get(i + 2) + JZEStrConst.KAIGYO_CD);

					// 4行目のデータを氏名としてマスク処理を行う。
					maskWorkData = maskReplace(commonItem, masklineDataList.get(i + 3), zenReplaceMoji, hanReplaceMoji, maskJogaiList);
					resultBuilder.append(maskWorkData + JZEStrConst.KAIGYO_CD);
					
					// 5行目のデータを氏名としてマスク処理を行う。
					maskWorkData = maskReplace(commonItem, masklineDataList.get(i + 4), zenReplaceMoji, hanReplaceMoji, maskJogaiList);
					resultBuilder.append(maskWorkData + JZEStrConst.KAIGYO_CD);
					i = i + 4;
				}
			}
		}
		return resultBuilder.toString();
	}
	
	/**
	 * マスク文字置換処理
	 * 
	 * マスク対象文字列に対して、全角/半角置換文字で置き換えを行う。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param lineData       一行分のマスク検索対象データ
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param chikanJogaiList 置換除外条件List
	 * @return String        マスク済み文字列
	 * @throws Exception     例外
	 **/
	public static String maskReplace(JBSbatCommonItem commonItem,
										String lineData,
										String zenReplaceMoji,
										String hanReplaceMoji,
										List<String> chikanJogaiList) throws Exception
	{
		StringBuilder maskZumiMoji = null;
		String jogaiMoji = null;

		// 行全体をマスクする
		maskZumiMoji = allReplace(lineData, zenReplaceMoji, hanReplaceMoji);
		for(int i = 0; i < chikanJogaiList.size(); i++)
		{
			jogaiMoji = chikanJogaiList.get(i);
			int replaceIndex = 0;

			// 置換除外条件に<>NUMERIC
			if(jogaiMoji.equals(NUMERIC))
			{
				// 数値以外全て変換を行う。
				// commonItem.getLogPrint().printDebugLog("置換除外条件に'<>NUMERIC'が指定されました。");
				return numReplace(lineData, zenReplaceMoji, hanReplaceMoji);
			}

			// マスク対象外文字列を検索する
			while(replaceIndex != -1)
			{
				// 置換除外文字
				replaceIndex = lineData.indexOf(jogaiMoji, replaceIndex);
				if(replaceIndex != -1)
				{
					// 置換除外文字が存在する場合、元の文字列から置換対象外文字を置換する。
					maskZumiMoji.replace(replaceIndex, replaceIndex + jogaiMoji.length(), jogaiMoji);
					// 検索文字インデックスをずらす
					replaceIndex++;
				}
			}
		}
		return maskZumiMoji.toString();
	}

	/**
	 * マスク除外文字判定込み置換処理
	 * 
	 * マスク対象文字列に対して、全角/半角置換文字で置き換えを行う。
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param lineData       一行分のマスク検索対象データ
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 半角置換文字
	 * @param maskJogaiList  マスク除外条件List
	 * @param chikanJogaiList  置換除外条件List
	 * @return String        マスク済み文字列
	 * @throws Exception     例外
	 **/
	public static String maskReplace(JBSbatCommonItem commonItem,
										String lineData,
										String zenReplaceMoji,
										String hanReplaceMoji,
										List<String> maskJogaiList,
										List<String> chikanJogaiList) throws Exception
	{
		StringBuilder maskZumiMoji = null;
		String jogaiMoji = null;

		// 行全体をマスクする
		maskZumiMoji = allReplace(lineData, zenReplaceMoji, hanReplaceMoji);
		
		for(int i = 0; i < chikanJogaiList.size(); i++)
		{
			jogaiMoji = chikanJogaiList.get(i);
			int replaceIndex = 0;
			
			// 置換除外条件に<>NUMERIC
			if(jogaiMoji.equals(NUMERIC))
			{
				// 数値以外全て変換を行う。
				return numReplace(lineData, zenReplaceMoji, hanReplaceMoji);
			}

			// マスク対象外文字列を検索する
			while(replaceIndex != -1)
			{
				// 置換除外文字
				replaceIndex = lineData.indexOf(jogaiMoji, replaceIndex);
				if(replaceIndex != -1)
				{
					// 置換除外文字が存在する場合、元の文字列から置換対象外文字を置換する。
					maskZumiMoji.replace(replaceIndex, replaceIndex + jogaiMoji.length(), jogaiMoji);
					// 検索文字インデックスをずらす
					replaceIndex++;
				}
			}
		}
		return maskZumiMoji.toString();
	}

	/**
	 * 
	 * 数値変換文字
	 * 
	 * @param commonItem     バッチ共通パラメータ電文
	 * @param targetMoji     置換対象対象文字
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 全角置換文字
	 * @return StringBuilder 全ての数値に対してマスク処理を行い、その結果を返す
	 * @return 全角文字と半角文字で全ての文字をマスクした文字列
	 * @throws Exception 例外
	 * 
	 **/
	public static String numReplace(String targetMoji,
									String zenReplaceMoji,
									String hanReplaceMoji) throws Exception
	{
		StringBuilder result  = new StringBuilder();
		String mojiStr = null;

		char moji;
		for(int i = 0; i < targetMoji.length(); i++)
		{
			// 一文字ずつ全角と半角の判定を行う
			moji = targetMoji.charAt(i);
			mojiStr = String.valueOf(moji);
	
			if(JCCBatCommon.isHannkakuSuuji1(mojiStr))
			{
				
				if(JCCBatCommon.isZenkaku(mojiStr))
				{

					// 全角置換文字で置換する
					result.append(zenReplaceMoji);
				}
				else
				{
					// 半角置換文字で置換する
					result.append(hanReplaceMoji);
				}
			}
			else
			{
				result.append(mojiStr);
			}
		}

		return result.toString();
	}

	
	/**
	 * 全角/半角文字置換処理
	 * 
	 * マスク対象文字列に対して、全ての文字を全角/半角置換文字で置き換える。
	 * @param targetMoji     置換対象対象文字
	 * @param zenReplaceMoji 全角置換文字
	 * @param hanReplaceMoji 全角置換文字
	 * @return StringBuilder 全角文字と半角文字で全ての文字をマスクした文字列
	 * @throws Exception 例外
	 **/
	public static StringBuilder allReplace(String targetMoji,
											String zenReplaceMoji,
											String hanReplaceMoji) throws Exception
	{
		StringBuilder result = new StringBuilder();
		String mojiStr = null;

		char moji;
		for(int i = 0; i < targetMoji.length(); i++)
		{
			// 一文字ずつ全角と半角の判定を行う
			moji = targetMoji.charAt(i);
			mojiStr = String.valueOf(moji);
			
			if(JCCBatCommon.isZenkaku(mojiStr))
			{
				// 全角置換文字で置換する
				result.append(zenReplaceMoji);
			}
			else
			{
				// 半角置換文字で置換する
				result.append(hanReplaceMoji);
			}
		}
		// 
		return result;
	}
	
	/**
	 * null空文字変換処理
	 * 
	 * 対象文字列がnullの場合、空白文字で置き換える。
	 * @param targetStr 対象文字列
	 * @return String  変換後文字列
	 **/
	public static String nullToBlank(String targetStr)
	{
		
		// 対象文字列がnullの場合
		if(targetStr == null)
		{
			// 空白文字を返す
			return "";
		}
		
		return targetStr;
	}
	
	/**
	 * 数値がnullの場合、空白文字で置き換える。
	 * @param targetDec 対象データ
	 * @return String  変換後文字列
	 **/
	public static String nullToBlank(BigDecimal targetDec)
	{
		if(targetDec == null)
		{
			return "";
		}
		return targetDec.toString();
	}
	
	/**
	 * ファイル書込み処理
	 * 
	 * @param commonItem 対象文字列
	 * @param writeDataList 書込みデータリスト
	 * @param outputFile 書込みファイル
	 * @return String  変換後文字列
	 * @throws Exception 例外
	 **/
	public static void fileDataWrite(JBSbatCommonItem commonItem,
										List<String> writeDataList,
										String outputFile) throws Exception
	{
		BufferedWriter bw = null;

		try
		{
			// 書込みファイル
			bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile)));			// 文字コードＯＳ準拠

			String data = null;

			// ファイル内容を全行読込
			for(int i = 0; i < writeDataList.size(); i++)
			{
				data = writeDataList.get(i);				// 1行読込み
				bw.append(data);
			}

		}
		catch (IOException ioe)
		{
			commonItem.getLogPrint().printDebugLog(ioe.getMessage());
			throw ioe;
		}
		finally
		{
			// 書込みファイルクローズ
			if (bw != null)
			{
				try
				{
					bw.flush();
					bw.close();
				}
				catch (IOException ioe)
				{
					commonItem.getLogPrint().printDebugLog("bw close error");
				}
			}
		}
		return;
	}
}
