/*
 * 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.db;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

/**
 * ユーザー単位のエディット設定情報を管理するためのクラスです。
 *
 * 画面ID+エディット名をキーとしてエディット設定オブジェクトの
 * 追加、削除、参照を行います。
 *
 * @og.rev 5.3.6.0 (2011/06/01) 新規追加
 *
 * @version  5.0
 * @author   Hiroki Nakamura
 * @since    JDK6.0,
 */
public class DBEditConfigManager {

	// エディット設定情報の管理オブジェクト(画面ID+エディット名単位で管理)
	private final Map<String,Map<String,DBEditConfig>> editConfigMap = new HashMap<String,Map<String,DBEditConfig>>();

	/**
	 * デフォルトコンストラクター
	 *
	 * 互換性を考慮し、デフォルトコンストラクターは残しておきます。
	 *
	 * @og.rev 6.0.2.2 (2014/10/03) 新規追加
	 */
	public DBEditConfigManager() {}

	/**
	 * 引数付コンストラクター
	 *
	 * UserInfo の Map<String,String> attribute から、EDIT_NAME_ で始まるキーワードを
	 * 取り出して、DBEditConfig オブジェクトを作成します。
	 * attribute には、"EDIT_NAME_(画面ID)_(エディット名)" というキー情報があるので、
	 * 画面IDとエディット名を分離し、DBEditConfig の各キーと再び合成して、attribute から、
	 * 設定値を取り出します。
	 * ただし、画面IDや、エディット名 にも、アンダーバーが含まれている可能性がある為、
	 * EDIT_NAME_(画面ID)_(エディット名) の値である、エディット名 を使用して、分離します。
	 * そのキーと値の配列を元に作成された DBEditConfig オブジェクトを、内部Map に画面IDを
	 * キーに設定します。
	 *
	 * 元々、UserInfo#makeEditConfigMap() で処理していた内容を、こちらに移植しました。
	 *
	 * @og.rev 6.0.2.2 (2014/10/03) 新規追加。DBEditConfig から、移動
	 *
	 * @param attribute  UserInfo の 属性Map
	 */
	public DBEditConfigManager( final Map<String,String> attribute ) {
		String[] keys = attribute.keySet().toArray( new String[attribute.size()] );
		if( keys == null || keys.length == 0 ) { return ; }

		final int KEYLEN = "EDIT_NAME_".length();

		for( String key : keys ) {
			if ( key != null && key.startsWith( "EDIT_NAME_" ) ) {
				String editName = attribute.get( key );
				if( editName == null || editName.isEmpty() ) {
					attribute.remove( key );		// editName の存在しない EDIT_NAME_ キーは削除します。
					continue;
				}

				// "EDIT_NAME_" より後ろで、editName の頭までが、画面ID
				// (ただし、後ろにアンダーバーが付いているので、さらに、1文字削除対象を増やす。)
				int last = key.lastIndexOf(editName)-1 ;
				if( last < 0 ) {					// 一致しない場合は、キーが違うから。
					attribute.remove( key );		// editName の一致しない EDIT_NAME_ キーは削除します。
					continue;
				}

				String guikey = key.substring( KEYLEN,last );
				if( guikey != null && guikey.length() > 0 ) {
					String[] editKeys = getEditKeys( guikey, editName );
					String[] editVals = new String[editKeys.length];
					for( int i=0; i<editKeys.length; i++ ) {
						editVals[i] = attribute.get( editKeys[i] );
					}
					addEditConfig( guikey, editName, new DBEditConfig( editVals ) );
				}
			}
		}
	}

