/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：JCRModelCommon
*   ソースファイル名：JCRModelCommon.java
*   作成者          ：富士通
*   日付            ：2011年04月01日
*＜機能概要＞
*   モデル共通アクセッサー部品です。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/04/01   FJ          新規作成
*
**********************************************************************/

package eo.ejb.common;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;

import eo.common.util.JCCGetSystemDateUtil;
import eo.common.util.JCRUtilCommon;
import eo.ejb.common.edit.JCRejbQueryConditionEdit;
import eo.ejb.common.itemrelation.JCRejbDateChecker;
import eo.ejb.common.itemrelation.JCRejbQueryConditionTKCK;
import eo.ejb.domain.JSYejbBaseDomain;

/**
 * モデル共通アクセッサー部品です。<p>
 * サービスインターフェイスで実装します。
 * <BR>
 * @ author 富士通
 */
public class JCRModelCommon extends JCCModelCommon
{
	/**
	 * 判定開始年月日と判定終了年月日の差を求め、指定範囲日数との比較を行います。
	 * <br>
	 * @param judgeStatymd 判定開始年月日(yyyyMMdd)
	 * @param judgeEndymd  判定終了年月日(yyyyMMdd)
	 * @param scopeDayNum  指定範囲日数
	 * @param sameDayFlg   同日判定フラグ
	 * @return String 加減算した日付
	 */
	public static boolean checkScopeDayPrd(CAANMsg inMsg, AgentDispatchContext context, Object judgeStatymd, Object judgeEndymd, Object scopeDayNum, Object sameDayFlg)
	{
		return JCRejbDateChecker.checkScopeDayPrd(inMsg, context, judgeStatymd, judgeEndymd, scopeDayNum, sameDayFlg);
	}
	
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * 引数で渡された、条件作成情報から出力項目（SELECT句）、テーブル結合条件（FROM句）、
	 * 個別条件（WHERE句）を作成します。
	 * <BR>
	 * @param select_items [スキーマID].[フィールド名].[コード種別コード]: ･･･
	 * @param schma_id スキーマID 6桁（固定長）×100（最大）
	 * @param query_kmk_no クエリ項目番号 10桁（固定長）×100（最大）
	 * @param query_kmk_nm クエリ項目名 50桁（固定長 桁数が満たない場合はスペースで埋める）×100（最大）
	 * @param field_nm フィールド名 26桁（固定長 桁数が満たない場合はスペースで埋める）×100（最大）
	 * @param field_type_cd フィールドタイプコード 1桁（固定長）×100（最大）
	 * @param query_joken_cd クエリ条件コード 2桁（固定長）×100（最大）
	 * @param query_value クエリ値 40桁（固定長 桁数が満たない場合はスペースで埋める）×100（最大）
	 * @param or_joken_um OR条件有無 1桁（固定長）×100（最大）
	 * @param base_ymd 基準年月日
	 * @return
	 */
	public static HashMap createCondtionInfo(String select_items, String schma_id, String query_trgt_kmk_kanri_no , String query_kmk_no, 
												String query_kmk_nm, String field_nm, String field_type_cd, 
												String query_joken_cd, String query_value, String or_joken_um, 
												String base_ymd) throws IllegalArgumentException
	{
		return JCRejbCreateQueryCondition.createCondtionInfo(select_items, schma_id, query_trgt_kmk_kanri_no , query_kmk_no, 
																query_kmk_nm, field_nm, field_type_cd, 
																query_joken_cd, query_value, or_joken_um, base_ymd);
	}
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * SELECT句を返します。
	 * <BR>
	 * @param condition_info_map
	 * @return
	 * @throws Exception
	 */
	public static String getSelectItems(HashMap condition_info_map)
	{
		return JCRejbCreateQueryCondition.getSelectItems(condition_info_map);
	}
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * FROM句を返します。
	 * <BR>
	 * @param condition_info_map
	 * @return
	 * @throws Exception
	 */
	public static String getJoinCondtion(HashMap condition_info_map)
	{
		return JCRejbCreateQueryCondition.getJoinCondtion(condition_info_map);
	}
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * WHERE句を返します。
	 * <BR>
	 * @param condition_info_map
	 * @return
	 * @throws Exception
	 */
	public static String getCondtion(HashMap condition_info_map)
	{
		return JCRejbCreateQueryCondition.getCondtion(condition_info_map);
	}

