/*********************************************************************
*  All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名			：eo顧客基幹システム
*	モジュール名		：JBSbatKKEoTokeiChrgFileOputNt
*	ソースファイル名	：JBSbatKKEoTokeiChrgFileOputNt.java
*	作成者				：富士通　
*	作成日				：2011年10月31日
*＜機能概要＞
*　ｅｏ光テレビ統計情報（課金）ファイル出力（ＮＴ）部品です。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2011/10/31  FJ)久保田	新規作成
*	v3.00.00	2012/08/30  FJ)藤本		【ST1-2012-0000404】障害対応
*	v3.01.00	2012/11/13  FJ)倉上		【ST1-2012-0000927,928】障害対応
*	v3.02.00	2012/11/23	FJ)柳		【TAI-2012-0000095】対応
*	v4.00.00	2012/12/25	FJ)古内		【ST1-2012-0000080】対応
*	v4.01.00	2013/02/27	FJ)石原		【KT1-2013-0000296】対応
*	v74.00.00	2024/12/02	FJ)井上		ANK-4592-00-00   テレビ新コース（スカパー用）導入対応
*********************************************************************/
package eo.business.service;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import eo.business.common.JBSbatBusinessService;
import eo.business.util.file.JBSbatKKIFM137;
import eo.business.util.table.JBSbatKK_M_PPLAN;
import eo.framework.application.JBSbatBusinessException;
import eo.framework.db.JBSbatSQLAccess;
import eo.framework.file.JBSbatDefFileUtil;
import eo.framework.file.JBSbatInputFileUtil;
import eo.framework.file.JBSbatOutputFileUtil;
import eo.framework.item.JBSbatCommonDBInterface;
import eo.framework.item.JBSbatCommonItem;
import eo.framework.item.JBSbatOutputItem;
import eo.framework.item.JBSbatServiceInterfaceMap;
import eo.framework.util.JBSbatAplConst;
import eo.framework.util.JBSbatDateUtil;
import eo.framework.util.JBSbatStringUtil;

/**
* (クラスの機能概要) <p>
*<BR>
* @author 富士通
*/
public class JBSbatKKEoTokeiChrgFileOputNt extends JBSbatBusinessService
{
	/**▼▼▼▼▼▼ツールから生成した宣言です 開始▼▼▼▼▼▼*/
	/** テーブル(料金グループ)*/
	private static final String D_TBL_NAME_KK_M_PRC_GRP = "KK_M_PRC_GRP";

	/** SQL定義キー(KK_SELECT_004)*/
	private static final String KK_M_PRC_GRP_KK_SELECT_004 = "KK_SELECT_004";

	/** SQL定義キー(KK_SELECT_005)*/
	private static final String KK_M_PRC_GRP_KK_SELECT_005 = "KK_SELECT_005";

	/** SQL定義キー(KK_SELECT_006)*/
	private static final String KK_M_PRC_GRP_KK_SELECT_006 = "KK_SELECT_006";

	/** テーブルアクセスクラス(料金グループ)*/
	private JBSbatSQLAccess db_KK_M_PRC_GRP = null;
	/**▲▲▲▲▲▲ツールから生成した宣言です 終了▲▲▲▲▲▲*/
	
	/** ｅｏ光統計情報データ件数ファイル（ネット・テレビ）*/
	private static final String FILE_NAME_NET_TV = "KKIFM224002.csv";

	/** ｅｏ光テレビ統計情報（課金）抽出（Ｐ．Ｋ．Ｏ）ファイル*/
	private static final String FILE_KKIFM137007 = "KKIFM137001.csv";

	/** 共通ヘッダー部_タイトル１*/
	private static final String TITLE1_STR = "Ｋ−ＣＡＴ　ｅｏ光テレビ（";

	/** 共通ヘッダー部_タイトル２*/
	private static final String TITLE2_STR = "年";

	/** 共通ヘッダー部_タイトル３*/
	private static final String TITLE3_STR = "月末　課金数）";

	/** ヘッダー部1行目_固定文字列(,,,,)*/
	private static final String HEADER1_STR = ",,,,";

	/** ヘッダー部2行目_固定文字列(契約区分名,単価名称,単価コード,合計,)*/
	private static final String HEADER2_STR = "契約区分名,単価名称,単価コード,合計,";

	/** 文字列_コンマ*/
	private static final String STR_COMMA = ",";

	/** 文字列_ネット＋テレビ*/
	private static final String STR_NET_TV = "ネット＋テレビ";

	/** 回線場所住所コード_その他*/
	private static final String ADD_CD_STATE_ETC = "99";
	
