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

import static org.opengion.fukurou.system.HybsConst.CR ;		// 6.1.0.0 (2014/12/26)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;

import org.jfree.data.jdbc.JDBCPieDataset;
import org.jfree.data.jdbc.JDBCXYDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.DefaultValueDataset;

import org.jfree.data.xy.CategoryTableXYDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.DefaultKeyedValues;

import org.jfree.data.category.CategoryDataset;			// 6.9.7.0 (2018/05/14)
import org.jfree.data.xy.XYDataset;						// 6.9.7.0 (2018/05/14)
import org.jfree.data.Values;							// 6.9.7.0 (2018/05/14)
import org.jfree.data.Value;							// 6.9.7.0 (2018/05/14)

/**
 * ChartFactory は、Dataset および、Renderer のオブジェクトを構築するファクトリクラスです。
 * JFreeChart では、各種オブジェクトの組み合わせで、色々なグラフを作成できます。
 * ここでは、簡易的にオブジェクトを構築できるように、一つのキーワードによって、各種作成する
 * オブジェクトのキーワードを関連付けておきます。
 *
 * <table class="plain">
 *   <caption>各種オブジェクトの組み合わせ一覧</caption>
 *   <tr><th> チャートタイプ          </th><th> レンデラー(org.jfree.chart.renderer.)    </th><th> Dataset          </th></tr>
 *   <tr><td> HybsLine                </td><td> HybsLineRenderer                         </td><td> Category         </td></tr>
 *   <tr><td> LineAndShape            </td><td> category.LineAndShapeRenderer            </td><td> Category         </td></tr>
 *   <tr><td> Line3D                  </td><td> category.LineRenderer3D                  </td><td> Category         </td></tr>
 *   <tr><td> StatisticalLineAndShape </td><td> category.StatisticalLineAndShapeRenderer </td><td> Category         </td></tr>
 *   <tr><td> HybsParetoLine          </td><td> HybsLineRenderer                         </td><td> ParetoCategory   </td></tr>
 *   <tr><td> HybsBar                 </td><td> HybsBarRenderer                          </td><td> Category         </td></tr>
 *   <tr><td> HybsColorBar            </td><td> HybsBarRenderer                          </td><td> Category         </td></tr>
 *   <tr><td> Bar                     </td><td> category.BarRenderer                     </td><td> Category         </td></tr>
 *   <tr><td> Bar3D                   </td><td> category.BarRenderer3D                   </td><td> Category         </td></tr>
 *   <tr><td> HybsColorBar3D          </td><td> HybsBarRenderer3D                        </td><td> Category         </td></tr>
 *   <tr><td> Area                    </td><td> category.AreaRenderer                    </td><td> Category         </td></tr>
 *   <tr><td> HybsStackedBar          </td><td> HybsStackedBarRenderer                   </td><td> Category         </td></tr>
 *   <tr><td> StackedBar              </td><td> category.StackedBarRenderer              </td><td> Category         </td></tr>
 *   <tr><td> StackedBar3D            </td><td> category.StackedBarRenderer3D            </td><td> Category         </td></tr>
 *   <tr><td> StackedArea             </td><td> category.StackedAreaRenderer             </td><td> Category         </td></tr>
 *   <tr><td> GroupedStackedBar       </td><td> category.GroupedStackedBarRenderer       </td><td> Category         </td></tr>
 *   <tr><td> LayeredBar              </td><td> category.LayeredBarRenderer              </td><td> Category         </td></tr>
 *   <tr><td> CategoryStep            </td><td> category.CategoryStepRenderer            </td><td> Category         </td></tr>
 *   <tr><td> Level                   </td><td> category.LevelRenderer                   </td><td> Category         </td></tr>
 *   <tr><td> MinMax                  </td><td> category.MinMaxCategoryRenderer          </td><td> Category         </td></tr>
 *   <tr><td> WaterfallBar            </td><td> category.WaterfallBarRenderer            </td><td> Category         </td></tr>
 *   <tr><td> MultiplePie             </td><td> null                                     </td><td> Category         </td></tr>
 *   <tr><td> SpiderWeb               </td><td> null                                     </td><td> Category         </td></tr>
 *   <tr><td> Pie                     </td><td> null                                     </td><td> Pie              </td></tr>
 *   <tr><td> Pie3D                   </td><td> null                                     </td><td> Pie              </td></tr>
 *   <tr><td> Ring                    </td><td> null                                     </td><td> Pie              </td></tr>
 *   <tr><td> XYArea                  </td><td> xy.XYAreaRenderer                        </td><td> XY               </td></tr>
 *   <tr><td> XYArea2                 </td><td> xy.XYAreaRenderer2                       </td><td> XY               </td></tr>
 *   <tr><td> XYBlock                 </td><td> xy.XYBlockRenderer                       </td><td> XY               </td></tr>
 *   <tr><td> CyclicXYItem            </td><td> xy.CyclicXYItemRenderer                  </td><td> XY               </td></tr>
 *   <tr><td> HighLow                 </td><td> xy.HighLowRenderer                       </td><td> XY               </td></tr>
 *   <tr><td> StackedXYArea           </td><td> xy.StackedXYAreaRenderer                 </td><td> XY               </td></tr>
 *   <tr><td> StackedXYArea2          </td><td> xy.StackedXYAreaRenderer2                </td><td> XY               </td></tr>
 *   <tr><td> StandardXYItem          </td><td> xy.StandardXYItemRenderer                </td><td> XY               </td></tr>
 *   <tr><td> XYBubble                </td><td> xy.XYBubbleRenderer                      </td><td> XY               </td></tr>
 *   <tr><td> XYDifference            </td><td> xy.XYDifferenceRenderer                  </td><td> XY               </td></tr>
 *   <tr><td> XYDot                   </td><td> xy.XYDotRenderer                         </td><td> XY               </td></tr>
 *   <tr><td> XYError                 </td><td> xy.XYErrorRenderer                       </td><td> XY               </td></tr>
 *   <tr><td> XYLine3D                </td><td> xy.XYLine3DRenderer                      </td><td> XY               </td></tr>
 *   <tr><td> XYLineAndShape          </td><td> xy.XYLineAndShapeRenderer                </td><td> XY               </td></tr>
 *   <tr><td> XYStepArea              </td><td> xy.XYStepAreaRenderer                    </td><td> XY               </td></tr>
 *   <tr><td> XYStep                  </td><td> xy.XYStepRenderer                        </td><td> XY               </td></tr>
 *   <tr><td> PolarItem               </td><td> DefaultPolarItemRenderer                 </td><td> XY               </td></tr>
 *   <tr><td> Meter                   </td><td> null                                     </td><td> Value            </td></tr>
 *   <tr><td> Thermometer             </td><td> null                                     </td><td> Value            </td></tr>
 *   <tr><td> Compass                 </td><td> null                                     </td><td> Value            </td></tr>
 *   <tr><td> Gantt                   </td><td> category.GanttRenderer                   </td><td> TaskSeries       </td></tr>
 *   <tr><td> XYBarV                  </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
 *   <tr><td> ClusteredXYBarV         </td><td> xy.ClusteredXYBarRenderer                </td><td> TimeSeries       </td></tr>
 *   <tr><td> YIntervalV              </td><td> xy.YIntervalRenderer                     </td><td> TimeSeries       </td></tr>
 *   <tr><td> DeviationV              </td><td> xy.DeviationRenderer                     </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeSeriesLineV         </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeSeriesLineH         </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeSeriesBarV          </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeSeriesBarH          </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
 *   <tr><td> StackedTimeSeriesLineV  </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
 *   <tr><td> StackedTimeSeriesLineH  </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeStepV               </td><td> xy.XYStepRenderer                        </td><td> TimeSeries       </td></tr>
 *   <tr><td> TimeStepH               </td><td> xy.XYStepRenderer                        </td><td> TimeSeries       </td></tr>
 * </table>
 *
 * @version  0.9.0	2007/06/21
 * @author	 Kazuhiko Hasegawa
 * @since	 JDK1.1,
 */
