/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.resource;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;

import org.opengion.fukurou.system.DateSet;						// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.util.HybsDateUtil;					// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.db.ApplicationInfo;
import org.opengion.fukurou.db.DBUtil;

import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Collections;									// 6.4.3.1 (2016/02/12)

/**
 * ユーザーアクセス画面管理テーブルを維持する為のクラスです。
 * @og.group リソース管理
 *
 * @version  4.1.1.0
 * @author   Sen.Li
 * @since    JDK5.0,
 */
public final class UserAccessTable {
	// 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
	private static final String GEA09_QUERY  = "SELECT GUIKEY,SEQNO,NAME_JA,LAST_ACCESS,FGFAVORITE,CLASSIFY,NEXTGUI FROM GEA09"
									+ " WHERE SYSTEM_ID=? AND USERID=?"
									+ " ORDER BY SEQNO,CLASSIFY,GUIKEY";
	private static final String GEA09_DELETE = "DELETE FROM GEA09"
									+ " WHERE SYSTEM_ID=? AND USERID=? AND GUIKEY=?";
	private static final String GEA09_INSERT = "INSERT INTO GEA09(SYSTEM_ID,USERID,GUIKEY,SEQNO,NAME_JA,CLASSIFY,FGJ"
									+ ",DYSET,USRSET,PGUPD) VALUES(?,?,?,?,?,?,?,?,?,?)";
	// 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
	private static final String GEA09_UPDATE = "UPDATE GEA09 SET LAST_ACCESS=?,NEXTGUI=?"
									+ " WHERE SYSTEM_ID=? AND USERID=? AND GUIKEY=?";

	private static final String DBID = HybsSystem.sys( "RESOURCE_DBID" );
	private static final int GEA09_GUIKEY		= 0;
	private static final int GEA09_SEQNO		= 1;
	private static final int GEA09_NAME_JA		= 2;
	private static final int GEA09_LAST_ACCESS	= 3;
	private static final int GEA09_FGFAVORITE	= 4;
	private static final int GEA09_CLASSIFY		= 5;
	private static final int GEA09_NEXTGUI		= 6;	// 5.3.0.0 (2010/12/01) 追加
	private static final String  FGFAVORITE_ON	= "1";

	/** フラグキーの enum */
	private static enum FgKeys { GUIMAP_ONLY,GEA09_ONLY };

	/**
	 * コンストラクター
	 * オブジェクトを作成できないように、privateにします。
	 *
	 * @og.rev 4.3.1.1 (2008/08/23) コンストラクタは、void 宣言を付けません。
	 */
	private UserAccessTable() { }