	/**
	 * 画面ID、エディット名をキーに、エディット設定オブジェクトの各設定値の
	 * 管理キーを指定します。
	 *
	 * エディット設定オブジェクトで管理される各キーに対して、
	 * "EDIT_[KEY]_(画面ID)__(エディット名)"というキーを生成し、これを配列にして返します。
	 *
	 * @og.rev 6.0.2.2 (2014/10/03) 新規追加。DBEditConfig から、移動
	 *
	 * @param guikey 画面ID
	 * @param editName エディット名
	 *
	 * @return エディット設定を管理するためのキー一覧
	 */
	public static String[] getEditKeys( final String guikey, final String editName ) {
		int size = DBEditConfig.EDIT_KEYS.length;
		String[] rtn = new String[size];
		for( int i=0; i<size; i++ ) {
			rtn[i] = "EDIT_" + DBEditConfig.EDIT_KEYS[i] + "_" + guikey + "_" + editName;
		}
		return rtn;
	}

	/**
	 * エディット設定オブジェクトを追加します。
	 *
	 * ここでの追加はあくまでメモリ上での登録になります。
	 * 登録した内容を永続的に登録する場合は、別途DBへの登録が必要になります。
	 *
	 * @param guikey 画面ID
	 * @param editName エディット名
	 * @param config エディット設定オブジェクト
	 */
	public void addEditConfig( final String guikey, final String editName, final DBEditConfig config ) {
		if( guikey   == null || guikey.isEmpty()   ) { return; }
		if( editName == null || editName.isEmpty() ) { return; }
		if( config   == null ) { return; }

		synchronized( editConfigMap ) {
			Map<String,DBEditConfig> map = editConfigMap.get( guikey );
			if( map == null ) {
				map = new HashMap<String, DBEditConfig>();
			}
			map.put( editName, config );

			editConfigMap.put( guikey, map );
		}
	}

	/**
	 * エディット設定オブジェクトを削除します。
	 *
	 * ここでの追加はあくまでメモリ上での削除になります。
	 * 登録した内容を永続的に削除する場合は、別途DBへの登録が必要になります。
	 *
	 * @param guikey 画面ID
	 * @param editName エディット名
	 *
	 * @return エディット設定オブジェクト
	 */
	public DBEditConfig deleteEditConfig( final String guikey, final String editName ) {
		if( guikey   == null || guikey.isEmpty()   ) { return null; }
		if( editName == null || editName.isEmpty() ) { return null; }

		DBEditConfig config = null;
		synchronized( editConfigMap ) {
			Map<String,DBEditConfig> map = editConfigMap.get( guikey );
			if( map == null ) { return null; }
			config = map.remove( editName );
			editConfigMap.put( guikey, map );
		}
		return config;
	}

	/**
	 * エディット設定オブジェクトを取得します。
	 *
	 * @param guikey 画面ID
	 * @param editName エディット名
	 *
	 * @return エディット設定オブジェクト
	 */
	public DBEditConfig getEditConfig( final String guikey, final String editName ) {
		if( guikey   == null || guikey.isEmpty()   ) { return null; }
		if( editName == null || editName.isEmpty() ) { return null; }

		synchronized( editConfigMap ) {
			Map<String,DBEditConfig> map = editConfigMap.get( guikey );
			if( map == null ) { return null; }
			return map.get( editName );
		}
	}

	/**
	 * 画面IDをキーにエディット設定の一覧(配列)を返します。
	 * 返される配列は、エディット名順にソートされた状態で返されます。
	 *
	 * @param guikey 画面ID
	 *
	 * @return エディット設定一覧(配列)
	 */
	public DBEditConfig[] getEditConfigs( final String guikey ) {
		if( guikey == null || guikey.isEmpty() ) { return null; }

		Map<String,DBEditConfig> map = editConfigMap.get( guikey );
		if( map == null ) { return null; }

		DBEditConfig[] configs = map.values().toArray( new DBEditConfig[0] );
		Arrays.sort( configs
				, new Comparator<DBEditConfig> (){
					public int compare( final DBEditConfig c1, final DBEditConfig c2 ) {
						return c1 == null ? -1 : c1.getEditName().compareTo( c2.getEditName() ) ;
					}
				}
		);

		return configs;
	}
}
