/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JFUDataBeanAccess
*   ソースファイル名：JFUDataBeanAccess.java
*   作成者          ：富士通
*   日付            ：2011年07月22日
*＜機能概要＞
*   DataBeanアクセス部品です。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/07/22   FJ）和田    新規作成
*
**********************************************************************/
package eo.web.webview.common;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.web.x31.X31CWebConst;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccess;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccessArray;
import com.fujitsu.futurity.web.x31.X31SWebLog;

/**
 * DataBeanアクセス部品です。
 * <br>
 * @author 富士通
 */
public class JFUDataBeanAccessHelper
{
	/** パスのセパレータ */
	private static final String SEP = "/";

	/** 複数要素 */
	private static final String MULTI_TYPE = "n";

	/** パスタイプ アイテム */
	private static final String TYPE_ITEM = "1";

	/** パスタイプ データBean */
	private static final String TYPE_BEAN = "2";

	/**
	 * 指定の要素番号のデータBeanタイプを取得します。<br>
	 * データBeanA/0/データBeanB となっている場合、データBeanA[0]に紐付くデータBeanBを取得します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	public static X31SDataBeanAccess getDataBeanTypeByPath(X31SDataBeanAccess bean, String componentIDPath)
	{
		return JFUDataBeanAccessHelper.getDataBeanTypeByPath(bean, componentIDPath, 0);
	}

	/**
	 * 指定の要素番号のデータBeanタイプを取得します。<br>
	 * データBeanA/0/データBeanB となっている場合、データBeanA[0]に紐付くデータBeanBを取得します。<br>
	 * データBeanA/0/データBeanB/n/データBeanC となっている場合、データBeanA[0]のデータBeanB[n番目(引数のidx)]に紐付くデータBeanCを取得します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param idx パス中の「n」を置換する要素番号
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	public static X31SDataBeanAccess getDataBeanTypeByPath(X31SDataBeanAccess bean, String componentIDPath, int idx)
	{
		return JFUDataBeanAccessHelper.getDataBeanType(bean, componentIDPath, idx, false, TYPE_BEAN);
	}

	/**
	 * Mapのキーと値に合致するデータBeanタイプを取得します。<br>
	 * データBeanA/0/データBeanB/n となっている場合、データBeanA[0]に紐付くデータBeanB(複数)に対して、<br>
	 * 引数のMapのキーと値に合致するデータBeanBを取得します。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param map 条件を保持するMap
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	public static X31SDataBeanAccess[] getDataBeanListByPathWithKey(X31SDataBeanAccess bean, String componentIDPath, Map<String, String> map)
	{

		List<X31SDataBeanAccess> beanList = new ArrayList<X31SDataBeanAccess>();
		X31SDataBeanAccess workBean = null;

		int cnt = 0;

		while (true)
		{
			workBean = JFUDataBeanAccessHelper.getDataBeanTypeByPath(bean, componentIDPath, cnt);

			if (workBean == null)
			{
				break;
			}

			String key = null;
			String val = null;
			String beanItem = null;
			boolean bol = false;

			for (Iterator iterator = map.keySet().iterator(); iterator.hasNext();)
			{
				key = (String)iterator.next();
				val = map.get(key);
				beanItem = workBean.sendMessageString(key, X31CWebConst.DATABEAN_GET_VALUE);
				if (val.equals(beanItem))
				{
					bol = true;
				}
				else
				{
					bol = false;
					break;
				}
			}
			if (bol)
			{
				beanList.add(workBean);
			}
			cnt++;
		}

		return beanList.toArray(new X31SDataBeanAccess[0]);
	}

	/**
	 * 指定の要素番号のデータBeanタイプを取得します。<br>
	 * データBeanA/0/データBeanB となっている場合、データBeanA[0]に紐付くデータBeanBを取得します。<br>
	 * データBeanが null の場合は再帰的に生成します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	public static X31SDataBeanAccess createAndGetDataBeanTypeByPath(X31SDataBeanAccess bean, String componentIDPath)
	{
		return JFUDataBeanAccessHelper.createAndGetDataBeanTypeByPath(bean, componentIDPath, 0);
	}

	/**
	 * 指定の要素番号のデータBeanタイプを取得します。<br>
	 * データBeanA/0/データBeanB となっている場合、データBeanA[0]に紐付くデータBeanBを取得します。<br>
	 * データBeanA/0/データBeanB/n/データBeanC となっている場合、データBeanA[0]のデータBeanB[n番目(引数のidx)]に紐付くデータBeanCを取得します。<br>
	 * データBeanが null の場合は再帰的に生成します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param idx パス中の「n」を置換する要素番号
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	public static X31SDataBeanAccess createAndGetDataBeanTypeByPath(X31SDataBeanAccess bean, String componentIDPath, int idx)
	{
		return JFUDataBeanAccessHelper.getDataBeanType(bean, componentIDPath, idx, true, TYPE_BEAN);
	}

	/**
	 * 指定の要素番号のデータBeanタイプから項目を取得します。<br>
	 * データBeanA/0/項目B となっている場合、データBeanA[0]で定義されている項目Bの値を取得します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。項目のみのパス指定はその限りではありません。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @return アイテム
	 */
	public static String getDataBeanItemByPath(X31SDataBeanAccess bean, String componentIDPath)
	{
		return JFUDataBeanAccessHelper.getDataBeanItemByPath(bean, componentIDPath, 0);
	}

