/*
 * Copyright (c) 2003, Morpho Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the Morpho Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package jp.morpho.util;

import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * <P>
 * PrimitiveHolderMap の実装です。
 * プリミティブ型の値をマッピングすることができます。
 * この実装は、マッピングされた数値を文字列へ変換したり、文字列を数値へ変換します。
 * 例えば、次のように数値を格納後、文字列として取り出すことができます。
 * <PRE>
 *     map.putInt("someKey", 999);
 *     String value = map.getString("someKey");
 * </PRE>
 * 文字列を格納後、数値として取り出すこともできます。
 * <PRE>
 *     map.putString("someKey", "999");
 *     int value = map.getInt("someKey");
 * </PRE>
 * 日付文字列を格納後、java.util.Date として取り出すこともできます。
 * <PRE>
 *     map.putString("someKey", "2003/04/01");
 *     java.util.Date value = map.getDate("someKey");
 * </PRE>
 * </P>
 * <P>
 * このような値の変換機能は、Web ページからフォームデータを文字列で受け取るような Web アプリケーションでは、特に有効です。
 * </P>
 * <P>
 * この実装は、値が関連付けられるキーが String の場合、大文字／小文字を区別しません。
 * キーが String の場合、すべて小文字に変換されます。
 * </P>
 * @author Kenichi Fukuda
 */