public final class ChartFactory {

	private static final String PLOT_SUB = "org.opengion.hayabusa.io.ChartPlot_" ;

	// ChartPlot オブジェクトはマルチスレッドで使用可能なため、キャッシュして使いまわします。

	private static ChartPlot plotCAT	;
	private static ChartPlot plotXY		;
	private static ChartPlot plotPIE	;
	private static ChartPlot plotTIM	;		// 5.6.1.0 (2013/02/01)
	private static ChartPlot plotXTIM	;		// 5.6.1.0 (2013/02/01)

	private static final Object LOCK = new Object();		// 6.4.1.1 (2016/01/16) lock → LOCK refactoring

	/**
	 * 引数タイプに応じたレンデラーやデータセットを規定します。
	 */
	/** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
	private static final Map<String,TypeRenderer> TYPE_RENDERER_MAP = new HashMap<>();

	// 4.1.1.0 (2008/02/04) HybsBar 追加
	// 5.3.0.0 (2010/12/01) xxxPlot 追加、データ内容修正、コメント部対応
	static {
		final String[][] data = new String[][] {
			// キーワード					xxxRenderer									xxxDataset				xxxPlot
		    {  "HybsLine"				, "HybsLineRenderer"						, "Category"			, "Category"	}
		  , {  "LineAndShape"			, "category.LineAndShapeRenderer"			, "Category"			, "Category"	}
		  , {  "Line3D"					, "category.LineRenderer3D" 				, "Category"			, "Category"	}
		  , {  "StatisticalLineAndShape", "category.StatisticalLineAndShapeRenderer", "Category"			, "Category"	}
		  , {  "HybsParetoLine"			, "HybsLineRenderer"						, "ParetoCategory"		, "Category"	}	// 6.0.2.1 (2014/09/26) パレート図

		  , {  "HybsBar"				, "HybsBarRenderer"							, "Category"			, "Category"	}
		  , {  "HybsColorBar"			, "HybsBarRenderer"							, "Category"			, "Category"	}	// 6.0.2.1 (2014/09/26) カテゴリカラー
		  , {  "Bar"					, "category.BarRenderer"					, "Category"			, "Category"	}
		  , {  "Bar3D" 					, "category.BarRenderer3D"					, "Category"			, "Category"	}
		  , {  "HybsColorBar3D"			, "HybsBarRenderer3D"						, "Category"			, "Category"	}	// 6.0.2.2 (2014/10/03) カテゴリカラー
		  , {  "Area"					, "category.AreaRenderer"					, "Category"			, "Category"	}

		  , {  "HybsStackedBar"			, "HybsStackedBarRenderer"					, "Category"			, "Category"	}
		  , {  "StackedBar"				, "category.StackedBarRenderer" 			, "Category"			, "Category"	}
		  , {  "StackedBar3D"			, "category.StackedBarRenderer3D"			, "Category"			, "Category"	}
		  , {  "StackedArea"			, "category.StackedAreaRenderer"			, "Category"			, "Category"	}
		  , {  "GroupedStackedBar" 		, "category.GroupedStackedBarRenderer"		, "Category"			, "Category"	}

		  , {  "LayeredBar"				, "category.LayeredBarRenderer" 			, "Category"			, "Category"	}

		  , {  "CategoryStep"			, "category.CategoryStepRenderer"			, "Category"			, "Category"	}
		  , {  "Level" 					, "category.LevelRenderer"					, "Category"			, "Category"	}

		  , {  "MinMax"					, "category.MinMaxCategoryRenderer" 		, "Category"			, "Category"	}

		  , {  "WaterfallBar"			, "category.WaterfallBarRenderer"			, "Category"			, "Category"	}

		  , {  "MultiplePie"			,  null 									, "Category"			, "MultiplePie"	}
		  , {  "SpiderWeb" 				,  null 									, "Category"			, "SpiderWeb"	}

	//	  , {  "BoxAndWhisker" 			, "category.BoxAndWhiskerRenderer"			, "BoxAndWhisker"		, "Category"	}
	//	  , {  "IntervalBar"			, "category.IntervalBarRenderer"			, "IntervalCategory"	, "Category"	}
	//	  , {  "StatisticalBar"			, "category.StatisticalBarRenderer" 		, "StatisticalCategory" , "Category"	}
	//	  , {  "Candlestick"			, "xy.CandlestickRenderer"					, "OHLC" 				, "XY"			}
	//	  , {  "StackedXYBarV"			, "xy.StackedXYBarRenderer" 				, "TableXY"				, "XY"			}
	//	  , {  "WindItem"				, "xy.WindItemRenderer" 					, "Wind" 				, "XY"			}
	//	  , {  "XYBoxAndWhisker"		, "xy.XYBoxAndWhiskerRenderer"				, "BoxAndWhiskerXY" 	, "XY"			}
	//	  , {  "WaferMap"				, "WaferMapRenderer"						, "WaferMap"			, "WaferMap"	}
	//	  , {  "Contour"				,  null 									, "Contour"				, "Contour"		}
	//	  , {  "FastScatter"			,  null 									, "float2"				, "FastScatter"	}

		  , {  "Pie"					,  null 									, "Pie"					, "Pie"	 		}
		  , {  "Pie3D" 					,  null 									, "Pie"					, "Pie"	 		}
		  , {  "Ring"					,  null 									, "Pie"					, "Ring"		}

		  , {  "XYArea"					, "xy.XYAreaRenderer"						, "XY"					, "XY"			}
		  , {  "XYArea2"				, "xy.XYAreaRenderer2"						, "XY"					, "XY"			}
		  , {  "XYBlock"				, "xy.XYBlockRenderer"						, "XY"					, "XY"			}
		  , {  "CyclicXYItem"			, "xy.CyclicXYItemRenderer" 				, "XY"					, "XY"			}
		  , {  "HighLow"				, "xy.HighLowRenderer"						, "XY"					, "XY"			}
		  , {  "StackedXYArea" 			, "xy.StackedXYAreaRenderer"				, "XY"					, "XY"			}
		  , {  "StackedXYArea2"			, "xy.StackedXYAreaRenderer2"				, "XY"					, "XY"			}
		  , {  "StandardXYItem"			, "xy.StandardXYItemRenderer"				, "XY"					, "XY"			}
		  , {  "XYBubble"				, "xy.XYBubbleRenderer" 					, "XY"					, "XY"			}
		  , {  "XYDifference"			, "xy.XYDifferenceRenderer" 				, "XY"					, "XY"			}
		  , {  "XYDot" 					, "xy.XYDotRenderer"						, "XY"					, "XY"			}
		  , {  "XYError"				, "xy.XYErrorRenderer"						, "XY"					, "XY"			}
		  , {  "XYLine3D"				, "xy.XYLine3DRenderer" 					, "XY"					, "XY"			}
		  , {  "XYLineAndShape"			, "xy.XYLineAndShapeRenderer"				, "XY"					, "XY"			}
		  , {  "XYStepArea"				, "xy.XYStepAreaRenderer"					, "XY"					, "XY"			}
		  , {  "XYStep"					, "xy.XYStepRenderer"						, "XY"					, "XY"			}
		  , {  "PolarItem" 				, "DefaultPolarItemRenderer"				, "XY"					, "Polar"		}

		  , {  "Meter" 					,  null 									, "Value"				, "Meter"		}
		  , {  "Thermometer"			,  null 									, "Value"				, "Thermometer"	}
		  , {  "Compass"				,  null 									, "Value"				, "Compass"		}

		  , {  "Gantt" 					, "category.GanttRenderer"					, "TaskSeries"			, "Time"		}

		  , {  "XYBarV" 				, "xy.XYBarRenderer"						, "TimeSeries"			, "XYTime"		}
		  , {  "ClusteredXYBarV"		, "xy.ClusteredXYBarRenderer"				, "TimeSeries"			, "XYTime"		}
		  , {  "YIntervalV" 			, "xy.YIntervalRenderer"					, "TimeSeries"			, "XYTime"		}
		  , {  "DeviationV" 			, "xy.DeviationRenderer"					, "TimeSeries"			, "XYTime"		}
		  , {  "TimeSeriesBarV"			, "xy.XYBarRenderer"						, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "TimeSeriesBarH"			, "xy.XYBarRenderer"						, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "TimeSeriesLineV"		, "xy.StandardXYItemRenderer"				, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "TimeSeriesLineH"		, "xy.StandardXYItemRenderer"				, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "StackedTimeSeriesLineV"	, "xy.StandardXYItemRenderer"				, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "StackedTimeSeriesLineH"	, "xy.StandardXYItemRenderer"				, "TimeSeries"			, "XYTime"		}	// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		  , {  "TimeStepV"				, "xy.XYStepRenderer"						, "TimeSeries"			, "XYTime"		}	// 5.9.17.1 (2017/02/10) step追加
		  , {  "TimeStepH"				, "xy.XYStepRenderer"						, "TimeSeries"			, "XYTime"		}	// 5.9.17.1 (2017/02/10) step追加
		};

		for( int i=0; i<data.length; i++ ) {
			TYPE_RENDERER_MAP.put( data[i][0],new TypeRenderer( data[i][0],data[i][1],data[i][2],data[i][3] ) );
		}
	}

	/**
	 * デフォルトコンストラクタを private 化しておきます。
	 *
	 */
	private ChartFactory() {}

