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

import org.opengion.fukurou.system.OgRuntimeException ;				// 6.4.2.0 (2016/01/29)
import java.awt.Color;
// import java.util.HashMap;
import java.util.LinkedHashMap;										// 6.4.6.1 (2016/06/03)
import java.util.Map;
import java.util.Locale ;

import static org.opengion.fukurou.system.HybsConst.CR;				// 6.1.0.0 (2014/12/26) refactoring

/**
 * ColorMap.java は、共通的に使用される Color関連メソッドを集約した、クラスです。
 * StringUtil から、Color関係の部分を独立させました。
 *
 * カラー文字列は、java.awt.Color static 定義色、CSS1 / HTML3–4 / VGA の色名称、
 * X11の色名称 が指定できます。
 *
 * カラー番号は、0:BLUE,1:CYAN,2:GRAY,3:GREEN,4:LIGHT_GRAY,
 * 5:MAGENTA,6:DARK_GRAY,7:ORANGE,8:PINK,9:RED,10:YELLOW 
 * となっており、配列数を超えると、0:BLUE に戻ります。
 *
 * @og.group ユーティリティ
 * @og.rev 6.0.2.1 (2014/09/26) 新規作成
 * @og.rev 6.4.3.3 (2016/03/04) ViewForm_ImageTimeBar#FlgColorMap 内部クラスから機能移動
 *
 * @version  6.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK8.0,
 */
public final class ColorMap {
	// 6.4.3.3 (2016/03/04) ViewForm_ImageTimeBar#FlgColorMap 内部クラスから移動
	private static final Color[] CLR_ARY = new Color[] {
			Color.BLUE      ,Color.CYAN   ,Color.GRAY ,Color.GREEN ,Color.LIGHT_GRAY ,Color.MAGENTA ,
			Color.DARK_GRAY ,Color.ORANGE ,Color.PINK ,Color.RED   ,Color.YELLOW
	};