	/**
	 *  問合せクエリ条件作成部品<BR>
	 * aliasを返します。
	 * <BR>
	 * @param condition_info_map
	 * @return
	 * @throws Exception
	 */
	public static ArrayList<String> getAlias(HashMap condition_info_map)
	{
		return JCRejbCreateQueryCondition.getAlias(condition_info_map);
	}
	
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * スキーマID、クエリ項目名、フィールド名、フィールドタイプ、クエリ値、
	 * クエリ条件コード、OR条件有無の単関連制約を実施します。
	 * それぞれの項目を固定長で区切った時、その個数がすべて同じ場合、TRUEを返します。
	 * <BR>
	 * @param msg CAANMsg
	 * @param context ディスパッチコンテキスト
	 * @return
	 * @throws Exception
	 */
	public static boolean isQueryConditionTKCK( CAANMsg msg , AgentDispatchContext context ) throws IllegalArgumentException
	{
		return JCRejbQueryConditionTKCK.isQueryConditionTKCK( msg , context);
	}
	/**
	 *  問合せクエリ条件作成部品<BR>
	 * 指定されたクエリ条件項目を指定された文字数で区切り、配列にして返します。
	 * <BR>
	 * @param edit
	 * @param length
	 * @return
	 * @throws IllegalArgumentException
	 */
	public static String[] splitQueryCondition( String edit , int length) throws IllegalArgumentException
	{
		return JCRejbQueryConditionEdit.splitQueryCondition( edit , length );
	}
	/**
	 * 
	 * @param inContext 
	 * @param inCBSMsg 
	 * @return 年月日時分
	 * @throws Exception 
	 */
	public static String JCRgetSystemDate(CAANMsg inCBSMsg, AgentDispatchContext inContext) throws Exception
	{
		return JCCGetSystemDateUtil.getSystemDateTime().get(JCCGetSystemDateUtil.KEY_YYYYMMDDHHMMSS).substring(0,12);
		
	}
	
	/**
	 * 
	 * @param msg      CAANMsg
	 * @param context  ディスパッチコンテキスト
	 * @param listNm1  サイズ比較リスト1
	 * @param listNm2  サイズ比較リスト2
	 * @param listNm3  サイズ比較リスト3
	 * @param delim    区切り文字
	 * @return
	 * @throws Exception
	 */
	public static boolean JCRejbListLengthCheck( CAANMsg msg , AgentDispatchContext context ,
														Object listNm1, Object listNm2 , Object listNm3 , Object delim)
	{
		return eo.ejb.common.itemrelation.JCRejbListLengthCheck.checkListLength(msg, context, listNm1, listNm2, listNm3, delim);
	}

	/**
	 * ResultSetからデータを引き上げます
	 * @param rs ResultSet
	 * @return 取得データ
	 * @throws SQLException エラー時
	 */
	public static List<Map<String, Object>> resultSetToListOfMap(ResultSet rs) throws SQLException
	{
		List<String> cols = new ArrayList<String>();
		ResultSetMetaData rsm = rs.getMetaData();
		int colCount = rsm.getColumnCount();
		for (int i = 1; i <= colCount; i++)
		{
			cols.add(rsm.getColumnName(i));
		}
		
		return resultSetToListOfMap(rs, cols.toArray(new String [colCount]));
	}

	/**
	 * ResultSetからデータを引き上げます
	 * @param rs ResultSet
	 * @return 取得データ
	 * @param cols 取得対象カラム名
	 * @throws SQLException エラー時
	 */
	public static List<Map<String, Object>> resultSetToListOfMap(ResultSet rs, String ... cols) throws SQLException
	{
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		
		while (rs.next())
		{
			Map<String, Object> data = mapInstance();

			for (String col : cols)
			{
				Object val = rs.getObject(col.toUpperCase());

//				System.out.println(String.format ("set (%s) to [%s].", val, col));
				data.put(col.toLowerCase(), val);
			}
			
			list.add(data);
		}
		
		return list;
	}