	/**
	 * ユーザーアクセス画面管理テーブルを整理します。
	 * このメソッドでは guiMap へのセットをしています(副作用の扱い)。
	 *
	 * @og.rev 4.1.1.0 (2008/01/30) 新規追加
	 * @og.rev 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
	 * @og.rev 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.entrySet() を使う様に変更。
	 * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
	 * @og.rev 6.4.2.0 (2016/01/29) HybsDateUtil.getDatePlus( String,int ) を直接利用するように修正します。
	 * @og.rev 6.4.3.1 (2016/02/12) Collections.unmodifiableMap( Map&lt;? extends K,? extends V&gt; ) で作成された変更不可のMapを返します。
	 * @og.rev 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
	 *
	 * @param  guiMap		画面オブジェクトマップへの参照
	 * @param  systemId		システムID
	 * @param  userId		ユーザーID
	 * @param  lang			言語
	 *
	 * @return	お気に入りマップ(Collections.unmodifiableMapされた書き換え不可のMap)
	 */
	public static Map<String,FavoriteGUIData> makeAccessDB(
							final Map<String,GUIInfo> guiMap,final String systemId,final String userId,final String lang ) {
		final String today			= DateSet.getDate( "yyyyMMddHHmmss" );				// 6.4.2.0 (2016/01/29)
		final Map<String,FgKeys>	fgKeyMap = new HashMap<>();
		/** コネクションにアプリケーション情報を追記するかどうか指定 */
		final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
		ApplicationInfo appInfo = null;
		if( USE_DB_APPLICATION_INFO ) {
			appInfo = new ApplicationInfo();
			// ユーザーID,IPアドレス,ホスト名
			appInfo.setClientInfo( systemId,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
			// 画面ID,操作,プログラムID
			appInfo.setModuleInfo( "UserAccessTable",userId,"makeAccessDB" );
		}

		// guiMapのキーで、新マップを作成、
		// 6.4.3.4 (2016/03/11) forループを、forEach メソッドに置き換えます。
		guiMap.keySet().forEach( k -> fgKeyMap.put( k,FgKeys.GUIMAP_ONLY ) );

		final Map<String,FavoriteGUIData> favoriteGuiMap = new LinkedHashMap<>();
		// 4.1.1.0(2008/01/22)ユーザーアクセスの日付を取得し、accessPastDays 前の日付を計算する。
		final String accessPastDays	= HybsSystem.sys( "ACCESS_TOKEI_PAST_DAYS" );
		final int    diffDate			= ( accessPastDays == null ) ? 0 : -Integer.parseInt( accessPastDays );
		final String judgeTime		= HybsDateUtil.getDatePlus( today.substring( 0,8 ),diffDate );			// 6.4.2.0 (2016/01/29)
		String lastAccessTime	= null;
		String key 				= null;
		String[]   args			= new String[] { systemId,userId };
		final String[][] vals			= DBUtil.dbExecute( GEA09_QUERY,args,appInfo,DBID );
		final int len					= vals.length;

		for( int i=0; i<len; i++ ) {
			key = vals[i][GEA09_GUIKEY];
			final GUIInfo gui = guiMap.get( key );
			if( gui == null ) {
				fgKeyMap.put( key,FgKeys.GEA09_ONLY );
			}
			else {
				// 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
				final String nxtgui = vals[i][GEA09_NEXTGUI];
				if( nxtgui != null ) {
					final String[] keys = nxtgui.split( "," );
					for( final String nextKey : keys ) {
						gui.setNextGuiKey( nextKey );		// DB から復活
					}
				}

				fgKeyMap.remove( key );
				// 4.1.1.0(2008/01/22)お気に入りマップの作成
				if( FGFAVORITE_ON.equals( vals[i][GEA09_FGFAVORITE] ) && gui.isRead() ) {
					favoriteGuiMap.put( key,new FavoriteGUIData( vals[i][GEA09_GUIKEY],vals[i][GEA09_SEQNO]
						,vals[i][GEA09_NAME_JA],vals[i][GEA09_CLASSIFY] ) );
				}
				// 4.1.1.0(2008/01/22)ACCESS_TOKEI_PAST_DAYSに定義された期間以内の画面を格上する。
				lastAccessTime = vals[i][GEA09_LAST_ACCESS];
				// 6.0.0.1 (2014/04/25) These nested if statements could be combined
				if( lastAccessTime.length() >= 8 && lastAccessTime.compareTo( judgeTime ) >=0 ) {
					gui.setLevelUp();
				}
			}
		}

		final ResourceManager resource = ResourceFactory.newInstance( lang );
		final String undefined = resource.getLabel( "UNDEFINED" );
		// 6.3.9.0 (2015/11/06) Map.keySet() ではなく、Map.entrySet() を使う様に変更。
		for( final Map.Entry<String,FgKeys> entry : fgKeyMap.entrySet() ) {
			final String conKey = entry.getKey();
			final FgKeys fgKey  = entry.getValue();
			switch ( fgKey ) {
				case GUIMAP_ONLY:
					args = new String[] { systemId,userId,conKey,"9999999",guiMap.get(conKey).getLabel()
										  ,undefined,"1",today,userId,"UsrAccsTbl" };
	                DBUtil.dbExecute( GEA09_INSERT,args,appInfo,DBID );
					break;
				case GEA09_ONLY:
					args = new String[] { systemId,userId,conKey };
					DBUtil.dbExecute( GEA09_DELETE,args,appInfo,DBID );
					break;
				default:
					final String errMsg = "guiMapとGEA09の突合せフラグが GUIMAP_ONLY と GEA09_ONLY 以外の値がセットされています。"
								  + "画面ID：" + conKey + " フラグ：" + fgKey;
					throw new HybsSystemException( errMsg );
			}
		}

		return Collections.unmodifiableMap( favoriteGuiMap );		// 6.4.3.1 (2016/02/12)
	}

	/**
	 * ユーザーアクセス画面管理テーブルの最終アクセス時間を更新します。
	 *
	 * @og.rev 4.1.1.0 (2008/01/30) 新規追加
	 * @og.rev 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
	 * @og.rev 6.8.4.2 (2017/12/25) nextGuiKeys(NEXTGUI)が、1000Byteのため、文字数制限しておきます。
	 *
	 * @param systemId			システムID
	 * @param userId			ユーザーID
	 * @param guiKey			画面ID
	 * @param lastAccessTime	画面の最終アクセス時間
	 * @param nextGuiKeys		次にアクセスしている画面IDのCSV文字列
	 */
	public static void updateLastAccessTime( final String systemId,final String userId,final String guiKey,final String lastAccessTime,final String nextGuiKeys ) {
		/** コネクションにアプリケーション情報を追記するかどうか指定 */
		final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
		ApplicationInfo appInfo = null;
		if( USE_DB_APPLICATION_INFO ) {
			appInfo = new ApplicationInfo();
			// ユーザーID,IPアドレス,ホスト名
			appInfo.setClientInfo( systemId,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
			// 画面ID,操作,プログラムID
			appInfo.setModuleInfo( "UserAccessTable",userId,"updateLastAccessTime" );
		}

		// 6.8.4.2 (2017/12/25) nextGuiKeys(NEXTGUI)が、1000Byteのため、文字数制限しておきます。
		final String nextGui = nextGuiKeys != null && nextGuiKeys.length() > 1000 ? nextGuiKeys.substring( 0,1000 ) : nextGuiKeys ;

		// 5.3.0.0 (2010/12/01) 画面アクセスの履歴(順番)を管理する機能を追加
		final String[] args = new String[] { lastAccessTime,nextGui,systemId,userId,guiKey };	// 6.8.4.2 (2017/12/25)
		DBUtil.dbExecute( GEA09_UPDATE,args,appInfo,DBID );
	}
}