	// 4.0.3.0 (2007/12/26) 色コードにPURPLE を追加
	// 5.7.8.0 (2014/07/04) 透明追加
	/** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
	private static final Map<String,Color> CLR_MAP;
	static {
//		CLR_MAP = new HashMap<>();
		CLR_MAP = new LinkedHashMap<>();							// 6.4.6.1 (2016/06/03) 登録順をキープします。
		// java.awt.Color static 定義色
		CLR_MAP.put( "BLUE"			,Color.BLUE			);
		CLR_MAP.put( "CYAN"			,Color.CYAN			);
		CLR_MAP.put( "GRAY"			,Color.GRAY			);
		CLR_MAP.put( "GREEN"		,Color.GREEN		);
		CLR_MAP.put( "LIGHTGRAY"	,Color.LIGHT_GRAY	);
		CLR_MAP.put( "MAGENTA"		,Color.MAGENTA		);
		CLR_MAP.put( "DARKGRAY"		,Color.DARK_GRAY	);
		CLR_MAP.put( "ORANGE"		,Color.ORANGE		);
		CLR_MAP.put( "PINK"			,Color.PINK			);
		CLR_MAP.put( "RED"			,Color.RED			);
		CLR_MAP.put( "YELLOW"		,Color.YELLOW		);

		CLR_MAP.put( "WHITE"		,Color.WHITE		);
		CLR_MAP.put( "BLACK"		,Color.BLACK		);
		CLR_MAP.put( "TRANSPARENT"	,new Color( 255,255,255,0 )	);		// 5.7.8.0 (2014/07/04) 透明追加

		// 6.0.2.1 (2014/09/26) CSS1 / HTML3–4 / VGA の色名称 追加
		CLR_MAP.put( "LIME"			,Color.decode( "#00FF00" )	);
		CLR_MAP.put( "AQUA"			,Color.decode( "#00FFFF" )	);
		CLR_MAP.put( "SILVER"		,Color.decode( "#C0C0C0" )	);
		CLR_MAP.put( "MAROON"		,Color.decode( "#800000" )	);		// X11では、#B03060
		CLR_MAP.put( "OLIVE"		,Color.decode( "#808000" )	);
		CLR_MAP.put( "TEAL"			,Color.decode( "#008080" )	);
		CLR_MAP.put( "NAVY"			,Color.decode( "#000080" )	);
		CLR_MAP.put( "FUCHSIA"		,Color.decode( "#FF00FF" )	);
		CLR_MAP.put( "PURPLE"		,Color.decode( "#800080" )	);		// X11では、#A020F0

		// 6.0.2.1 (2014/09/26) X11の色名称 追加
		CLR_MAP.put( "ALICEBLUE"			,Color.decode( "#F0F8FF" )	);
		CLR_MAP.put( "ANTIQUEWHITE"			,Color.decode( "#FAEBD7" )	);
		CLR_MAP.put( "AQUAMARINE"			,Color.decode( "#7FFFD4" )	);
		CLR_MAP.put( "AZURE"				,Color.decode( "#F0FFFF" )	);
		CLR_MAP.put( "BEIGE"				,Color.decode( "#F5F5DC" )	);
		CLR_MAP.put( "BISQUE"				,Color.decode( "#FFE4C4" )	);
		CLR_MAP.put( "BLANCHEDALMOND"		,Color.decode( "#FFEBCD" )	);
		CLR_MAP.put( "BLUEVIOLET"			,Color.decode( "#8A2BE2" )	);
		CLR_MAP.put( "BROWN"				,Color.decode( "#A52A2A" )	);
		CLR_MAP.put( "BURLYWOOD"			,Color.decode( "#DEB887" )	);
		CLR_MAP.put( "CADETBLUE"			,Color.decode( "#5F9EA0" )	);
		CLR_MAP.put( "CHARTREUSE"			,Color.decode( "#7FFF00" )	);
		CLR_MAP.put( "CHOCOLATE"			,Color.decode( "#D2691E" )	);
		CLR_MAP.put( "CORAL"				,Color.decode( "#FF7F50" )	);
		CLR_MAP.put( "CORNFLOWERBLUE"		,Color.decode( "#6495ED" )	);
		CLR_MAP.put( "CORNSILK"				,Color.decode( "#FFF8DC" )	);
		CLR_MAP.put( "CRIMSON"				,Color.decode( "#DC143C" )	);
		CLR_MAP.put( "DARKBLUE"				,Color.decode( "#00008B" )	);
		CLR_MAP.put( "DARKCYAN"				,Color.decode( "#008B8B" )	);
		CLR_MAP.put( "DARKGOLDENROD"		,Color.decode( "#B8860B" )	);
		CLR_MAP.put( "DARKGREEN"			,Color.decode( "#006400" )	);
		CLR_MAP.put( "DARKKHAKI"			,Color.decode( "#BDB76B" )	);
		CLR_MAP.put( "DARKMAGENTA"			,Color.decode( "#8B008B" )	);
		CLR_MAP.put( "DARKOLIVEGREEN"		,Color.decode( "#556B2F" )	);
		CLR_MAP.put( "DARKORANGE"			,Color.decode( "#FF8C00" )	);
		CLR_MAP.put( "DARKORCHID"			,Color.decode( "#9932CC" )	);
		CLR_MAP.put( "DARKRED"				,Color.decode( "#8B0000" )	);
		CLR_MAP.put( "DARKSALMON"			,Color.decode( "#E9967A" )	);
		CLR_MAP.put( "DARKSEAGREEN"			,Color.decode( "#8FBC8F" )	);
		CLR_MAP.put( "DARKSLATEBLUE"		,Color.decode( "#483D8B" )	);
		CLR_MAP.put( "DARKSLATEGRAY"		,Color.decode( "#2F4F4F" )	);
		CLR_MAP.put( "DARKTURQUOISE"		,Color.decode( "#00CED1" )	);
		CLR_MAP.put( "DARKVIOLET"			,Color.decode( "#9400D3" )	);
		CLR_MAP.put( "DEEPPINK"				,Color.decode( "#FF1493" )	);
		CLR_MAP.put( "DEEPSKYBLUE"			,Color.decode( "#00BFFF" )	);
		CLR_MAP.put( "DIMGRAY"				,Color.decode( "#696969" )	);
		CLR_MAP.put( "DODGERBLUE"			,Color.decode( "#1E90FF" )	);
		CLR_MAP.put( "FIREBRICK"			,Color.decode( "#B22222" )	);
		CLR_MAP.put( "FLORALWHITE"			,Color.decode( "#FFFAF0" )	);
		CLR_MAP.put( "FORESTGREEN"			,Color.decode( "#228B22" )	);
		CLR_MAP.put( "GAINSBORO"			,Color.decode( "#DCDCDC" )	);
		CLR_MAP.put( "GHOSTWHITE"			,Color.decode( "#F8F8FF" )	);
		CLR_MAP.put( "GOLD"					,Color.decode( "#FFD700" )	);
		CLR_MAP.put( "GOLDENROD"			,Color.decode( "#DAA520" )	);
		CLR_MAP.put( "GREENYELLOW"			,Color.decode( "#ADFF2F" )	);
		CLR_MAP.put( "HONEYDEW"				,Color.decode( "#F0FFF0" )	);
		CLR_MAP.put( "HOTPINK"				,Color.decode( "#FF69B4" )	);
		CLR_MAP.put( "INDIANRED"			,Color.decode( "#CD5C5C" )	);
		CLR_MAP.put( "INDIGO"				,Color.decode( "#4B0082" )	);
		CLR_MAP.put( "IVORY"				,Color.decode( "#FFFFF0" )	);
		CLR_MAP.put( "KHAKI"				,Color.decode( "#F0E68C" )	);
		CLR_MAP.put( "LAVENDER"				,Color.decode( "#E6E6FA" )	);
		CLR_MAP.put( "LAVENDERBLUSH"		,Color.decode( "#FFF0F5" )	);
		CLR_MAP.put( "LAWNGREEN"			,Color.decode( "#7CFC00" )	);
		CLR_MAP.put( "LEMONCHIFFON"			,Color.decode( "#FFFACD" )	);
		CLR_MAP.put( "LIGHTBLUE"			,Color.decode( "#ADD8E6" )	);
		CLR_MAP.put( "LIGHTCORAL"			,Color.decode( "#F08080" )	);
		CLR_MAP.put( "LIGHTCYAN"			,Color.decode( "#E0FFFF" )	);
		CLR_MAP.put( "LIGHTGOLDENRODYELLOW"	,Color.decode( "#FAFAD2" )	);
		CLR_MAP.put( "LIGHTGREEN"			,Color.decode( "#90EE90" )	);
		CLR_MAP.put( "LIGHTPINK"			,Color.decode( "#FFB6C1" )	);
		CLR_MAP.put( "LIGHTSALMON"			,Color.decode( "#FFA07A" )	);
		CLR_MAP.put( "LIGHTSEAGREEN"		,Color.decode( "#20B2AA" )	);
		CLR_MAP.put( "LIGHTSKYBLUE"			,Color.decode( "#87CEFA" )	);
		CLR_MAP.put( "LIGHTSLATEGRAY"		,Color.decode( "#778899" )	);
		CLR_MAP.put( "LIGHTSTEELBLUE"		,Color.decode( "#B0C4DE" )	);
		CLR_MAP.put( "LIGHTYELLOW"			,Color.decode( "#FFFFE0" )	);
		CLR_MAP.put( "LIMEGREEN"			,Color.decode( "#32CD32" )	);
		CLR_MAP.put( "LINEN"				,Color.decode( "#FAF0E6" )	);
		CLR_MAP.put( "MEDIUMAQUAMARINE"		,Color.decode( "#66CDAA" )	);
		CLR_MAP.put( "MEDIUMBLUE"			,Color.decode( "#0000CD" )	);
		CLR_MAP.put( "MEDIUMORCHID"			,Color.decode( "#BA55D3" )	);
		CLR_MAP.put( "MEDIUMPURPLE"			,Color.decode( "#9370DB" )	);
		CLR_MAP.put( "MEDIUMSEAGREEN"		,Color.decode( "#3CB371" )	);
		CLR_MAP.put( "MEDIUMSLATEBLUE"		,Color.decode( "#7B68EE" )	);
		CLR_MAP.put( "MEDIUMSPRINGGREEN"	,Color.decode( "#00FA9A" )	);
		CLR_MAP.put( "MEDIUMTURQUOISE"		,Color.decode( "#48D1CC" )	);
		CLR_MAP.put( "MEDIUMVIOLETRED"		,Color.decode( "#C71585" )	);
		CLR_MAP.put( "MIDNIGHTBLUE"			,Color.decode( "#191970" )	);
		CLR_MAP.put( "MINTCREAM"			,Color.decode( "#F5FFFA" )	);
		CLR_MAP.put( "MISTYROSE"			,Color.decode( "#FFE4E1" )	);
		CLR_MAP.put( "MOCCASIN"				,Color.decode( "#FFE4B5" )	);
		CLR_MAP.put( "NAVAJOWHITE"			,Color.decode( "#FFDEAD" )	);
		CLR_MAP.put( "OLDLACE"				,Color.decode( "#FDF5E6" )	);
		CLR_MAP.put( "OLIVEDRAB"			,Color.decode( "#6B8E23" )	);
		CLR_MAP.put( "ORANGERED"			,Color.decode( "#FF4500" )	);
		CLR_MAP.put( "ORCHID"				,Color.decode( "#DA70D6" )	);
		CLR_MAP.put( "PALEGOLDENROD"		,Color.decode( "#EEE8AA" )	);
		CLR_MAP.put( "PALEGREEN"			,Color.decode( "#98FB98" )	);
		CLR_MAP.put( "PALETURQUOISE"		,Color.decode( "#AFEEEE" )	);
		CLR_MAP.put( "PALEVIOLETRED"		,Color.decode( "#DB7093" )	);
		CLR_MAP.put( "PAPAYAWHIP"			,Color.decode( "#FFEFD5" )	);
		CLR_MAP.put( "PEACHPUFF"			,Color.decode( "#FFDAB9" )	);
		CLR_MAP.put( "PERU"					,Color.decode( "#CD853F" )	);
		CLR_MAP.put( "PLUM"					,Color.decode( "#DDA0DD" )	);
		CLR_MAP.put( "POWDERBLUE"			,Color.decode( "#B0E0E6" )	);
		CLR_MAP.put( "ROSYBROWN"			,Color.decode( "#BC8F8F" )	);
		CLR_MAP.put( "ROYALBLUE"			,Color.decode( "#4169E1" )	);
		CLR_MAP.put( "SADDLEBROWN"			,Color.decode( "#8B4513" )	);
		CLR_MAP.put( "SALMON"				,Color.decode( "#FA8072" )	);
		CLR_MAP.put( "SANDYBROWN"			,Color.decode( "#F4A460" )	);
		CLR_MAP.put( "SEAGREEN"				,Color.decode( "#2E8B57" )	);
		CLR_MAP.put( "SEASHELL"				,Color.decode( "#FFF5EE" )	);
		CLR_MAP.put( "SIENNA"				,Color.decode( "#A0522D" )	);
		CLR_MAP.put( "SKYBLUE"				,Color.decode( "#87CEEB" )	);
		CLR_MAP.put( "SLATEBLUE"			,Color.decode( "#6A5ACD" )	);
		CLR_MAP.put( "SLATEGRAY"			,Color.decode( "#708090" )	);
		CLR_MAP.put( "SNOW"					,Color.decode( "#FFFAFA" )	);
		CLR_MAP.put( "SPRINGGREEN"			,Color.decode( "#00FF7F" )	);
		CLR_MAP.put( "STEELBLUE"			,Color.decode( "#4682B4" )	);
		CLR_MAP.put( "TAN"					,Color.decode( "#D2B48C" )	);
		CLR_MAP.put( "THISTLE"				,Color.decode( "#D8BFD8" )	);
		CLR_MAP.put( "TOMATO"				,Color.decode( "#FF6347" )	);
		CLR_MAP.put( "TURQUOISE"			,Color.decode( "#40E0D0" )	);
		CLR_MAP.put( "VIOLET"				,Color.decode( "#EE82EE" )	);
		CLR_MAP.put( "WHEAT"				,Color.decode( "#F5DEB3" )	);
		CLR_MAP.put( "WHITESMOKE"			,Color.decode( "#F5F5F5" )	);
		CLR_MAP.put( "YELLOWGREEN"			,Color.decode( "#9ACD32" )	);

		// 6.4.4.1 (2016/03/18)
		for( int i=0; i<CLR_ARY.length; i++ ) {
			CLR_MAP.put( String.valueOf( i ) ,CLR_ARY[i] );
		}
	}

	/**
	 *	デフォルトコンストラクターをprivateにして、
	 *	オブジェクトの生成をさせないようにする。
	 *
	 */
	private ColorMap() {}