	/** 回線場所住所コード_その他*/
	private static final String ADD_CD_CITY_ETC = "99999";

	/** 文字列_その他住所*/
	private static final String STR_ADD_ETC = "その他住所";

	/** 文字列_その他*/
	private static final String STR_OTHER = "その他";
	
	/** エンコード */
	private static final String ENCODE = "Shift-JIS";

	/** エラーメッセージ(置換え文字列：%2%) */
	private static final String MASSEAGE = "ファイル出力";

	/** 行ヘッダの出力有無を判定 */
	private boolean hasWriteRowHeader = true;
	
	/**
	 * 初期処理
	 * @param JBSbatCommonItem commonItem　バッチ共通パラメータ電文
	 * @throws Exception
	 */
	public void initial(JBSbatCommonItem commonItem) throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの初期処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した初期化のソースです 開始▼▼▼▼▼▼*/
		// 共通パラメータを設定します
		super.setCommonInfo(commonItem);

		// DBアクセスクラスを生成します
		db_KK_M_PRC_GRP = new JBSbatSQLAccess(commonItem, D_TBL_NAME_KK_M_PRC_GRP);
		/**▲▲▲▲▲▲ツールから生成した初期化のソースです 終了▲▲▲▲▲▲*/

		// *** NET+TVのファイル生成である場合、共通ヘッダを出力する。
		// 共通ヘッダー部の出力を行います。
		JBSbatOutputFileUtil out_obj = super.commonItem.getOutPutFile();
		
		// ANK-4592-00-00 MOD START
		getCommonHeaderRow(out_obj);
		// ANK-4592-00-00 MOD END
		
