/*
 履歴:
 NO   日付        内容
 001  2021.04.26  新規作成
 */
package com.galaxygoby;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <DL>
 * <DT>クラス概要:
 * <DD>共有メモリアクセス用クラス
 * <DD>WEB/APサーバの共有メモリで管理するテーブル情報を取得する。
 * </DL>
 */
public class ShmStaticTable {

	/** スペース */
	private static final String SPACE = " ";

	/** 空行 */
	private static final String BLANK = "";

	/** カンマ */
	private static final String COMMA = ",";

	/** コロン */
	private static final String SEMICOLON = ";";

	/** クエスチョン */
	private static final String QUESTION = "?";

	/** 等号（=） */
	private static final String EQUAL = "=";

	/** 不等号、より大きい（>） */
	private static final String MORE_BIG = ">";

	/** 不等号、より小さい（<） */
	private static final String MORE_SMALL = "<";

	/** 不等号、大きいイコール（>=） */
	private static final String BIG_EQUAL = ">=";

	/** 不等号、小さいイコール（<=） */
	private static final String SMALL_EQUAL = "<=";

	/** 等しくない（!=） */
	private static final String NOT_EQUAL = "!=";

	/** 文字列（or） */
	private static final String STR_OR = "or";

	/** 文字列（and） */
	private static final String STR_AND = "and";

	/** 改行コード */
	private static final String BREAK_CODE = "\n";

	/** 空白入り改行コード */
	private static final String SPACE_BREAK_CODE = " \n";

	/** タブコード */
	private static final String TAB_CODE = "\t";

	/** 空白（char型） */
	private static final char CHAR_SPACE = ' ';

	/** ゼロ（char型） */
	private static final char CHAR_ZERO = '\0';

	/** 0:共有メモリモード, 1:ファイル入力モード */
	static int sharedMode = 0;

	/** 静的データ管理ファイル名称 */
	static String TableDefineFile;

	/** 静的データ管理ファイル更新時刻（ﾐﾘ秒） */
	static long DFModifiedTime = 0;

	/** 静的データファイルLIST */
	static Map<String, String[]> StaticDataFile = new HashMap<String, String[]>();

	/** 最大条件数 */
	private static final int MAX_COND = 20;

	// ライブラリをロード
	static {
		// 共有メモリモード判定
		getMode();
		// 共有メモリアクセスライブラリのロード
		if (sharedMode == 0) {
			System.loadLibrary("GG_SHM0011");
		}
	}

	// ネイティブメソッドを宣言
	/**
	 * <DL>
	 * <DT>C言語アプリケーション
	 * <DT>指定された検索文字列とアクセスパターン定義(XML)により、データ検索を行い、検索データ長を返却する。
	 * </DL>
	 * 
	 * @param inByte TableName/Key/in を改行文字区切りでByte列に設定。
	 * @return 検索結果データ長を返却。
	 */
	public native int SHM0011(byte[] inByte);

	/**
	 * <DL>
	 * <DT>C言語アプリケーション
	 * <DT>SHM0011で検索を行った結果を返却する。SHM0011でデータ長を取得した大きさ分だけ、
	 * <DT>本APでoutByte領域を確保し、SHM0011getDataでoutByte領域にデータ返却を行う。
	 * </DL>
	 * 
	 * @param outByte 返却データ領域。カラムが\tで、行が\nで区切られて返却。
	 */
	public native void SHM0011getData(byte[] outByte);

	/**
	 * <DL>
	 * <DT>業務APが共有メモリアクセスAPI（本API）を使用する入口。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（Map<String, String[]>）
	 */
	public static Map<String, String[]> getTableData(String TableName, String Key, Map<String, String> in) {
		// 共有メモリモード判定（0:共有メモリからデータ取得、1:ファイルからデータ取得）
		if (sharedMode == 0) {
			return (getSharedMemory(TableName, Key, in));
		}
		else {
			return (getFileData(TableName, Key, in));
		}
	}

	/**
	 * <DL>
	 * <DT>業務APが共有メモリアクセスAPI（本API）を使用する入口。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（List<Map<String,String>>）
	 */
	public static List<Map<String, String>> getTableDataList(String TableName, String Key, Map<String, String> in) {
		// 共有メモリモード判定（0:共有メモリからデータ取得、1:ファイルからデータ取得）
		if (sharedMode == 0) {
			return (getSharedMemoryList (TableName, Key, in));
		}
		else {
			return ((List<Map<String, String>>)null);
		}
	}