	/**
	 * カラーキーワードより、Colorオブジェクトを作成します。
	 *
	 * 指定文字列は、java.awt.Color クラスのstatic フィールド名で指定します。
	 * BLACK , BLUE , CYAN , DARK_GRAY , GRAY , GREEN , LIGHT_GRAY ,
	 * MAGENTA , ORANGE , PINK , RED , WHITE , YELLOW , PURPLE , TRANSPARENT(透明) が指定できます。
	 * 
	 * 6.0.2.1 (2014/09/26) 以降では、CSS1/HTML3–4/VGA の色名称として、
	 * LIME , AQUA , SILVER , MAROON , OLIVE , TEAL , NAVY , FUCHSIA を追加。
	 * それと、X11の色名称 を追加しました。
	 * 
	 * また、先頭に、# を付ける事で、#XXXXXX形式の16bitRGB表記 でも指定可能です。
	 * static フィールド名のMapを管理していますが、存在しない場合は、エラーになります。
	 *
	 * @og.rev 3.8.9.1 (2007/06/29) 新規作成
	 * @og.rev 4.1.1.0 (2008/02/04) CLR_MAP に存在しない場合はエラーにします。
	 * @og.rev 6.0.2.1 (2014/09/26) CSS1/HTML3–4/VGA の色名称 , X11の色名称 追加
	 * @og.rev 6.3.9.0 (2015/11/06) valueのnullチェックの仕方が間違っていた。
	 * @og.rev 6.4.6.1 (2016/06/03) 色番号の取得も対応しておきます。
	 *
	 * @param	value java.awt.Color フィールドを示す文字列または、#XXXXXX形式の16bitRGB表記
	 *
	 * @return	Colorオブジェクト
	 * @see		java.awt.Color#BLACK
	 */
	public static Color getColorInstance( final String value ) {
		// 6.3.9.0 (2015/11/06) valueのnullチェックの仕方が間違っていた。
		if( value == null || value.length() == 0 ) {
//			final String errMsg = "指定の色コードは使用できません Color=[" + value + "]" + CR
			final String errMsg = "色コードが指定されていません。" + CR			// 6.4.6.1 (2016/06/03)
						+ "ColorMap=" + CLR_MAP.keySet().toString();
			throw new OgRuntimeException( errMsg );
		}

//		final Color clr ;
		Color clr = null ;			// 6.4.6.1 (2016/06/03) 色番号で、再設定しているため、final をはずす。

//		if( value != null && value.length() > 0 && value.charAt(0) == '#' ) {	// 6.1.0.0 (2014/12/26) refactoring
		if( value.charAt(0) == '#' ) {
			try {
				clr = Color.decode( value );
			}
			catch( final NumberFormatException ex ) {			// 10進、8進、および16進の整数値に変換できない場合
				final String errMsg = "指定の色コードのフォーマットが異なります Color=[" + value + "]" + CR
							+ "ColorMap=" + CLR_MAP.keySet().toString();
				throw new OgRuntimeException( errMsg,ex );
			}
		}
		else {
			// "_"を削除するのは、LIGHT_GRAY などの表記を統一するため。
			final String val = value.replaceAll( "_" , "" ).toUpperCase(Locale.JAPAN);
			clr = CLR_MAP.get( val );
			if( clr == null ) {
				// 6.4.6.1 (2016/06/03) 色番号の取得も対応しておきます。
				// 0 ～ 10 は登録済みなので、それ以降の数字の繰り返しが出来ない
				try {
					clr = getColorInstance( Integer.parseInt( value ) );
				}
				catch( final NumberFormatException ex ) {			// 数字ではない value をパースしているので、この、Exception は伝播不要。
					final String errMsg = "指定の色コードは使用できません Color=[" + value + "]" + CR
								+ "ColorMap=" + CLR_MAP.keySet().toString();
					throw new OgRuntimeException( errMsg,ex );
				}
			}
		}

		return clr;
	}