	/**▲▲▲▲▲▲業務サービスの初期処理を記述してください。▲▲▲▲▲▲*/
	}
	
	/**
	 * 主処理
	 * @return JBSbatOutputItem　出力情報
	 * @throws Exception
	 */
	public JBSbatOutputItem execute() throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの主処理を記述してください。▼▼▼▼▼▼*/
		
		super.logPrint.printDebugLog("execute_START");
		
		JBSbatOutputFileUtil out_obj = super.commonItem.getOutPutFile();
		
		// ヘッダー部の作成及び出力
		List<String> tokeiAddressList = createHeaderInfo(out_obj);
		
		// ｅｏ光テレビ統計情報（課金）抽出（Ｐ．Ｋ．Ｏ）ファイル(KKIFM137007)の読み込み
		Map<String, Map<String, Integer>> planXaddressMap = getKKIFM137007(tokeiAddressList);
		
		int processCounter = 0;
		
		// *** 基本サービスの情報を取得 ***
		processCounter += writePlnInfo(tokeiAddressList,
									   planXaddressMap,
									   KK_M_PRC_GRP_KK_SELECT_004, 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate());
		
		// *** 機器提供サービスの情報を取得 ***
		processCounter += writePlnInfo(tokeiAddressList,
									   planXaddressMap,
									   KK_M_PRC_GRP_KK_SELECT_005, 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate());

		// *** オプションサービスの情報を取得 ***
		processCounter += writePlnInfo(tokeiAddressList,
									   planXaddressMap,
									   KK_M_PRC_GRP_KK_SELECT_006, 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate(), 
									   commonItem.getOpeDate());
		
		// ****** ｅｏ光統計情報データ件数ファイル（ネット・テレビ）を出力 ******
		executeOutputFile(processCounter);
		
		super.logPrint.printDebugLog("execute_END");
		
		return null;
	/**▲▲▲▲▲▲業務サービスの主処理を記述してください。▲▲▲▲▲▲*/
	}

	/**
	 * 業務サービス終了処理
	 * @throws Exception
	 */
	public void terminal() throws Exception
	{
	/**▼▼▼▼▼▼業務サービスの終了処理を記述してください。▼▼▼▼▼▼*/
		/**▼▼▼▼▼▼ツールから生成した終了処理のソースです 開始▼▼▼▼▼▼*/
		// DBアクセスクラスをクローズします
		db_KK_M_PRC_GRP.close();
		/**▲▲▲▲▲▲ツールから生成した終了処理のソースです 終了▲▲▲▲▲▲*/
	/**▲▲▲▲▲▲業務サービスの終了処理を記述してください。▲▲▲▲▲▲*/
	}

	/**▼▼▼▼▼▼ツールから生成したメソッドです 開始▼▼▼▼▼▼*/
	
	/**▲▲▲▲▲▲ツールから生成したメソッドです 終了▲▲▲▲▲▲*/

	// ANK-4592-00-00 ADD START
	/**
	 * ファイルのヘッダ行を作成
	 * 
	 * @return ヘッダ情報
	 * @throws Exception 
	 */
	protected void getCommonHeaderRow(JBSbatOutputFileUtil out_obj) throws Exception {
		
		//ヘッダ情報を取得
		out_obj.write(getCommonHeader());
		
	}
	// ANK-4592-00-00 ADD END
	
	/**
	 * ファイルのヘッダ情報を取得
	 * 
	 * @return ヘッダ情報
	 */
	protected String getCommonHeader() {
		StringBuilder head_str = new StringBuilder();
		String opeDate = commonItem.getOpeDate();
		String fileYear = JBSbatDateUtil.adjustMonth(opeDate, -1);
		
		head_str.append(TITLE1_STR)
				.append(fileYear.substring(0, 4))
				.append(TITLE2_STR)
				.append(Integer.parseInt(fileYear.substring(4, 6)))
				.append(TITLE3_STR);

		return head_str.toString();
	}
	
	/**
	 * 件数ファイルのファイル名を取得
	 * 
	 * @return 件数ファイル名
	 */
	protected String getCountFileName()
	{
		return FILE_NAME_NET_TV;
	}
	
	/**
	 * 入力ファイル名を取得
	 * 
	 * @return 入力ファイル名
	 */
	protected String getInputFileName()
	{
		return FILE_KKIFM137007;
	}
	
	/**
	 * 行ヘッダ文字列を取得
	 * 
	 * @return 行ヘッダ文字列
	 */
	protected String getRowHeader()
	{
		return STR_NET_TV;
	}
	
	/**
	 * 
	 * ヘッダー部の作成及び出力を行います。
	 * 
	 * @param  out_obj   JBSbatOutputFileUtil
	 * @throws Exception 業務サービス内で発生した例外全般。
	 * 
	 */
	private ArrayList<String> createHeaderInfo(JBSbatOutputFileUtil out_obj) throws Exception
	{
		
		ArrayList<String> tokeiAddressCdList = new ArrayList<String>();
		
		// 指定ファイル読込み
		BufferedReader br = null;
		try {
			InputStreamReader is = new InputStreamReader(this.getClass().getClassLoader().getResourceAsStream("KKTokeiAddresscdList.txt"), ENCODE);
			
			br = new BufferedReader(is);
			
			String lineData = "";
			//ヘッダー部1行目の文字列を設定
			StringBuilder head1row_str = new StringBuilder(HEADER1_STR);
			//ヘッダー部2行目の文字列を設定
			StringBuilder head2row_str = new StringBuilder(HEADER2_STR);
			int count = 1;
			int count2 = 1;
			
			String cityCodeBK = "";
			
			while ((lineData = br.readLine()) != null)
			{
				// CSVファイル一行読込み ※一文字目がセミコロンの場合は読み飛ばす。
				if("".equals(lineData) || lineData.charAt(0) == '；')
				{
					continue;
				}
					
				// ワークリストに格納された一行分のファイルデータを格納
				String[] workArray = lineData.split(",");
				
				// リストにおける一番目の文字列を取得
				String firstStr = workArray[0];
				
				tokeiAddressCdList.add(firstStr);
				
				// リストの1番目の文字列が2桁の場合
				if(firstStr.length() == 2)
				{
					// ワークリストの2番目には都道府県名の前に連番を設定する。
					head1row_str.append(STR_COMMA);
					head2row_str.append(count2++ + workArray[1]).append(STR_COMMA);
				}
				// リストの1番目の文字列が5桁の場合
				else if(firstStr.length() == 5)
				{
					String cityCode = firstStr;
					
					// ヘッダ2に市町村名を設定する。
					head2row_str.append(workArray[2]).append(STR_COMMA);
					
					// 退避した市町村コードの上2桁と現在の市町村コードの上2桁が異なる場合
					if(!cityCodeBK.equals(cityCode.substring(0, 2)))
					{
						// ヘッダ1に都道府県名を設定する。
						head1row_str.append(count++ + workArray[1]).append(STR_COMMA);
						// 市町村コードを退避する。
						cityCodeBK = cityCode.substring(0, 2);
					}
					else
					{
						// ヘッダ１行目にカンマを設定する。
						head1row_str.append(STR_COMMA);
					}
				}
			}
			tokeiAddressCdList.add(ADD_CD_CITY_ETC);
			
			// ヘッダ部の出力を行います。
			out_obj.write(head1row_str.append(STR_OTHER).toString());
			out_obj.write(head2row_str.append(STR_ADD_ETC).toString());
		} catch (IOException e) {
			throw new JBSbatBusinessException("EKKB0020CE", new String[]{"KKTokeiAddresscdList.txt"});
		} finally {
			// ファイルのクローズ処理
			if (br != null)
			{
				br.close();
			}
		}
		
		return tokeiAddressCdList;
	}
	
	/**
	 * 
	 * ｅｏ光テレビ統計情報（課金）抽出（Ｐ．Ｋ．Ｏ）ファイル(KKIFM137007)の読み込みを行います。
	 * 
	 * @throws Exception 業務サービス内で発生した例外全般。
	 * 
	 */
	private Map<String, Map<String, Integer>> getKKIFM137007(List<String> printAddList) throws Exception 
	{
		// 料金プランx住所マップ
		Map<String, Map<String, Integer>> planXaddressMap = new HashMap<String, Map<String, Integer>>();
		
		// フリー項目を取得。
		String file_path = commonItem.getFreeItem() + getInputFileName();
		
		JBSbatInputFileUtil inFileObj = new JBSbatInputFileUtil(file_path);
		// 入力定義ファイルオブジェクトを生成する
		JBSbatDefFileUtil fileDef = new JBSbatDefFileUtil(JBSbatAplConst.getAplConstValue("IND") + "KKIFM137.def",inFileObj);
		//Readerオブジェクトを生成する。
		inFileObj.createReader();
		
		int inputCount = 0;
		
		while (inFileObj.ready())
		{
			JBSbatServiceInterfaceMap inMap = fileDef.lineToObject(inFileObj.readLine(),inFileObj,++inputCount);
			
			String pplanCd = inMap.getString(JBSbatKKIFM137.PPLAN_CD);
			if (!planXaddressMap.containsKey(pplanCd))
			{
				planXaddressMap.put(pplanCd, new HashMap<String, Integer>());
			}
			Map<String, Integer> planMap = planXaddressMap.get(pplanCd);
			
			String kaisenPlaceAddCd = inMap.getString(JBSbatKKIFM137.KAISEN_PLACE_AD_CD);
			if (kaisenPlaceAddCd == null || "".equals(kaisenPlaceAddCd))
			{
				kaisenPlaceAddCd = "99999999999";
			}
			
			String stateCd = kaisenPlaceAddCd.substring(0, 2);
			if (!printAddList.contains(stateCd))
			{
				stateCd = ADD_CD_STATE_ETC;
			}
			String cityCd = kaisenPlaceAddCd.substring(0, 5);
			if (!printAddList.contains(cityCd))
			{
				cityCd = ADD_CD_CITY_ETC;
			}
			
			if (!planMap.containsKey(stateCd))
			{
				planMap.put(stateCd, 0);
			}
			if (!planMap.containsKey(cityCd))
			{
				planMap.put(cityCd, 0);
			}
			planMap.put(stateCd, planMap.get(stateCd) + 1);
			planMap.put(cityCd, planMap.get(cityCd) + 1);
		}
		// ファイルのクローズ処理
		inFileObj.close();
		
		return planXaddressMap;
	}
	
	/**
	 * 各種料金プランに該当するレコード情報を作成
	 * @param strbuild
	 * @param pplanCd
	 * @param pplanNm
	 */
	private void makeRowData(StringBuilder strbuild, Map<String, Map<String, Integer>> planXaddressMap, String pplanCd, String pplanNm)
	{
		if (hasWriteRowHeader)
		{
			strbuild.append(getRowHeader()).append(STR_COMMA);
			hasWriteRowHeader = false;
		}
		else
		{
			strbuild.append(STR_COMMA);
		}
		strbuild.append(pplanNm).append(STR_COMMA);
		strbuild.append(pplanCd).append(STR_COMMA);
		
		// 契約数合計結果取得の呼び出し
		if (planXaddressMap.containsKey(pplanCd))
		{
			// 集計結果に対象の料金プランが存在する場合は「住所コード」が５桁（市区町村）のデータを集計
			int counter = 0;
			Map<String, Integer> planMap = planXaddressMap.get(pplanCd);
			Iterator<String> it = planMap.keySet().iterator();
			while (it.hasNext())
			{
				String key = it.next();
				if (key.length() == 5)
				{
					counter += planMap.get(key);
				}
			}
			strbuild.append(counter);
		}
		else
		{
			// 集計結果に対象の料金プランが存在しない場合は「0」固定
			strbuild.append(0);
		}
	}
	
	/**
	 * 
	 * 料金プランコード、料金プラン名を取得し、データを出力します。
	 * 
	 * @throws Exception 業務サービス内で発生した例外全般。
	 * 
	 */
	private int writePlnInfo(List<String> tokeiAddressList, Map<String, Map<String, Integer>> planXaddressMap, String sqlDefKey, String... params) throws Exception 
	{
		int processCounter = 0;
		
		// 料金グループ情報の抽出
		// SQL実行結果取得用mapを生成（料金グループ）
		JBSbatCommonDBInterface prcGprPrcMap = new JBSbatCommonDBInterface(); 
		
		StringBuilder bodyPrcStr = new StringBuilder();
		
		// バイント変数のリストを生成します
		JBSbatCommonDBInterface paramList = new JBSbatCommonDBInterface();
		for (String param : params)
		{
			paramList.setValue(param.toString());
		}
		// DBアクセスを実行します
		db_KK_M_PRC_GRP.selectBySqlDefine(paramList, sqlDefKey);
		
		// 検索結果を取得する
		for(prcGprPrcMap = db_KK_M_PRC_GRP.selectNext(); null != prcGprPrcMap ; prcGprPrcMap = db_KK_M_PRC_GRP.selectNext())
		{
			String pplanKoteiAmnt = JBSbatStringUtil.Rtrim(prcGprPrcMap.getString("PPLAN_KOTEI_AMNT"));
			if ("".equals(pplanKoteiAmnt))
			{
				// 固定単価が「NULL（※空含む）」の場合、テレビガイド誌及びＮＨＫ団体一括以外は出力対象外とする。
				String opSvcCd = prcGprPrcMap.getString("SVC_CD");
				if (!("B068".equals(opSvcCd) || "B069".equals(opSvcCd)))
				{
					continue;
				}
			}
			else
			{
				// 固定単価が「NULL（※空含む）」出ない場合は、固定単価が「1」未満の場合出力対象外とする。
				if (Long.parseLong(pplanKoteiAmnt) < 1)
				{
					continue;
				}
			}
			
			bodyPrcStr.setLength(0);
			makeRowData(bodyPrcStr,
						planXaddressMap,
						JBSbatStringUtil.Rtrim(prcGprPrcMap.getString(JBSbatKK_M_PPLAN.PPLAN_CD)),
						JBSbatStringUtil.Rtrim(prcGprPrcMap.getString(JBSbatKK_M_PPLAN.PPLAN_NM)));
			
			if (planXaddressMap.containsKey(JBSbatStringUtil.Rtrim(prcGprPrcMap.getString(JBSbatKK_M_PPLAN.PPLAN_CD))))
			{
				Map<String, Integer> addressMap = planXaddressMap.get(JBSbatStringUtil.Rtrim(prcGprPrcMap.getString(JBSbatKK_M_PPLAN.PPLAN_CD)));
				// 出力対象となるデータが存在しない場合
				for (String address : tokeiAddressList)
				{
					if (addressMap.containsKey(address))
					{
						bodyPrcStr.append(STR_COMMA).append(addressMap.get(address));
					}
					else
					{
						bodyPrcStr.append(STR_COMMA).append("0");
					}
				}
			}
			else
			{
				// 出力対象となるデータが存在しない場合
				for (String address : tokeiAddressList)
				{
					bodyPrcStr.append(STR_COMMA).append("0");
				}
			}
			super.commonItem.getOutPutFile().write(bodyPrcStr.toString());
			
			processCounter++;
		}
		return processCounter;
	}
	
	/**
	 * 	ｅｏ光統計情報データ件数ファイル（ネット・テレビ）を出力します。<br>
	 * <p>
	 * @param record_cnt 出力情報
	 * @param file_path ファイル名(フルパス)
	 * @throws JBSbatBusinessException 
	 * @throws IOException 業務サービス内で発生した例外全般。
	 */	
	private void executeOutputFile(int record_cnt) throws IOException, JBSbatBusinessException
	{
		
		String count_file = commonItem.getFreeItem() + getCountFileName();
		
		// 一時ファイル読込み処理
		BufferedWriter wr = null;
		try
		{
			// パラメータで渡された中間ファイルを出力する。
			wr = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(count_file), ENCODE));
			// ファイル書き込み
			wr.write("\"" + String.valueOf(record_cnt) + "\"");
			wr.write("\n");
			wr.flush();
		}
		catch(IOException e)
		{
			throw new JBSbatBusinessException("EKKB0250CE", new String[]{getCountFileName(), MASSEAGE});
		}
		finally
		{
			if (null != wr)
			{
				wr.close();
			}
		}
	}
}
