/*********************************************************************
* All Rights reserved,Copyright (c) K-Opticom
**********************************************************************
*＜プログラム内容＞
*   システム名      ：eo顧客基幹システム
*   モジュール名    ：物流管理システム
*   ソースファイル名：JDKUtilCommon.java
*   作成者          ：富士通
*   日付            ：2011年06月03日
*＜機能概要＞
*   物流管理システムの共通処理クラスです。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/06/03   FJ          新規作成
*  v57.00.00    2022/03/14   FK)三原     【OM-2022-0000252】在庫出荷完了一覧照会の画面遷移が遅い
*
**********************************************************************/
package eo.common.util;

import java.sql.PreparedStatement;
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.CAANJDBCUtil;
import com.fujitsu.futurity.model.base.CAANMsg;


/**
 * 物流システム共通処理
 *
 */
public class JDKCommonUtil extends JPCUtilCommon
{
	
	/**
	 * オブジェクトに値が設定されているか判定します。
	 * <br>
	 * @param test 判定するオブジェクト
	 * @return オブジェクトに値が設定されていない場合はtrue
	 */
	public static boolean isNull(Object test)
	{
		return JPCCommonUtil.isNull(test);
	}
	

	/**
	 * 有効なパラメータか判定します。
	 * 文字列に値が設定されていない場合はエラーとします。
	 * <br>
	 * @param test 判定するオブジェクト
	 * @return パラメータが不正な場合はfalse
	 */
	public static boolean isValidParameter(Object test) 
	{
		return JPCCommonUtil.isValidParameter(test);
	}

	
	/**
	 * 有効なパラメータか判定します。
	 * 文字列に値が設定されていない場合、及び指定された桁数と
	 * 一致しない場合はエラーとします。
	 * <br>
	 * @param test 判定する文字列
	 * @param level 文字列として有効な桁数
	 * @return パラメータが不正な場合はfalse
	 */
	public static boolean isValidParameter(String test, int level) 
	{
		return JPCCommonUtil.isValidParameter(test, level);
	}
	
	
	/**
	 * 件数取得用のSQLを生成します。
	 * @param innerSql 元のSQL
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForCount(String innerSql)
	{
		return makeSqlForCount(innerSql, "CNT");
	}

	/**
	 * 件数取得用のSQLを生成します。
	 * @param innerSql 元のSQL
	 * @param countAlias カウンタのエイリアス
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForCount(String innerSql, String countAlias)
	{
		StringBuffer sql = new StringBuffer();
		
		sql.append(String.format("SELECT COUNT(*) %s FROM (", countAlias))
			.append(innerSql)
			.append(")");
		
		return sql.toString();
	}
	
	// OM-2022-0000252 ADD START
	/**
	 * 件数取得用のSQLを生成します。(ヒント句：NO_PARALLEL)
	 * @param innerSql 元のSQL
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForCountNoParallel(String innerSql)
	{
		return makeSqlForCountNoParallel(innerSql, "CNT");
	}
	
	/**
	 * 件数取得用のSQLを生成します。(ヒント句：NO_PARALLEL)
	 * @param innerSql 元のSQL
	 * @param countAlias カウンタのエイリアス
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForCountNoParallel(String innerSql, String countAlias)
	{
		StringBuffer sql = new StringBuffer();
		
		sql.append(String.format("SELECT /*+ NO_PARALLEL */ COUNT(*) %s FROM (", countAlias))
			.append(innerSql)
			.append(")");
		
		return sql.toString();
	}
	// OM-2022-0000252 ADD END
	
