/*********************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*	モジュール名	：JCHCsvDataUtil
*	ソースファイル名：JCHCsvDataUtil.java
*	作成者			：富士通
*	日付			：2012年01月18日
*＜機能概要＞
*	ＣＳＶデータを編集するユーティリティクラスです。
*＜修正履歴＞
*	バージョン	修正日		修正者		修正内容
*	v1.00.00	2012/01/18	富士通		新規作成
*
**********************************************************************/
package eo.web.webview.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.SortedMap;
import java.util.TreeMap;

import com.fujitsu.futurity.web.x31.X31CWebConst;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccess;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccessArray;

import eo.common.constant.JACStrConst;
import eo.common.util.JCCToolTextDateFormat;
import eo.common.util.JCCToolTextDecimalFormat;

/**
 * ＣＳＶデータ編集ユーティリティ
 * <br>
 * @author 富士通
 */
public class JCHCsvDataUtil 
{

    /** 改行 */
    private final static String NEW_LINE = "\r\n";
    /** ダブルクォート */
    private final static String DBL_QUOATE = "\"";
    
    /** Bean配列アクセサ */
    private X31SDataBeanAccessArray beanAccessArray = null;
    
    /** ソートカラム情報 */
    private ArrayList<String> sortColumns = null;
    
    /** フィルターカラム情報 */
    private ArrayList<String> filterColumns = null;
    
    /** ヘッダ */
    private String header = null;
    
    /** コード変換リスト */
    private HashMap<String, ArrayList<String>> codeConvertList = null;
    
    /** フォーマットリスト */
    private HashMap<String, String> formatList = null;
    /** フォーマットタイプ */
    private final static String FORMAT_DATE = "0";
    private final static String FORMAT_AMNT = "1";
    
    /** コード変換及びフォーマットの属性区切り */
    private final static String ATTR_SEPARATER = "\t";
    
    /** 項目の囲み */
    private boolean itemKakomi;
    
	/**
	 * インスタンス生成.<br>
	 * ＣＳＶデータ編集ユーティリティのインスタンスを生成します。
	 * <br>
	 * @param beanArray    Bean配列アクセサ
	 * @return ＣＳＶデータ編集ユーティリティ
	 */
	public static JCHCsvDataUtil createInstance(X31SDataBeanAccessArray beanArray) {

		JCHCsvDataUtil util = new JCHCsvDataUtil();
		
		util.beanAccessArray = beanArray;
		util.filterColumns = new ArrayList<String>();
		util.sortColumns = new ArrayList<String>();
		util.codeConvertList = new HashMap<String, ArrayList<String>>();
		util.formatList = new HashMap<String, String>();
		util.itemKakomi = false;

		return util;
	}
	
	/**
	 * フィルターカラム設定処理.<br>
	 * <br>
	 * @param columns フィルタカラム
	 */
	public void setFilterColumns(String[][] columns)
	{
		// ヘッダ生成
		StringBuffer header = new StringBuffer();
		
		String[] headerList = columns[0];
		for (int i = 0; i < headerList.length; i++)
		{
			if (header.length() != 0)
			{
				header.append(JACStrConst.COMMA);
			}
			header.append(headerList[i]);
		}
		this.header = header.toString();
		
		// フィルタカラム情報
		String[] colList = columns[1];
		for (int i = 0; i < colList.length; i++)
		{
			this.filterColumns.add(colList[i]);
		}
	}
	
	/**
	 * フィルターカラム設定処理.(囲みあり)<br>
	 * <br>
	 * @param columns フィルタカラム
	 */
	public void setFilterColumnsDblQuoate(String[][] columns)
	{
		// ヘッダ生成
		StringBuffer header = new StringBuffer();
		
		String[] headerList = columns[0];
		for (int i = 0; i < headerList.length; i++)
		{
			if (header.length() != 0)
			{
				header.append(JACStrConst.COMMA);
			}
			header.append(DBL_QUOATE);
			header.append(headerList[i]);
			header.append(DBL_QUOATE);
		}
		this.header = header.toString();
		
		// フィルタカラム情報
		String[] colList = columns[1];
		for (int i = 0; i < colList.length; i++)
		{
			this.filterColumns.add(colList[i]);
		}
	}
	