	/**
	 * 指定の要素番号のデータBeanタイプから項目を取得します。<br>
	 * データBeanA/0/項目B となっている場合、データBeanA[0]で定義されている項目Bの値を取得します。<br>
	 * データBeanA/0/データBeanB/n/項目C となっている場合、データBeanA[0]のデータBeanB[n番目(引数のidx)]の項目Cの値を取得します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。項目のみのパス指定はその限りではありません。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param idx パス中の「n」を置換する要素番号
	 * @return アイテム
	 */
	public static String getDataBeanItemByPath(X31SDataBeanAccess bean, String componentIDPath, int idx)
	{
		X31SDataBeanAccess subBean = JFUDataBeanAccessHelper.getDataBeanType(bean, componentIDPath, idx, false, TYPE_ITEM);

		if (subBean == null)
		{
			return null;
		}

		// 一番最後の要素がターゲット項目ID
		String[] itemPathArray = componentIDPath.split(SEP);
		String targetItem = itemPathArray[itemPathArray.length - 1];

		String result = subBean.sendMessageString(targetItem, X31CWebConst.DATABEAN_GET_VALUE);
		return result;
	}

	/**
	 * パスを指定してデータBeanに値を設定します。<br>
	 * データBeanA/0/項目B となっている場合、データBeanA[0]で定義されている項目Bに値を設定します。<br>
	 * データBeanが null の場合は再帰的に生成します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。項目のみのパス指定はその限りではありません。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param value 設定する値
	 */
	public static void setDataBeanItemByPath(X31SDataBeanAccess bean, String componentIDPath, String value)
	{
		JFUDataBeanAccessHelper.setDataBeanItemByPath(bean, componentIDPath, value, 0);
	}

	/**
	 * パスを指定してデータBeanに値を設定します。<br>
	 * データBeanA/0/項目B となっている場合、データBeanA[0]のデータBeanタイプで定義されている項目Bに値を設定します。<br>
	 * データBeanA/0/データBeanB/n/項目C となっている場合、データBeanA[0]のデータBeanB[n番目(引数のidx)]の項目Cに値を設定します。<br>
	 * データBeanが null の場合は再帰的に生成します。<br>
	 * 先頭パスのデータBeanは引数の「対象データBean」と同じである必要があります。項目のみのパス指定はその限りではありません。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param componentIDPath データBean階層パス
	 * @param value 設定する値
	 * @param idx パス中の「n」を置換する要素番号
	 */
	public static void setDataBeanItemByPath(X31SDataBeanAccess bean, String componentIDPath, String value, int idx)
	{
		X31SDataBeanAccess subBean = JFUDataBeanAccessHelper.getDataBeanType(bean, componentIDPath, idx, true, TYPE_ITEM);
		if (subBean == null)
		{
			X31SWebLog.DEBUG_LOG.debug("【JFUDataBeanAccessHelper.setDataBeanItemByPath】データBeanがnullのため処理停止");
			return;
		}

		// 一番最後の要素がターゲット項目ID
		String[] itemPathArray = componentIDPath.split(SEP);
		String targetItem = itemPathArray[itemPathArray.length - 1];

		String result = subBean.sendMessageString(targetItem, X31CWebConst.DATABEAN_SET_VALUE, value);
		if (result == null)
		{
			X31SWebLog.DEBUG_LOG.debug("【JFUDataBeanAccessHelper.setDataBeanItemByPath】"
					+ targetItem + "の設定処理に失敗しました。階層パス：" + componentIDPath);
		}
	}

	/**
	 * パスを指定してデータBeanタイプ/アイテムを取得します。<br>
	 * 項目A/0/項目B となっている場合、項目A[0]のデータBeanタイプを取得します。<br>
	 * <br>
	 * @param bean 対象データBean
	 * @param path データBean階層パス
	 * @param idx パス中の「n」を置換する要素番号
	 * @param create データBeanがnullの場合生成するかどうか
	 * @param type 1:最終項目がアイテムの場合 2:最終項目がデータBeanタイプの場合
	 * @return X31SDataBeanAccess データBeanタイプ
	 */
	private static X31SDataBeanAccess getDataBeanType(X31SDataBeanAccess bean, String path, int idx, boolean create, String type)
	{
		if (bean == null || path == null)
		{
			return null;
		}

		X31SDataBeanAccess subBean = bean;

		String componentIDPath = path.replace(MULTI_TYPE, Integer.toString(idx));

		String[] itemPathArray = componentIDPath.split(SEP);

		int count = itemPathArray.length - 1;

		for (int i = 0; i <= count; i += 2)
		{
			if (type.equals(TYPE_ITEM) && i == count)
			{
				break;
			}

			String typeBeanName = itemPathArray[i];

			int index = 0;
			if (i < count)
			{
				index = Integer.parseInt(itemPathArray[i + 1]);
			}

			X31SDataBeanAccessArray subBeanArray = subBean.getDataBeanArray(typeBeanName);
			subBean = subBeanArray.getDataBean(index);

			if (subBean == null)
			{
				if (create)
				{
					subBeanArray.addDataBean();
					subBean = subBeanArray.getDataBean(index);
				}
				else
				{
					break;
				}
			}
		}

		return subBean;
	}
}