	/**
	 * 範囲検索用のSQLを生成します。
	 * @param innersql 元のSQL
	 * @param columnPrefix 取得対象カラムのプリフィックス
	 * @param rowNumAlias rownumのエイリアス
	 * @return 件数制限取得用のＳＱＬ
	 */
	public static String makeSqlForRealm(String innersql, String columnPrefix, String rowNumAlias)
	{
		StringBuffer sql = new StringBuffer();
		String prefix = columnPrefix.toUpperCase();
		
		String[] sqlFragments = innersql.split(" ");
		List<String> selections = new ArrayList<String>();
		for (String sqlFragment : sqlFragments)
		{
			if (!sqlFragment.toUpperCase().startsWith(prefix + "_"))
			{
				continue;
			}
			
			selections.add(chompForSqlSelection(sqlFragment));
		}
		
		String tableName = "TAB_ORGSQL";
		StringBuffer selection = new StringBuffer();
		boolean first = true;
		for (String col : selections)
		{
			if (!first)
			{
				selection.append(",");
			}

			String realColumnName = col.substring(prefix.length() + 1, col.length());
			selection.append(String.format("%s.%s %s", tableName, col, realColumnName));
			first = false;
		}
		
		sql.append("SELECT ")
			.append(selection.toString())
			.append(String.format(" FROM ( SELECT %s_INNER.*, rownum %s FROM (", tableName, rowNumAlias))
			.append(innersql)
			.append(") TAB_ORGSQL_INNER ) ")
			.append(tableName)
			.append(" WHERE")
			.append(String.format(" %s.%s BETWEEN ? AND ?", tableName, rowNumAlias));
		
		return sql.toString();
	}
	
	/**
	 * 英数字、＿の以外の文字を削除します。
	 * @param str 文字列
	 * @return strから英数字と＿のみを選択したもの
	 */
	private static String chompForSqlSelection(String str)
	{
		StringBuffer sb = new StringBuffer();
		
		for (char c : str.toCharArray())
		{
			if (Character.isLetter(c)
				|| Character.isDigit(c)
				|| c == '_')
			{
				sb.append(c);
			}
		}
		
		return sb.toString();
	}

	/**
	 * inMgsのkeyに何か値があればsqlにwhereを追加します。
	 * @param key キー
	 * @param where where句
	 * @param inMsg インプットデータ
	 * @param sql SQL
	 * @param andConnection AND 句をレンダリングするかどうか
	 */
	public static void appendSqlIfAnyInput(String key, String where, CAANMsg inMsg, StringBuffer sql, boolean andConnection)
	{
		if (inMsg.isNull(key))
		{
			return ;
		}
		String andStatement = andConnection ? "AND" : "";
		sql.append(String.format(" %s %s ", andStatement, where));
	}

	/**
	 * inMgsのkeyに何か値があればsqlにwhereを追加します。
	 * @param key キー
	 * @param where where句
	 * @param inMsg インプットデータ
	 * @param sql SQL
	 */
	public static void appendSqlIfAnyInput(String key, String where, CAANMsg inMsg, StringBuffer sql)
	{
		appendSqlIfAnyInput(key, where, inMsg, sql, true);
	}
	
	/**
	 * inMgsのkeyに値があり、期待値と同じであればsqlにwhereを追加します。
	 * @param key キー
	 * @param expect 期待値
	 * @param where where句
	 * @param inMsg インプットデータ
	 * @param sql SQL
	 */
	public static void appendSqlIfInputEq(String key, String expect, String where, CAANMsg inMsg, StringBuffer sql)
	{
		if (inMsg.isNull(key))
		{
			return ;
		}
		
		if (!inMsg.getObject(key).toString().equals(expect))
		{
			return;
		}
		
		appendSqlIfAnyInput(key, where, inMsg, sql, true);
	}

	
	/**
	 * inMsgのkeyに何らかの値があればstatementのindex番目に当該値を設定します。
	 * 値の設定に成功すると、次のインデックス値を返します。
	 * @param key キー
	 * @param index インデックス
	 * @param inMsg インプットデータ
	 * @param statement ステートメント
	 * @return 次のインデックス
	 * @throws SQLException 例外発生時
	 */
	public static int appendParamIfAnyInput(String key, int index, CAANMsg inMsg, PreparedStatement statement) throws SQLException
	{
		if (inMsg.isNull(key))
		{
			return index;
		}
		
		String param = inMsg.getString(key);
		CAANJDBCUtil.setParam(statement, index, param);
		return index + 1;
	}
	


	/**
	 * 指定された文字列の配列をseparatorで結合します。
	 * @param separator 結合文字列
	 * @param strs 結合する文字列
	 * @return 結合された文字列
	 */
	public static String join(String separator, List<String> strs)
	{
		if (isNull(strs))
		{
			return "";
		}
		return srroundedJoin(separator, "", strs.toArray(new String [strs.size()]));
	}
	