	/**
	 * <DL>
	 * <DT>共有メモリモード値の返却。static メソッドとして利用
	 * <DD>0:共有メモリからデータ取得、1:ファイルからデータ取得
	 * </DL>
	 * 
	 */
	private static synchronized void getMode() {

		// 環境変数（GG_SHAREDMODE）の値により判断
		String envWork = System.getenv("GG_SHAREDMODE");
		if (envWork == null) {
			return;
		}
		try {
			sharedMode = Integer.valueOf(envWork);
		} catch (NumberFormatException ne) {
			sharedMode = 1;
		}

		// 共有メモリモードが「1:ファイルからデータ取得」だった場合
		if (sharedMode == 1) {
			envWork = System.getenv("GG_TBLDEF");
			if (envWork == null) {
				sharedMode = 0;
			}
			else {
				TableDefineFile = envWork.substring(0);
				if ((new File(TableDefineFile)).exists() == true) {
					List<String> DFData = fileLoad(TableDefineFile);
					MngTblDef(DFData);
					DFModifiedTime = (new File(TableDefineFile)).lastModified();
				}
				else {
					sharedMode = 0;
				}
			}
		}
	}

	/**
	 * <DL>
	 * <DT>共有メモリアクセス処理。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（Map<String, String[]>）
	 */
	private static Map<String, String[]> getSharedMemory(String TableName, String Key, Map<String, String> in) {

		String outSt = callCApplication ( TableName , Key , in ) ;
		if ( outSt == null ) {
			return ( (Map<String, String[]>)null ) ;
		}
		String[] outParm = outSt.split(BREAK_CODE);
		String[] outColumn = outParm[0].split(TAB_CODE);
		String[][] outArray = trimColumnData ( outColumn.length , outParm ) ;

		Map<String, String[]> out = new HashMap<String, String[]>();
		for (int j = 0; j < outColumn.length; j++) {
			out.put(outColumn[j], outArray[j]);
		}
		return (out);
	}

	/**
	 * <DL>
	 * <DT>共有メモリアクセス処理。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（List<Map<String,String>>）
	 */
	private static List<Map<String, String>> getSharedMemoryList(String TableName, String Key, Map<String, String> in) {

		String outSt = callCApplication ( TableName , Key , in ) ;
		if ( outSt == null ) {
			return ( (List<Map<String, String>>)null ) ;
		}
		String[] outParm = outSt.split(BREAK_CODE);
		String[] outColumn = outParm[0].split(TAB_CODE);
		String[][] outArray = trimColumnData ( outColumn.length , outParm ) ;

		List<Map<String, String>> out = new ArrayList<Map<String, String>>();
		for (int i = 0; i < outArray[0].length; i++) { 
			Map<String, String> outMap = new HashMap<String, String>() ;
			for (int j = 0 ; j < outColumn.length; j++) {
				outMap.put ( outColumn[j] , outArray[j][i] ) ;
			}
			out.add ( outMap ) ;
		}
		return (out);
	}