	/**
	 * ソートカラム設定処理.<br>
	 * <br>
	 * @param columns ソートカラム
	 */
	public void setSortColumns(String[] columns)
	{
		// ソートカラム情報
		for (int i = 0; i < columns.length; i++)
		{
			this.sortColumns.add(columns[i]);
		}
	}
	
	/**
	 * コード変換設定追加処理.<br>
	 * <br>
	 * @param column  カラム
	 * @param code    変換元コード
	 * @param name    変換先名称
	 */
	public void addCodeConvertor(String column, String code, String name)
	{
		ArrayList<String> codeConvertors = null;
		if (this.codeConvertList.containsKey(column))
		{
			codeConvertors = this.codeConvertList.get(column);
		}
		else
		{
			codeConvertors = new ArrayList<String>();
			this.codeConvertList.put(column, codeConvertors);
		}
		
		StringBuffer codeConvertor = new StringBuffer();
		codeConvertor.append(code).append(ATTR_SEPARATER).append(name);
		codeConvertors.add(codeConvertor.toString());
	}
	
	/**
	 * 日付フォーマット変換設定追加処理.<br>
	 * <br>
	 * @param column      カラム
	 * @param dateformat  変換先フォーマット
	 * @param name        変換元フォーマット
	 */
	public void addDateFormatter(String column, String dateformat, String parseformat)
	{
		StringBuffer formatter = new StringBuffer();
		formatter.append(FORMAT_DATE).append(ATTR_SEPARATER).append(dateformat).append(ATTR_SEPARATER).append(parseformat);
		this.formatList.put(column, formatter.toString());
	}
	
	/**
	 * 円フォーマット変換設定追加処理.<br>
	 * <br>
	 * @param column      カラム
	 */
	public void addYenFormatter(String column)
	{
		StringBuffer formatter = new StringBuffer();
		formatter.append(FORMAT_AMNT).append(ATTR_SEPARATER).append("\\");
		this.formatList.put(column, formatter.toString());
	}
	
	/**
	 * 金額フォーマット変換設定追加処理.<br>
	 * <br>
	 * @param column      カラム
	 */
	public void addAmntFormatter(String column)
	{
		StringBuffer formatter = new StringBuffer();
		formatter.append(FORMAT_AMNT).append(ATTR_SEPARATER).append(JACStrConst.SPACE_1);
		this.formatList.put(column, formatter.toString());
	}
	
	/**
	 * 金額フォーマット変換設定追加処理.(スペース追加なし)<br>
	 * <br>
	 * @param column      カラム
	 */
	public void addAmntFormatterNoSpace(String column)
	{
		StringBuffer formatter = new StringBuffer();
		formatter.append(FORMAT_AMNT).append(ATTR_SEPARATER);
		this.formatList.put(column, formatter.toString());
	}
	
	/**
	 * 項目囲み有効設定.<br>
	 * <br>
	 * @param column      カラム
	 */
	public void setItemKakomiOn()
	{
		this.itemKakomi = true;
	}
	
	/**
	 * ＣＳＶデータ生成処理.<br>
	 * @return ＣＳＶデータ(バイト配列) 
	 * @throws Exception 
	 */
	public byte[] createData() throws Exception
	{
		StringBuffer data = new StringBuffer();
		
		// ◇ヘッダ
		if (this.header != null)
		{
			data.append(this.header);
		}
		
		// ◇ソートリスト生成
		SortedMap<String, Integer> sortList = null;
		if (this.sortColumns.size() > 0)
		{
			sortList = new TreeMap<String, Integer>();
			for (int i = 0; i < this.beanAccessArray.getCount(); i++)
			{
				String key = this.generateSortKey(this.beanAccessArray.getDataBean(i));
				sortList.put(key, i);
			}
		}
		
		// ◇ソートリストが生成されている場合
		if (sortList != null)
		{
			for (int idxRow: sortList.values())
			{
				if (data.length() != 0)
				{
					data.append(NEW_LINE);
				}
				String rowData = buildRowData(this.beanAccessArray.getDataBean(idxRow));
				data.append(rowData);
			}
		}
		else
		{
			// データビーン配列の順序で生成
			for (int i = 0; i < this.beanAccessArray.getCount(); i++)
			{
				if (data.length() != 0)
				{
					data.append(NEW_LINE);
				}
				String rowData = buildRowData(this.beanAccessArray.getDataBean(i));
				data.append(rowData);
			}
		}
		
		return data.toString().getBytes(JACStrConst.ENCODE_MS932);
	}
	