public class ConversionMap
	extends MapWrapper
	implements PrimitiveHolderMap, Serializable
{
	//null の String 型の値
	private static final String NULL_STRING = "";

	/**
	 * <P>
	 * 指定のマップをラップする ConversionMap を構築します。
	 * </P>
	 * @param map ラップされるマップ
	 * @exception IllegalArgumentException マップが null の場合
	 */
	public ConversionMap(java.util.Map map)
	{
		super(map);
	}

	/**
	 * <P>
	 * ConversionMap を構築します。
	 * HashMap をラップする新しい ConversionMap を構築します。
	 * </P>
	 */
	public ConversionMap()
	{
		super(new HashMap());
	}

	private Object getKey(Object key)
	{
		if (key instanceof String)
		{
			return ((String)key).toLowerCase();
		}
		return key;
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を入力ストリームとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getInputStream(Object)
	 */
	public synchronized InputStream getInputStream(Object key)
	{
		return (InputStream)get(key);
	}

	/**
	 * <P>
	 * 指定の入力ストリームをマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putInputStream(Object, InputStream)
	 */
	public synchronized void putInputStream(Object key, InputStream value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.math.BigDecimal オブジェクトとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getBigDecimal(Object)
	 */
	public synchronized BigDecimal getBigDecimal(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return null;
		}

		if (obj instanceof BigDecimal)
		{
			return (BigDecimal)obj;
		}
		else if (obj.toString().trim().length() > 0)
		{
			return new BigDecimal(obj.toString());
		}

		return null;
	}

	/**
	 * <P>
	 * 指定の java.math.BigDecimal オブジェクトをマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putBigDecimal(Object, BigDecimal)
	 */
	public synchronized void putBigDecimal(Object key, BigDecimal value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.math.BigInteger オブジェクトとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getBigInteger(Object)
	 */
	public synchronized BigInteger getBigInteger(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return null;
		}

		if (obj instanceof BigInteger)
		{
			return (BigInteger)obj;
		}
		else if (obj.toString().trim().length() > 0)
		{
			return new BigInteger(obj.toString());
		}

		return null;
	}

	/**
	 * <P>
	 * 指定の java.math.BigInteger オブジェクトをマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putBigInteger(Object, BigInteger)
	 */
	public synchronized void putBigInteger(Object key, BigInteger value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の boolean として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getBoolean(Object)
	 */
	public synchronized boolean getBoolean(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return false;
		}

		if (obj instanceof Boolean)
		{
			return ((Boolean)obj).booleanValue();
		}
		else
		{
			return Boolean.valueOf(obj.toString()).booleanValue();
		}
	}

	/**
	 * <P>
	 * 指定の boolean 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putBoolean(Object, boolean)
	 */
	public synchronized void putBoolean(Object key, boolean value)
	{
		put(key, new Boolean(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の byte として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getByte(Object)
	 */
	public synchronized byte getByte(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Byte)
		{
			return ((Byte)obj).byteValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Byte.valueOf(obj.toString()).byteValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の byte 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putByte(Object, byte)
	 */
	public synchronized void putByte(Object key, byte value)
	{
		put(key, new Byte(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の byte 配列として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getBytes(Object)
	 */
	public synchronized byte[] getBytes(Object key)
	{
		return (byte[])get(key);
	}

	/**
	 * <P>
	 * 指定の byte 配列をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putBytes(Object, byte[])
	 */
	public synchronized void putBytes(Object key, byte[] value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の char として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getChar(Object)
	 */
	public synchronized char getChar(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Character)
		{
			return ((Character)obj).charValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return obj.toString().toCharArray()[0];
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の char 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putChar(Object, char)
	 */
	public synchronized void putChar(Object key, char value)
	{
		put(key, new Character(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.io.Reader オブジェクトとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getReader(Object)
	 */
	public synchronized Reader getReader(Object key)
	{
		return (Reader)get(key);
	}

	/**
	 * <P>
	 * 指定の java.io.Reader オブジェクトをマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putReader(Object, Reader)
	 */
	public synchronized void putReader(Object key, Reader value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.util.Date オブジェクトとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getDate(Object)
	 */
	public synchronized Date getDate(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return null;
		}

		if (obj instanceof java.sql.Timestamp)
		{
			//java.sql.Timestamp オブジェクトの場合
			return new java.util.Date(((java.sql.Timestamp)obj).getTime());
		}
		else if (obj instanceof java.sql.Date)
		{
			//java.sql.Date オブジェクトの場合
			return new java.util.Date(((java.sql.Date)obj).getTime());
		}
		else if (obj instanceof java.sql.Time)
		{
			//java.sql.Time オブジェクトの場合
			return new java.util.Date(((java.sql.Time)obj).getTime());
		}
		else if (obj instanceof java.util.Date)
		{
			//java.util.Date オブジェクトの場合
			return (java.util.Date)obj;
		}
		else
		{
			//java.sql.Timestamp の文字列表現の場合
			try
			{
				return new java.util.Date(java.sql.Timestamp.valueOf(obj.toString()).getTime());
			}
			catch (Exception e)
			{
			}

			//java.sql.Date の文字列表現の場合
			try
			{
				return new java.util.Date(java.sql.Date.valueOf(obj.toString()).getTime());
			}
			catch (Exception e)
			{
			}

			//java.sql.Time の文字列表現の場合
			try
			{
				return new java.util.Date(java.sql.Time.valueOf(obj.toString()).getTime());
			}
			catch (Exception e)
			{
			}

			//java.util.Date の文字列表現の場合
			try
			{
				return new SimpleDateFormat(
					"EEE MMM dd HH:mm:ss zzz yyyy",
					Locale.US).parse(obj.toString());
			}
			catch (Exception e)
			{
			}

			//日付/時刻の文字列表現の場合
			try
			{
				return DateFormat.getDateTimeInstance().parse(obj.toString());
			}
			catch (Exception e)
			{
			}

			//日付の文字列表現の場合
			try
			{
				return DateFormat.getDateInstance().parse(obj.toString());
			}
			catch (Exception e)
			{
			}

			//時刻の文字列表現の場合
			try
			{
				return DateFormat.getTimeInstance().parse(obj.toString());
			}
			catch (Exception e)
			{
			}
		}

		return null;
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値の文字列表現を pattern で指定した日付／時刻パターンで解析して、java.util.Date オブジェクトとして取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @param pattern 日付／時刻パターン
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#parseDate(Object, String)
	 */
	public synchronized Date parseDate(Object key, String pattern)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return null;
		}

		try
		{
			return new SimpleDateFormat(pattern).parse(obj.toString());
		}
		catch (ParseException e)
		{
		}

		return null;
	}

	/**
	 * <P>
	 * 指定の java.util.Date 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putDate(Object, Date)
	 */
	public synchronized void putDate(Object key, Date value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の double として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getDouble(Object)
	 */
	public synchronized double getDouble(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Double)
		{
			return ((Double)obj).doubleValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Double.valueOf(obj.toString()).doubleValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の double 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putDouble(Object, double)
	 */
	public synchronized void putDouble(Object key, double value)
	{
		put(key, new Double(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の float として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getFloat(Object)
	 */
	public synchronized float getFloat(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Float)
		{
			return ((Float)obj).floatValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Double.valueOf(obj.toString()).floatValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の float 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putFloat(Object, float)
	 */
	public synchronized void putFloat(Object key, float value)
	{
		put(key, new Float(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の int として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getInt(Object)
	 */
	public synchronized int getInt(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Integer)
		{
			return ((Integer)obj).intValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Double.valueOf(obj.toString()).intValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の int 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putInt(Object, int)
	 */
	public synchronized void putInt(Object key, int value)
	{
		put(key, new Integer(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の long として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getLong(Object)
	 */
	public synchronized long getLong(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Long)
		{
			return ((Long)obj).longValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Double.valueOf(obj.toString()).longValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の long 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putLong(Object, long)
	 */
	public synchronized void putLong(Object key, long value)
	{
		put(key, new Long(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の Object として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getObject(Object)
	 */
	public synchronized Object getObject(Object key)
	{
		return get(key);
	}

	/**
	 * <P>
	 * 指定の Object 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putObject(Object, Object)
	 */
	public synchronized void putObject(Object key, Object value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の short として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getShort(Object)
	 */
	public synchronized short getShort(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return 0;
		}

		if (obj instanceof Short)
		{
			return ((Short)obj).shortValue();
		}
		else if (obj.toString().trim().length() > 0)
		{
			return Double.valueOf(obj.toString()).shortValue();
		}

		return 0;
	}

	/**
	 * <P>
	 * 指定の short 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putShort(Object, short)
	 */
	public synchronized void putShort(Object key, short value)
	{
		put(key, new Short(value));
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を Java プログラミング言語の String として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getString(Object)
	 */
	public synchronized String getString(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return NULL_STRING;
		}

		if (obj instanceof String)
		{
			return (String)obj;
		}
		else
		{
			return obj.toString();
		}
	}

	/**
	 * <P>
	 * 指定の String 値をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putString(Object, String)
	 */
	public synchronized void putString(Object key, String value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * 新しい ConversionMap を構築して、指定のマップからすべてのマッピングを構築した新しい  ConversionMap にコピーします。
	 * 指定のマップが ConversionMap の場合は、それを返します。
	 * </P>
	 * @param map 新しく構築される ConversionMap に格納されるマッピング
	 * @return ConversionMap
	 */
	public synchronized static ConversionMap valueOf(Map map)
	{
		if (map instanceof ConversionMap)
		{
			return (ConversionMap)map;
		}
		else
		{
			ConversionMap cmap = new ConversionMap();
			cmap.putAll(map);
			return cmap;
		}
	}

	/**
	 * <P>
	 * 指定されたキーにマップされている値が配列の場合に true を返します。
	 * </P>
	 * @param key マップされている値が配列であるかどうかが判定されるキー
	 * @return 指定されたキーにマップされている値が配列の場合は true
	 */
	public synchronized boolean isArray(Object key)
	{
		Object obj = get(key);

		if (obj == null)
		{
			return false;
		}

		return this.getObject(key).getClass().isArray();
	}

	/**
	 * <P>
	 * マップが指定のキーのマッピングを保持する場合に true を返します。
	 * </P>
	 * @param key マップにあるかどうかが判定されるキー
	 * @return マップが指定のキーのマッピングを保持する場合は true
	 * @see java.util.Map#containsKey(Object)
	 */
	public boolean containsKey(Object key)
	{
		return super.containsKey(getKey(key));
	}

	/**
	 * <P>
	 * このマップで指定されたキーにマップされている値を返します。
	 * マップがこのキーのマッピングを保持していない場合は null を返します。
	 * 戻り値の null は、マップがキーのマッピングを保持していないことを示すとはかぎりません。
	 * つまり、マップが明示的にキーを null にマップすることもあります。
	 * containsKey(Object) メソッドを使うと、こうした 2 つの場合を見分けることができます。
	 * <P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが、指定されたキーにマッピングしている値。このキーに対するマッピングがマップにない場合は  null
	 * @see java.util.Map#get(Object)
	 */
	public Object get(Object key)
	{
		return super.get(getKey(key));
	}

	/**
	 * <P>
	 * 指定の値と指定されたキーをこのマップに関連付けます。
	 * マップが以前にこのキーのマッピングを保持していた場合、古い値が置き換えられます。
	 * <P>
	 * @param key 指定される値が関連付けられるキー
	 * @param value 指定されるキーに関連付けられる値
	 * @return 指定されたキーに関連した値。または、キーのマッピングがなかった場合は null。戻り値 null は、ConversionMap が以前に null と指定されたキーを関連付けていたことを示す場合もある
	 * @see java.util.Map#put(Object, Object)
	 */
	public Object put(Object key, Object value)
	{
		return super.put(getKey(key), value);
	}

	/**
	 * <P>
	 * 指定のマップからすべてのマッピングをマップにコピーします。
	 * これにより、マップが指定のマップ内に現在あるキーのすべてに対して持っていたマッピングが置き換えられます。
	 * <P>
	 * @param map マップに格納されるマッピング
	 * @see java.util.Map#putAll(Map)
	 */
	public void putAll(Map map)
	{
		Object[] keys = map.keySet().toArray();
		for (int i = 0; i < keys.length; i++)
		{
			put(getKey(keys[i]), map.get(keys[i]));
		}
	}

	/**
	 * <P>
	 * キーに対するマッピングがあれば、そのキーをマップから削除します。
	 * <P>
	 * @param key マッピングがマップから削除されるキー
	 * @return 指定されたキーに関連した値。または、キーのマッピングがなかった場合は null。戻り値 null は、マップが以前に null と指定されたキーを関連付けていたことを示す場合もある
	 * @see java.util.Map#remove(Object)
	 */
	public Object remove(Object key)
	{
		return super.remove(getKey(key));
	}

	/**
	 * <P>
	 * 指定されたキーにマップされている値が NULL の場合に true を返します。
	 * </P>
	 * @param key マップされている値が NULL であるかどうかが判定されるキー
	 * @return 指定されたキーにマップされている値が NULL の場合は true
	 */
	public synchronized boolean isNull(Object key)
	{
		return ((this.getObject(key) == null) ? true : false);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.util.List として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getList(Object)
	 */
	public synchronized java.util.List getList(Object key)
	{
		return (java.util.List)get(key);
	}

	/**
	 * <P>
	 * 指定の java.util.List をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putList(Object, List)
	 */
	public synchronized void putList(Object key, java.util.List value)
	{
		put(key, value);
	}

	/**
	 * <P>
	 * マップが指定のキーをマップする値を java.util.Map として取得します。
	 * </P>
	 * @param key 関連付けられた値が返されるキー
	 * @return マップが指定されたキーをマップする値
	 * @see jp.morpho.util.PrimitiveHolderMap#getMap(Object)
	 */
	public synchronized java.util.Map getMap(Object key)
	{
		return (java.util.Map)get(key);
	}

	/**
	 * <P>
	 * 指定の java.util.Map をマップ内の指定のキーと関連付けます。
	 * </P>
	 * @param key 指定された値が関連付けられるキー
	 * @param value 指定されたキーに関連付けられる値
	 * @see jp.morpho.util.PrimitiveHolderMap#putMap(Object, Map)
	 */
	public synchronized void putMap(Object key, java.util.Map value)
	{
		put(key, value);
	}

}