	/**
	 * 指定の番号に対応した、色オブジェクトを返します。
	 *
	 * 以前は、ViewForm_ImageTimeBar#uniqColor() メソッドで、ユニークな色を
	 * 返していました。配列を超えると、自動的にランダムな色を出していましたが、
	 * 実質的にそのような色を出すのではなく、番号に応じて、繰り返すことにします。
	 * 割り当てた色の番号は、0:BLUE,1:CYAN,2:GRAY,3:GREEN,4:LIGHT_GRAY,
	 * 5:MAGENTA,6:DARK_GRAY,7:ORANGE,8:PINK,9:RED,10:YELLOW 
	 * となっており、それを超えると、0:BLUE に戻ります。
	 *
	 * @og.rev 6.4.3.3 (2016/03/04) ViewForm_ImageTimeBar#uniqColor() メソッドから移動。
	 *
	 * @param	no 内部で管理している色番号
	 * @return	色オブジェクト
	 */
//	public Color uniqColor() {
	public static Color getColorInstance( final int no ) {
		return CLR_ARY[no % CLR_ARY.length];

//		final Color col;						// 6.3.9.0 (2015/11/06) Found 'DU'-anomaly for variable(PMD)
//		if( lastCnt < CLR_ARY.length ) {
//			col = CLR_ARY[lastCnt++];
//		}
//		else {
//			// 6.0.2.5 (2014/10/31) refactoring
//			final Random rand = new Random();
//			final int R=rand.nextInt(256);
//			final int G=rand.nextInt(256);
//			final int B=rand.nextInt(256);
//			col = new Color(R,G,B);
//		}
//
//		return col;
	}

	/**
	 * 内部で管理している ColorMap のキー配列を返します。
	 *
	 * @og.rev 6.0.2.1 (2014/09/26) 新規追加
	 *
	 * @return	キー配列
	 * @og.rtnNotNull
	 */
	public static String[] getColorKeys() {
		return CLR_MAP.keySet().toArray( new String[CLR_MAP.size()] );
	}
}