	/**
	 * 行データ生成処理.<br>
	 * フィルターカラム情報を使用して行データを生成します。<br>
	 * コード変換、またはフォーマット変換が設定されている場合、変換を実施します。
	 * @param  bean データビーン配列の１行
	 * @return 行データ 
	 */
	private String buildRowData(X31SDataBeanAccess bean)
	{
		StringBuffer rowData = new StringBuffer();
		
		for (int i = 0; i < this.filterColumns.size(); i++)
		{
			if (i != 0)
			{
				rowData.append(JACStrConst.COMMA);
			}
			String itemValue = bean.sendMessageString(this.filterColumns.get(i), X31CWebConst.DATABEAN_GET_VALUE);
			// ◇コード変換
			if (this.codeConvertList.containsKey(this.filterColumns.get(i)))
			{
				itemValue = doCodeConvert(this.filterColumns.get(i), itemValue);
			}
			// ◇フォーマット変換
			if (this.formatList.containsKey(this.filterColumns.get(i)))
			{
				itemValue = doFormat(this.filterColumns.get(i), itemValue);
			}
			// ◇項目囲み
			if (this.itemKakomi)
			{
				itemValue = DBL_QUOATE + itemValue + DBL_QUOATE;
			}
			rowData.append(itemValue);
		}
		
		return rowData.toString();
	}
	
	/**
	 * コード変換実行.<br>
	 * @param  column  カラム名
	 * @param  code    変換元
	 * @return 変換後 
	 */
	private String doCodeConvert(String column, String code)
	{
		String converted = code;
		
		ArrayList<String> converters = this.codeConvertList.get(column);
		for (String converter : converters)
		{
			String[] codeValue = converter.split(ATTR_SEPARATER);
			if (codeValue[0].equals(code))
			{
				converted = codeValue[1].trim();
				break;
			}
		}
		
		return converted;
	}
	
	/**
	 * フォーマット変換実行.<br>
	 * @param  column  カラム名
	 * @param  value   変換元
	 * @return 変換後 
	 */
	private String doFormat(String column, String value)
	{
		String converted = value;
		
		String formatter = this.formatList.get(column);
		String[] attr = formatter.split(ATTR_SEPARATER);

		if (FORMAT_DATE.equals(attr[0]))
		{
			converted = new JCCToolTextDateFormat(attr[1], attr[2]).formattedPrint(value);
		}
		else if (FORMAT_AMNT.equals(attr[0]))
		{
			converted = new JCCToolTextDecimalFormat("#,##0").formattedPrint(value);
			if (!JACStrConst.KARA_MOJI.equals(converted.trim()) && (attr.length >= 2))
			{
				converted = attr[1] + converted;
			}
		}
		
		return converted;
	}
	
	/**
	 * ソートキー生成処理.<br>
	 * @param  bean データビーン配列の１行
	 * @return ソートキー 
	 */
	private String generateSortKey(X31SDataBeanAccess bean)
	{
		StringBuffer key = new StringBuffer();
		
		for (int i = 0; i < this.sortColumns.size(); i++)
		{
			key.append(bean.sendMessageString(this.sortColumns.get(i), X31CWebConst.DATABEAN_GET_VALUE));
		}
		
		return key.toString();
	}
	
}