	/**
	 * Connection と query 文字列から、Dataset オブジェクトを作成します。
	 *
	 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
	 * より、対象とするチャート特性を取得します。(getTypeRenderer)
	 * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスは、
	 * "org.jfree.data.jdbc.JDBC****Dataset" の **** の箇所を特定します。
	 * 現状は、Category , ParetoCategory , Pie , XY の３種類 ＋ Valueデータセットが選択されます。
	 *
	 * @og.rev 3.8.9.2 (2007/07/28) HybsJDBCCategoryDataset 追加
	 * @og.rev 5.3.0.0 (2010/12/01) その他のDataset 追加
	 * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加
	 * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
	 * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
	 * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加
	 *
	 * @param	conn	Dataset の取得先のコネクション
	 * @param	query 	取得するクエリー文字列
	 * @param	type	Dataset オブジェクトの作成元を求めるキーワード
	 * @param	lbls	シリーズのラベル名配列
	 * @param	useCateColor	カテゴリのカラー名指定 [false:指定しない/true:指定する]
	 *
	 * @return	Datasetオブジェクト
	 *
	 * @see     #getTypeRenderer( String )
	 * @see     #newDataset( DBTableModel ,String ,String[] ,boolean )
	 * @throws SQLException データベースアクセスエラー
	 */
	public static Dataset newDataset( final Connection conn,final String query,
									  final String type,final String[] lbls,final boolean useCateColor )
									throws SQLException {
		final Dataset dataset ;

		final TypeRenderer rend = getTypeRenderer( type );

		final String dsType = rend.getDatasetType();
	 	// 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
		final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType );
		if( "Category".equalsIgnoreCase( dsType ) || isPareto ) {
			final HybsCategoryDataset hData = new HybsCategoryDataset();
			hData.initParam( lbls,useCateColor,isPareto );
			hData.execute( conn, query );
			dataset = hData ;
		}
		else if( "XY".equalsIgnoreCase( dsType ) ) {
			dataset = new JDBCXYDataset( conn, query );
		}
		else if( "Pie".equalsIgnoreCase( dsType ) ) {
			dataset = new JDBCPieDataset( conn, query );
		}
		else if( "Value".equalsIgnoreCase( dsType ) ) {
			dataset = new DefaultValueDataset();
		}
		// 5.3.0.0 (2010/12/01) その他のDataset 追加
	//	else if( "GanttCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new HybsJDBCCategoryDataset2( conn, query );		// 代替
	//	}
	//	else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new HybsJDBCCategoryDataset2( conn, query );		// 代替
	//	}
	//	else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new HybsJDBCCategoryDataset2( conn, query );		// 代替
	//	}
		else if( "TimeSeries".equalsIgnoreCase( dsType ) ) {
			dataset = new HybsTimeSeriesCollection( type  );					// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
			((HybsTimeSeriesCollection)dataset).executeQuery( conn, query );
		}
		else if( "TaskSeries".equalsIgnoreCase( dsType ) ) {
			dataset = new HybsTaskSeriesCollection();							// 5.6.1.0 (2013/02/01) タスク情報を持つチャート
			((HybsTaskSeriesCollection)dataset).executeQuery( conn, query );
		}
		else {
			final String errMsg = "Category,ParetoCategory,Pie,XY,Value,TimeSeries 以外のDataset はサポートしていません。[" + dsType + "]";
			throw new HybsSystemException( errMsg );
		}