	/**
	 * 指定された文字列の配列をseparatorで結合します。
	 * @param separator 結合文字列
	 * @param strs 結合する文字列
	 * @return 結合された文字列
	 */
	public static String join(String separator, String...strs)
	{
		return srroundedJoin(separator, "", strs);
	}	
	
	/**
	 * 指定された文字列の配列をseparatorで結合します。
	 * @param separator 結合文字列
	 * @param strs 結合する文字列
	 * @return 結合された文字列
	 */
	public static String srroundedJoin(String separator, String srround, String...strs)
	{
		if (isNull(strs))
		{
			return "";
		}
		
		StringBuffer sb = new StringBuffer();
		
		boolean isFirst = true;
		for (String str : strs)
		{
			if (!isFirst)
			{
				sb.append(separator);
			}
			
			sb.append(String.format("%s%s%s", srround, str, srround));
			isFirst = false;
		}
		
		return sb.toString();
	}
	
	
	/**
	 * メーカー棚の一覧
	 */
	private static final Map<String, String> MAKER_SHELFS = new HashMap<String, String>();
	static {
		MAKER_SHELFS.put("DA", "MDA");
		MAKER_SHELFS.put("FA", "MFA");
		MAKER_SHELFS.put("HC", "MHC");
		MAKER_SHELFS.put("HO", "MHO");
		MAKER_SHELFS.put("IO", "MIO");
		MAKER_SHELFS.put("JR", "MJR");
		MAKER_SHELFS.put("MC", "MMC");
		MAKER_SHELFS.put("ME", "MME");
		MAKER_SHELFS.put("NA", "MNA");
		MAKER_SHELFS.put("NE", "MNE");
		MAKER_SHELFS.put("NS", "MNS");
		MAKER_SHELFS.put("PI", "MPI");
		MAKER_SHELFS.put("SD", "MSD");
		MAKER_SHELFS.put("SE", "MSE");
		MAKER_SHELFS.put("SS", "MSS");
		MAKER_SHELFS.put("XM", "MXM");
	}
	/**
	 * メーカー棚を取得します
	 */
	public static String getShelfOf(String maker) 
	{
		return MAKER_SHELFS.get(maker);
	}
	

	/**
	 * 最後の項目が空白でも正しく文字列分割する
	 * @param line 分割対象
	 * @param sepalator 分割文字(１文字目を使用）
	 * @return 分割された文字列配列
	 */
	public static String[] splitAnycase(String line, String sepalator)
	{
		if (JDKCommonUtil.isNull(sepalator))
		{
			return new String [] {line};
		}
		return splitAnycase(line, sepalator.toCharArray()[0]);
	}
	
	/**
	 * 最後の項目が空白でも正しく文字列分割する
	 * @param line 分割対象
	 * @param sepalator 分割文字
	 * @return 分割された文字列配列
	 */
	public static String[] splitAnycase(String line, Character sepalator)
		{
		if (line == null)
		{
			return new String [0];
		}
		
		boolean finWithEmpty = line.endsWith(sepalator.toString());
		if (finWithEmpty)
		{
			Character tmpTerminator = '|';
			if (sepalator.equals(tmpTerminator))
			{
				tmpTerminator = '_';
			}
			line = line + tmpTerminator;
		}
		
		String[] lines = line.split(sepalator.toString());
		
		if (finWithEmpty)
		{
			lines[lines.length - 1] = "";
		}
		
		return lines;
	}
	
	/**
	 * 件数制限用のSQLを生成します。
	 * @param inMsg
	 * @param maxSerch
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForRownum(CAANMsg inMsg, String maxSerch)
	{
		int maxSerchNum = Integer.parseInt(inMsg.getString(maxSerch)) + 1; 
		return makeSqlForRownum(String.valueOf(maxSerchNum));
	}

	/**
	 * 件数制限用のSQLを生成を生成します。
	 * @param rownumAlias カウンタのエイリアス
	 * @return 件数取得用SQL
	 */
	public static String makeSqlForRownum(String rownumAlias)
	{
		StringBuffer sql = new StringBuffer();
		sql.append(String.format("AND ROWNUM <= %s", rownumAlias));
		
		return sql.toString();
	}
}