	/**
	 * nullチェック付きのHashMapインスタンスを生成します。
	 * @return マップ
	 */
	private static Map<String, Object> mapInstance()
	{
		return new HashMap<String, Object>()
		{
			private static final long serialVersionUID = 1L;

			@Override
			public Object put(String key, Object val)
			{
//				System.out.println ("-- k : " + key + " v : " + val);
				return super.put(key, val == null ? "" : val);
			}
		};
	}

	/**
	 * キー配列を使用して、CAANMsgから入力データをMapに引き上げます
	 * @param map データ格納先のマップ
	 * @param msg 入力データ
	 * @param keyAndTypes 項目定義
	 * @return マップ
	 */
	private static Map<String, Object> inMsgToMap(Map<String, Object> map, CAANMsg msg, Object[][] keyAndTypes)
	{
		if (JCRUtilCommon.isNull(keyAndTypes))
		{
			return map;
		}
		
		for (Object[] keyAndType : keyAndTypes)
		{
			String key = keyAndType[0].toString();
			String type = keyAndType[1].toString();
			
			String val = "";
			if ("int".equals(type))
			{
				val = Integer.toString(msg.getInt(key));
				map.put(key, val);
			}
			else if ("String".equals(type))
			{
				val = msg.getString(key);
				map.put(key, val);
			}
			else if (type.endsWith("[]"))
			{
				String listType = type.substring(0, type.length() - 2);

				List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
				@SuppressWarnings("unchecked")
				Class subListClass = null;
				try 
				{
					subListClass = Class.forName(listType);
				}
				catch (ClassNotFoundException e)
				{
//					System.out.println (e);
					continue;
				}
				
				map.put(key, list);
				
				CAANMsg[] subMsgs = msg.getCAANMsgList(key);
				if (null == subMsgs)
				{
					continue;
				}

				for (CAANMsg subMessage : subMsgs)
				{
					list.add(msgToMap(subMessage, subListClass));
				}
			}
			
			else
			{
				// error?
			}
		}
		
		return map;
	}

	/**
	 * CAANMsgをMapの階層構造に変換します。
	 * @param msg SerivceI/Fの入力
	 * @param clazz 入力の項目名が定義されているクラス
	 * @return マップ
	 */
	public static Map<String, Object> msgToMap(CAANMsg msg, Class<?> clazz)
	{
		Field contentsField = null;
		try
		{
			contentsField = clazz.getDeclaredField("CONTENTS");
		}
		catch (NoSuchFieldException e)
		{
//			System.out.println(e.getMessage());
			return null;
		}
		
		contentsField.setAccessible(true);
		
		Object[][] contents = null;
		try
		{
			contents = (Object[][])contentsField.get(contentsField);
		}
		catch (IllegalAccessException e)
		{
			return null;
		}
		
		return inMsgToMap(mapInstance(), msg, contents);
	}

	/**
	 * 単項目制約定義とドメイン定義から、単項目チェック定義を生成
	 * @param args 単項目制約定義情報
	 * @return	単項目制約情報（単項目チェック部品へ引き渡すチェック用パラメタ配列）
	 *
	 */
	@SuppressWarnings("unchecked")
	public static String[][] createTMCKArgs(String[][] args)
	{
		
		ArrayList tmckList = new ArrayList();
		for (int i = 0 ; i < args.length ; i++) 
		{
			ArrayList tmckRec = new ArrayList();
			String[] komokuDef = args[i];
			String domainID = komokuDef[7];
			String domainCls = "eo.ejb.domain.JSYejb" + domainID + "Domain";
			try
			{
				JSYejbBaseDomain domain = (JSYejbBaseDomain) Class.forName(domainCls).newInstance();
				tmckRec = domain.getTmckDefine(komokuDef);
				for (int p = 0 ; p < tmckRec.size() ; p++) 
				{
					tmckList.add(tmckRec.get(p));
				}
			}
			catch (Exception e) 
			{
			}
		}
	
		return (String[][])tmckList.toArray(new String[tmckList.size()][0]);
	
	}
	
}