	/**
	 * <DL>
	 * <DT> C言語API呼び出しおよびJavaデータに変換。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。(String）
	 */
	private static String callCApplication (String TableName, String Key, Map<String, String> in) {

		ShmStaticTable StcTbl = new ShmStaticTable();

		StringBuilder inSt = new StringBuilder(1024);

		inSt.append(TableName);
		inSt.append(BREAK_CODE);
		inSt.append(Key);
		inSt.append(BREAK_CODE);

		if (in != null) {
			Object[] objKey = in.keySet().toArray();

			for (int i = 0; i < objKey.length; i++) {
				inSt.append((objKey[i]).toString());
				inSt.append(BREAK_CODE);
				if (BLANK.equals(in.get(objKey[i].toString()))) {
					inSt.append(SPACE_BREAK_CODE);
				}
				else {
					inSt.append(in.get(objKey[i].toString()));
					inSt.append(BREAK_CODE);
				}
			}
		}
		inSt.append(BREAK_CODE);

		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 共有メモリ検索処理
		// 本処理(StcTbl.SHM0011)では、業務APが設定したパラメータに従って共有
		// メモリ検索を行い、C言語中に検索結果を一時格納し、データサイズを返却
		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

		int dataSize = StcTbl.SHM0011(inSt.toString().getBytes());

		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 検索データ取得処理（返却データ無しの場合） C言語中の内部バッファクリアのために、呼び出しが必要
		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		if (dataSize <= 0) {
			byte[] outBt = new byte[1];
			outBt[0] = CHAR_ZERO;
			StcTbl.SHM0011getData(outBt);
			// 共有メモリ取得エラーの場合
			if (-10 >= dataSize) {
				throw new RuntimeException("共有メモリ取得エラー (" + dataSize + ")");
			}
			return ((String)null);
		}

		byte[] outBt = new byte[dataSize + 1];
		outBt[0] = CHAR_SPACE;

		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
		// 検索データ取得処理
		// 本処理(StcTbl.SHM0011getData)では、前処理(StcTbl.SHM0011)から返却さ
		// れたデータ長のバッファ(outBt)を用意し、そのバッファに検索データを返却
		// する。(バッファ長の圧縮による性能向上が目的)
		// _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

		StcTbl.SHM0011getData(outBt);

		String outSt;
		try {
			outSt = new String(outBt, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			// 文字コード指定しての変換エラーの場合、nullを返却
			return ((String)null);
		}

		return ( outSt ) ;
	}

	/**
	 * <DL>
	 * <DT>データ項目分割・整形（トリム）処理
	 * </DL>
	 * 
	 * @param outParam テーブル（メモリ）から取得したデータの行情報
	 * @return 検索結果を項目毎に分割、および整形（uFFFDデータの削除）して返却
	 */
	private static String[][] trimColumnData( int colLength , String[] outParm ) {

		String[][] outArray = new String[colLength][outParm.length - 2];

		for (int i = 1; i < outParm.length - 1; i++) {
			String[] outData = outParm[i].split(TAB_CODE);
			for (int j = 0; j < colLength ; j++) {
				int k;
				for (k = outData[j].length() - 1; k >= 0; k--) {
					if (outData[j].charAt(k) != '\uFFFD') {
						break;
					}
					/*
					 * if (outData[j].charAt(k) != ' ') { break; }
					 */
				}
				if (k >= 0) {
					outArray[j][i - 1] = outData[j].substring(0, k + 1);
				}
				else {
					outArray[j][i - 1] = BLANK;
				}
			}
		}

		return ( outArray );
	}

	/**
	 * <DL>
	 * <DT>ファイルアクセス処理。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（Map<String, String[]>）
	 */
	private static Map<String, String[]> getFileData(String TableName, String Key, Map<String, String> in) {

		ShmStringArrayList[] retArray = gerReadFile ( TableName , Key , in ) ;
		if ( retArray == null ) {
			return ( (Map<String, String[]>)null ) ;
		}
		String[] outParm = outSt.split(BREAK_CODE);
		String[] outColumn = outParm[0].split(TAB_CODE);
		String[][] outArray = trimColumnData ( outColumn.length , outParm ) ;

		Map<String, String[]> out = new HashMap<String, String[]>();
		for (int j = 0; j < outColumn.length; j++) {
			out.put(outColumn[j], outArray[j]);
		}
		return (out);
		



	}

	/**
	 * <DL>
	 * <DT>ファイルアクセス処理。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param TableName 参照するテーブルの名称を指す識別子を指定。
	 * @param Key 参照するアクセスキー（アクセス方法）を指定。
	 * @param in Keyで指定した検索条件に設定する検索条件の値を設定。
	 * @return 検索結果を返却する領域。（Map<String, String[]>）
	 */
	private static Map<String, String[]> getFileData(String TableName, String Key, Map<String, String> in) {
		// Table.defの最終更新日付をチェックして、現更新日付が新しい場合は再展開
		if (DFModifiedTime < (new File(TableDefineFile)).lastModified()) {
			List<String> DFData = fileLoad(TableDefineFile);
			MngTblDef(DFData);
			DFModifiedTime = (new File(TableDefineFile)).lastModified();
		}

		// 論理テーブル名称（上位APの引数）が、Table.defのレコードに存在するか？
		String[] DFNameData = StaticDataFile.get(TableName);
		if (DFNameData == (String[])null) {
			return ((Map<String, String[]>)null);
		}

		// アクセスパターンファイル（XML）をParse
		ShmXMLList AccessPtnFile = new ShmXMLList(DFNameData[2]);
		String AccessPtnId[] = AccessPtnFile.getValue("/TableAccess/Table/Search/@id");

		// アクセスパターン番号（上位APの引数）が、論理テーブルのパターンに存在するか？
		int AccessPtnNo = 0;
		for (AccessPtnNo = 0; AccessPtnNo < AccessPtnId.length; AccessPtnNo++) {
			if (AccessPtnId[AccessPtnNo].equals(Key) == true) {
				break;
			}
		}

		String[] Left = new String[MAX_COND];
		Integer[] Left_Num = new Integer[MAX_COND];
		String[] Comp = new String[MAX_COND];
		String[] Right = new String[MAX_COND];
		Long[] Right_Num = new Long[MAX_COND];
		String[] Comb = new String[MAX_COND];

		if ("AllDataOutput".equals(Key) == false && "AllDataOutput-back".equals(Key) == false) {

			// 存在しなかったら、null返却
			if (AccessPtnNo == AccessPtnId.length) {
				return ((Map<String, String[]>)null);
			}

			// ShmXMLList.getFrame のパラメータセット
			String wherePrm[] = { "tag", "TableAccess", "tag", "Table", "parm", "id", "pval", "in07?", "", "", "", "", "tag",
					"Search", "parm", "id", "pval", "in17?", "tag", "Define" };
			wherePrm[7] = TableName;
			wherePrm[17] = Key;

			// ShmXMLList.getFrame を使用して、データ取得時のwhere句を取得
			List<String> AccessPtnFrame = AccessPtnFile.getFrame(wherePrm);

			if (AccessPtnFrame == null) {
				return ((Map<String, String[]>)null);
			}

			// 0 件目の配列 5 に、where句の内容が配置されている
			// tag Sentence parm where pval RETU_1 = ? and RETU_2 = ? ←where句
			String where = (AccessPtnFrame.get(0).split(ShmXMLList.SEP_XML))[5];
			String[] wherePart = where.split(SPACE);

			// where句の記述内容を分解。
			// 左辺(Left) / 比較演算子(Comp) / 右辺(Right) / 条件結合子(and/or)
			Comb[0] = "";
			for (int i = 0; i < wherePart.length; i++) {
				if (i % 4 == 0) {
					Left[i / 4] = wherePart[i];
					int Left_Num_Pos = Left[i / 4].indexOf('@');
					if (Left_Num_Pos >= 1) {
						String Left_Real = Left[i / 4].substring(0, Left_Num_Pos);
						Left[i / 4] = Left_Real;
						Left_Num[i / 4] = 1;
					}
					else {
						Left_Num[i / 4] = 0;
					}
				}
				else if (i % 4 == 1) {
					Comp[i / 4] = wherePart[i];
				}
				else if (i % 4 == 2) {
					Right[i / 4] = wherePart[i];
				}
				else if (i % 4 == 3) {
					Comb[i / 4] = wherePart[i];
					if (i / 4 + 1 < MAX_COND) {
						Comb[i / 4 + 1] = BLANK;
					}
				}
			}

			// 右辺の「?」に業務APから指定された値（in Map）を代入
			int line = 1;
			for (int i = 0; i < Right.length; i++) {
				if (QUESTION.equals(Right[i]) == true) {
					// 1 件目以降の配列 5 に、?に埋め込む項目名称が配置されている
					// tag iData parm column pval RETU_1 ←項目名称
					String Col = (AccessPtnFrame.get(line).split(ShmXMLList.SEP_XML))[5];
					if (in == null || 0 == in.size()) {
						return ((Map<String, String[]>)null);
					}
					Right[i] = in.get(Col);
					// キーに指定する値がnullの場合、検索結果を0件で返却
					if (Right[i] == null) {
						return ((Map<String, String[]>)null);
					}
					if (Left_Num[i] == 1) {
						try {
							Right_Num[i] = Long.parseLong(Right[i]);
						} catch (Exception e) {
							return ((Map<String, String[]>)null);
						}
					}

					line++;
				}
				if (BLANK.equals(Comb[i]) == true) {
					break;
				}
			}
		}

		int[] LeftPos = new int[MAX_COND];

		// ファイルデータの読込および適合判定処理
		String[] ColName = null;
		ShmStringArrayList[] retArray = null;
		BufferedReader br = null;
		try {
			String envWork = System.getenv("GG_CHARSET");

			if (envWork == null) {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(DFNameData[0])));
			}
			else {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(DFNameData[0]), envWork));
			}
			String inBuf = br.readLine();
			ColName = inBuf.split(TAB_CODE);
			retArray = new ShmStringArrayList[ColName.length];

			if ("AllDataOutput".equals(Key) == false && "AllDataOutput-back".equals(Key) == false) {

				// LeftPos[MAX_COND]の初期化
				for (int j = 0; j == 0 || (j > 0 && BLANK.equals(Comb[j - 1]) == false); j++) {
					LeftPos[j] = -1;
				}

				// 入力ファイルの一行目（ヘッダ情報）から、各カラムの相対位置（0～）をLeftPosにセット
				for (int i = 0; i < ColName.length; i++) {
					retArray[i] = new ShmStringArrayList();
					for (int j = 0; j == 0 || (j > 0 && BLANK.equals(Comb[j - 1]) == false); j++) {
						if (ColName[i].equals(Left[j]) == true) {
							LeftPos[j] = i;
						}
					}
				}

				// 左辺項目(Left)の全項目が、ヘッダ情報のカラム(ColName)に存在するかチェック
				for (int j = 0; j == 0 || (j > 0 && BLANK.equals(Comb[j - 1]) == false); j++) {
					if (LeftPos[j] == -1) {
						System.out.println("パラメータ不正１：Left[" + j + "]=" + Left[j]);
						return ((Map<String, String[]>)null);
					}
				}
				// 入力ファイルの二行目以降（データ部）の判定処理
				for (; (inBuf = br.readLine()) != null;) {

					// タブ区切りの入力データを配列化
					String[] RecData = inBuf.split(TAB_CODE);
					int j;
					for (j = 0; (j == 0 || (j > 0 && BLANK.equals(Comb[j - 1]) == false)); j++) {

						// データ値の比較
						long CompRest = 0;
						if (Left_Num[j] == 0) {
							if (RecData[LeftPos[j]].length() > Right[j].length()) {
								int complen = RecData[LeftPos[j]].length() - 1;
								for (; complen >= Right[j].length(); complen--) {
									if (" ".equals(RecData[LeftPos[j]].substring(complen, complen + 1)) == false)
										break;
								}
								String shmChar = new String(RecData[LeftPos[j]].substring(0, complen + 1));
								CompRest = (long)shmChar.compareTo(Right[j]);
							}
							else if (RecData[LeftPos[j]].length() < Right[j].length()) {
								int complen = Right[j].length() - 1;
								for (; complen >= RecData[LeftPos[j]].length(); complen--) {
									if (" ".equals(Right[j].substring(complen, complen + 1)) == false)
										break;
								}
								String shmChar = new String(Right[j].substring(0, complen + 1));
								CompRest = (long)RecData[LeftPos[j]].compareTo(shmChar);
							}
							else {
								CompRest = (long)RecData[LeftPos[j]].compareTo(Right[j]);
							}
						}
						else {
							long wk_Left_Num = Long.parseLong(RecData[LeftPos[j]]);
							CompRest = wk_Left_Num - Right_Num[j];
							if (CompRest > 0 && (wk_Left_Num < 0 || Right_Num[j] < 0)) {
								// 比較結果がプラスでかつ左辺または右辺の値がマイナスの場合
								// 再比較を行う。
								if (wk_Left_Num == Right_Num[j]) {
									CompRest = 0;
								}
								else if (wk_Left_Num < Right_Num[j]) {
									CompRest = -1;
								}
								else if (wk_Left_Num > Right_Num[j]) {
									CompRest = 1;
								}
							}
						}

						if ((EQUAL.equals(Comp[j]) == true && CompRest == 0)
								|| (MORE_SMALL.equals(Comp[j]) == true && CompRest < 0)
								|| (SMALL_EQUAL.equals(Comp[j]) == true && CompRest <= 0)
								|| (MORE_BIG.equals(Comp[j]) == true && CompRest > 0)
								|| (BIG_EQUAL.equals(Comp[j]) == true && CompRest >= 0)
								|| (NOT_EQUAL.equals(Comp[j]) == true && CompRest != 0)) {
							// 条件結合子(and/or)がない、またはorであれば、本レコードは適合
							// 注 : and と or の混合比較は実装出来ていないため、Combの値(and/or)は
							// 必ず先頭で指定した値Comb[0]で判定する
							if (STR_OR.equals(Comb[0]) == true || BLANK.equals(Comb[j]) == true) {
								for (int h = 0; h < ColName.length; h++) {
									// 返却領域(retArray)にデータをセット。null時は空文字("")を返却
									if (h < RecData.length && RecData[h] != null) {
										retArray[h].add(RecData[h]);
									}
									else {
										retArray[h].add(BLANK);
									}
								}
								break;
								// 条件結合子が(and)の場合は、次の条件判定を継続
							}
							else if (STR_AND.equals(Comb[0]) == true) {
								continue;
							}
						}
						else {
							if (STR_OR.equals(Comb[0]) == true && BLANK.equals(Comb[j]) == false) {
								continue;
							}
							break;
						}
					}
				}
			}
			else {
				for (; (inBuf = br.readLine()) != null;) {
					// タブ区切りの入力データを配列化
					String[] RecData = inBuf.split(TAB_CODE);
					for (int h = 0; h < ColName.length; h++) {
						if (retArray[h] == null) {
							retArray[h] = new ShmStringArrayList();
						}
						// 返却領域(retArray)にデータをセット。null時は空文字("")を返却
						if (h < RecData.length && RecData[h] != null) {
							retArray[h].add(RecData[h]);
						}
						else {
							retArray[h].add(BLANK);
						}
					}
				}
			}
		} catch (FileNotFoundException fe) {
			System.out.println("入力ファイル:" + DFNameData[0] + " が存在しない");
			return ((Map<String, String[]>)null);
		} catch (IOException ie) {
			System.out.println("入力ファイル:" + DFNameData[0] + " アクセスエラー発生");
			return ((Map<String, String[]>)null);
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
				}
			}
		}

		// retArrayから、返却データの設定
		Map<String, String[]> ret = new HashMap<String, String[]>();
		if (retArray[0] != null && retArray[0].isEmpty() == false) {
			String[][] retData = new String[ColName.length][];
			for (int i = 0; i < ColName.length; i++) {
				retData[i] = retArray[i].toArray();
				ret.put(ColName[i], retData[i]);
			}
			return (ret);
		}
		else {
			return ((Map<String, String[]>)null);
		}
	}

	/**
	 * <DL>
	 * <DT>定義ファイル（Table.def）の読込処理。static メソッドとして利用。
	 * </DL>
	 * 
	 * @param in 定義ファイル名称を指定。
	 * @return 定義ファイル内容を返却。（ArrayList）
	 */
	private static synchronized List<String> fileLoad(String in) {

		List<String> outArray = new ArrayList<String>();
		BufferedReader br = null;
		try {
			String envWork = System.getenv("GG_CHARSET");
			if (envWork == null) {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(in)));
			}
			else {
				br = new BufferedReader(new InputStreamReader(new FileInputStream(in), envWork));
			}
			while (true) {
				String inBuf = new String();
				if ((inBuf = br.readLine()) == null) {
					break;
				}
				outArray.add(inBuf);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
				}
			}
		}

		return (outArray);
	}

	/**
	 * <DL>
	 * <DT>定義ファイル（Table.def）の解析処理。static メソッドとして利用。
	 * <DT>定義ファイルを下記の項目に分解し、StaticDataFile(static)に設定。
	 * <DT>テーブルID、テーブル識別名称、テーブル配置先、データファイル名、XMLファイル名称、DBテーブル名称
	 * </DL>
	 * 
	 * @param DFData 定義ファイル読込結果。（List形式）
	 */
	private static synchronized void MngTblDef(List<String> DFData) {

		StaticDataFile.clear();
		for (int i = 0; i < DFData.size(); i++) {
			// コメント行はスキップ
			if (SEMICOLON.equals(DFData.get(i).substring(0, 1)) == true) {
				continue;
			}
			// カンマ区切りでsplit
			String[] DFColumn = DFData.get(i).split(COMMA);
			File WDataF = new File(DFColumn[4]);
			File WPtnF = new File(DFColumn[5]);
			// データファイル、XMLファイルがない場合は、設定しない
			if (WDataF.exists() == false || WPtnF.exists() == false) {
				continue;
			}
			// StaticDataFile(Map)のキー取得
			String TblId = new String(DFColumn[1]);
			String[] MngFile = new String[4];
			// データファイル名称設定
			MngFile[0] = DFColumn[4];
			// データファイルの最終更新日付設定
//			MngFile[1] = (new Long(WDataF.lastModified())).toString();
			MngFile[1] = (Long.valueOf(WDataF.lastModified())).toString();
			// XMLファイル（アクセスパターン定義）名称設定
			MngFile[2] = DFColumn[5];
			// XMLファイル（アクセスパターン定義）の最終更新日付設定
//			MngFile[3] = (new Long(WPtnF.lastModified())).toString();
			MngFile[3] = (Long.valueOf(WPtnF.lastModified())).toString();

			StaticDataFile.put(TblId, MngFile);
		}
	}

}