		return dataset ;
	}

	/**
	 * DBTableModelオブジェクトから、Dataset オブジェクトを作成します。
	 *
	 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
	 * より、対象とするチャート特性を取得します。(getTypeRenderer)
	 * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスを作成します。
	 *
	 * 現状は、Category , ParetoCategory , Pie , XY の３種類 ＋ Valueデータセットが選択されます。
	 *
	 * ※ DBTableModel の row,col と、Dataset の row,col は、逆になっています。
	 *
	 * @og.rev 5.3.0.0 (2010/12/01) 新規追加
	 * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
	 * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
	 * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加
	 *
	 * @param	table	Dataset の取得先のテーブルモデル
	 * @param	type	Dataset オブジェクトの作成元を求めるキーワード
	 * @param	lbls	シリーズのラベル名配列
	 * @param	useCateColor	カテゴリのカラー名指定 [false:指定しない/true:指定する]
	 *
	 * @return	Datasetオブジェクト
	 *
	 * @see     #getTypeRenderer( String )
	 * @see     #newDataset( Connection ,String ,String ,String[] ,boolean )
	 */
	public static Dataset newDataset( final DBTableModel table , 
									  final String type,final String[] lbls,final boolean useCateColor ) {
		final Dataset dataset ;

		final TypeRenderer rend = getTypeRenderer( type );
		final int clmNo = table.getColumnCount();
		final int rowNo = table.getRowCount();

		final String dsType = rend.getDatasetType();
	 	// 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
		final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType );
		if( "Category".equalsIgnoreCase( dsType ) || isPareto ) {
			// select key,val1,val2,val3 ･･･ from ･･･

			final String[] seri = getSeriesLabels( table,lbls );		// 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加

			final HybsCategoryDataset hData = new HybsCategoryDataset();
			hData.initParam( seri,useCateColor,isPareto );
			hData.execute( table );
			dataset = hData ;

		}
		else if( "XY".equalsIgnoreCase( dsType ) ) {
			// select valx,valy from ･･･

			final CategoryTableXYDataset xyDataset = new CategoryTableXYDataset() ;
	 		// 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
			final String[] seri = getSeriesLabels( table,lbls );		// 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加

			for( int row=0; row<rowNo; row++ ) {
				final String[] vals   = table.getValues( row );
				final double rval = vals[0] == null || vals[0].isEmpty() ? 0.0d : Double.parseDouble( vals[0] );		// 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
				for( int clm=1; clm<clmNo; clm++ ) {		// ２番目(アドレス=1)からカラムデータを取得
					final String sval = vals[clm];
					final double val  = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ;		// 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
					xyDataset.add( rval,val,seri[clm] );
				}
			}

			dataset = xyDataset;
		}
		else if( "Pie".equalsIgnoreCase( dsType ) ) {
			// select key,val from ･･･

			final DefaultKeyedValues keyVal = new DefaultKeyedValues();
			for( int row=0; row<rowNo; row++ ) {
				final String[] vals   = table.getValues( row );

				final String key  = vals[0];	// KEY項目
				final String sval = vals[1];	// VALUE項目
				final double val = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ;		// 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
				keyVal.addValue( key ,val );
			}
			dataset = new DefaultPieDataset( keyVal );
		}
		else if( "Value".equalsIgnoreCase( dsType ) ) {
			// Value は、オブジェクトを作成するだけ。値は、markValues を ChartDataset.java で設定
			dataset = new DefaultValueDataset();
		}
		// 5.3.0.0 (2010/12/01) その他のDataset 追加
	//	else if( "GanttCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new TaskSeriesCollection();
	//	}
	//	else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new DefaultIntervalCategoryDataset( String[] seriesNames, Number[][] starts, Number[][] ends) ;
	//	}
	//	else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) {
	//		dataset = new DefaultStatisticalCategoryDataset();
	//	}
	//	else if( "Wind".equalsIgnoreCase( dsType ) ) {
	//		dataset = new DefaultWindDataset(java.lang.String[] seriesNames, java.lang.Object[][][] data);
	//	}
	//	else if( "OHLC".equalsIgnoreCase( dsType ) ) {
	//		dataset = new DefaultOHLCDataset(java.lang.Comparable key, OHLCDataItem[] data);
	//	}
	//	else if( "BoxAndWhiskerXY".equalsIgnoreCase( dsType ) ) {
	//		dataset = new org.jfree.data.statistics.DefaultBoxAndWhiskerXYDataset(java.lang.Comparable seriesKey);
	//	}
	//	else if( "WaferMap".equalsIgnoreCase( dsType ) ) {
	//		dataset = new JDBCXYDataset( conn, query );
	//	}
	//	else if( "float2".equalsIgnoreCase( dsType ) ) {
	//		float[][] を返すので、ここでは使えない。
	//	}
		else {
			final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。[" + dsType + "]";
			throw new HybsSystemException( errMsg );
		}

		return dataset ;
	}

	/**
	 * Datasetオブジェクトのデータ件数を返します。
	 *
	 * org.jfree.data.general.Dataset には、共通に利用できる件数取得のメソッドが定義されていません。
	 * なので、個々のクラスごとに、取得します。
	 * ChartFactory に持っているのは、このクラスで、Dataset の実態を作成している関係上、
	 * 新しいクラスを追加時に、このメソッドの手直しが必要になるからです。
	 *
	 * @og.rev 6.9.7.0 (2018/05/14) データ０件の対応。
	 *
	 * @param	dataset Datasetオブジェクト
	 * @return	データ件数
	 */
	public static int getRowCount( final Dataset dataset ) {
		if( dataset == null ) {
			return 0;
		}
		else if( dataset instanceof CategoryDataset ) {
			return ((CategoryDataset)dataset).getRowCount();
		}
		else if( dataset instanceof XYDataset ) {
			final XYDataset xyData = (XYDataset)dataset;
			int cnt = 0;
			for( int i=0; i<xyData.getSeriesCount(); i++ ) {
				for( int j=0; j<xyData.getItemCount( i ); j++ ) {
					cnt++ ;
				}
			}

			return cnt;
		}
		else if( dataset instanceof Values ) {
			return ((Values)dataset).getItemCount();
		}
		else if( dataset instanceof Value ) {
			return ((Value)dataset).getValue() == null ? 0 : 1 ;
		}
		else {
			final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。" + dataset.getClass();
			throw new HybsSystemException( errMsg );
		}
	}

	/**
	 * シリーズのラベル名配列を作成します。
	 * 
	 * シリーズのラベル名配列が null でない場合は、その配列から、そうでない場合は、
	 * DBTableModelオブジェクトから、ラベル名配列を作成します。
	 *
	 * シリーズのラベル名配列追加引数は、DBTableModelオブジェクトのカラム数ー１ でなければなりません。
	 * シリーズのラベルは、以前は、テーブルのカラムそのものでしたが、リソースを経由したラベルに変更します。
	 * また、ここで返すラベルの配列は、ゼロ番目が、カラム順の１番目になります。
	 * カラムの０番目は、カテゴリなので、シリーズのラベル名としては使用しません。
	 * COLOR対応の場合は、最後のカラムが、色コードになり、ラベルとしては使いませんが、
	 * ここで作成する配列には、含まれます。利用する側で、COLORの場合は、無視するだけです。
	 *
	 * @og.rev 6.0.2.0 (2014/09/19) 新規追加
	 *
	 * @param	table	Datasetの取得先のテーブルモデル
	 * @param	lbls	0から始まるシリーズのラベル名配列(可変長引数)
	 *
	 * @return	カラム名の配列(0...)(ラベル化されている)
	 */
	private static String[] getSeriesLabels( final DBTableModel table , final String... lbls ) {
		final int clmNo = table.getColumnCount();

		// 6.0.2.0 (2014/09/19) シリーズのラベル名配列を使うときは、必ずカラム数ー１以上必要
		// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
		if( lbls != null && lbls.length < clmNo-1 ) {
				final String errMsg = "seriesLabels を使用する場合は、必ず(カラム数ー１)以上にしてください。"
							+ CR
							+ " seriesLabels.length=" + lbls.length
							+ " columnCount=" + clmNo
							+ CR
							+ " seriesLabels=" + Arrays.toString( lbls )
							+ CR ;
			throw new IllegalArgumentException( errMsg );
		}

		String[] series = new String[clmNo-1];
		for( int i=0; i<clmNo-1; i++ ) {
			// 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
			// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
			series[i] = lbls == null || lbls[i] == null ? table.getColumnLabel(i+1) : lbls[i];
		}
		return series;
	}

	/**
	 * TypeRenderer オブジェクトを作成します。
	 *
	 * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
	 * より、対象とするチャート特性を取得します。
	 * typeは、org.jfree.chart.renderer.XXXX.YYYYRenderer のYYYY とほぼ一致します。
	 * TYPE_RENDERER_MAP マップには、XXXX.YYYYRenderer 部分が定義されています。
	 * XXXX は、category と xy が定義されており、それ以外のレンデラーは null に
	 * なっています。Pie 関係は、レンデラーではなく、Plot と対応します。
	 * ただし、個々に設定情報が異なる為、ChartPlot_Pie クラスで個別対応しています。
	 *
	 * @param	type	Rendererオブジェクトの作成元を求めるキーワード
	 *
	 * @return	TypeRendererオブジェクト
	 */
	public static TypeRenderer getTypeRenderer( final String type ) {
		final TypeRenderer rend = TYPE_RENDERER_MAP.get( type );

		if( rend == null ) {
			final String errMsg = "指定のタイプに該当する Renderer はサポートしていません。[" + type + "]"
					+ CR
					+ "Key=" + Arrays.toString( TYPE_RENDERER_MAP.keySet().toArray( new String[TYPE_RENDERER_MAP.size()] ) );
			throw new HybsSystemException( errMsg );
		}

		return rend ;
	}

	/**
	 * ChartPlot オブジェクトを作成します。
	 *
	 * ChartPlot オブジェクトは、ChartPlot インターフェースを継承した
	 * サブクラスで、"org.opengion.hayabusa.io.ChartPlot_**** になります。
	 * **** には、Category , Pie , XY が指定できます。
	 *
	 * @og.rev 4.0.0.0 (2007/11/29) ChartPlot のサブクラスを動的に作成、キャッシュします。
	 * @og.rev 5.3.0.0 (2010/12/01) xxxPlot対応
	 * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加
	 *
	 * @param	type	Rendererオブジェクトの作成元を求めるキーワード
	 *
	 * @return	ChartPlotオブジェクト
	 */
	public static ChartPlot newChartPlot( final String type ) {

		final ChartPlot plot ;

		final TypeRenderer rend = TYPE_RENDERER_MAP.get( type );

		final String pltType = rend.getPlotType();			// 5.3.0.0 (2010/12/01) xxxPlot対応
		if( "Category".equalsIgnoreCase( pltType ) ) {
			synchronized( LOCK ) {
				if( plotCAT == null ) {
					plotCAT = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
				}
			}
			plot = plotCAT;
		}
		else if( "XY".equalsIgnoreCase( pltType ) ) {
			synchronized( LOCK ) {
				if( plotXY == null ) {
					plotXY = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
				}
			}
			plot = plotXY;
		}
		// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		else if( "Time".equalsIgnoreCase( pltType ) ) {
			synchronized( LOCK ) {
				if( plotTIM == null ) {
					plotTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
				}
			}
			plot = plotTIM;
		}
		// 5.6.1.0 (2013/02/01) 時間軸を持つチャート
		else if( "XYTime".equalsIgnoreCase( pltType ) ) {
			synchronized( LOCK ) {
				if( plotXTIM == null ) {
					plotXTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
				}
			}
			plot = plotXTIM;
		}
		else {
			synchronized( LOCK ) {
				if( plotPIE == null ) {
					plotPIE = (ChartPlot)StringUtil.newInstance( PLOT_SUB + "Pie" ) ;
				}
			}
			plot = plotPIE;
		}

		return plot ;
	}
}
