/*
 * 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 java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.Locale;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;

import java.awt.Color;

import org.opengion.fukurou.util.Closer;
import org.opengion.fukurou.util.LogWriter;
import org.opengion.fukurou.util.ColorMap;				// 6.0.2.1 (2014/09/26)
import org.opengion.fukurou.db.DBUtil;

import org.jfree.data.jdbc.JDBCCategoryDataset;

/**
 * HybsJDBCCategoryDataset は、org.jfree.data.jdbc.JDBCCategoryDataset を継承したサブクラスで、
 * executeQuery(Connection , String )  をオーバーライドしています。
 * 
 * series の縦持ち 対応です。
 * 
 * 通常、select category,series1,series2,series3,… from … 形式で、シリーズは、カラムとして使用されます。
 * series* には、数値が設定され、カラム名が、series 名になります。
 * この、series名を縦持ちで与える形式が、このクラスになります。
 * その結果、カラムの位置が、固定になるため、今までできなかった、category に対する色指定が可能になりました。
 *   形式①：select category,value from … 
 *   形式②：select category,series,value from … 
 *   形式③：select category,series,color,value from … 
 * 
 * 必ず、カラムは、category,series,color,value の順番で用意します。value が、一番最後です。
 * series がない場合は、category の別名ラベルがseries名になります。（形式①）
 * color は、Colorコードです。series が無くても、color を指定する場合は、必ず必要です。（形式③）
 *
 * なお、Colorコードは、このクラスで作成しますが、Renderer に与える必要があります。
 * 通常のRenderer には、categoryにカラーを指定する機能がありませんので、HybsBarRenderer に
 * 用意します。
 * categoryColor を与えるメソッドを作成し、getItemPaint( int,int ) をオーバーライドして、
 * categoryに対応したカラーを返すようにします。
 * 理論的には、カテゴリとシリーズの組み合わせで色指定も可能ですが、今回は、category のみ対象とします。
 * 処理的には、一番最初に見つかったcategoryに指定された色を採用します。
 *
 * 参考:JFreeChart : a free chart library for the Java(tm) platform(jfreechart-1.0.6)
 *
 * @og.rev 3.8.9.2 (2007/07/28) 新規作成
 * @og.rev 6.0.2.1 (2014/09/26) 新規復活(categoryにカラーを、指定する機能を用意します)
 *
 * @version  0.9.0  2001/05/05
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.1,
 */
public class HybsJDBCCategoryDataset extends JDBCCategoryDataset {
	private static final long serialVersionUID = 602120140926L ;

	private Color[]		categoryColor	= null;
	private final int	hsCode	= Long.valueOf( System.nanoTime() ).hashCode() ;	// 5.1.9.0 (2010/08/01) equals,hashCode

	/**
	 * Creates a new dataset with the given database connection, and executes
	 * the supplied query to populate the dataset.
	 *
	 * @param connection  the connection.
	 * @param query  the query.
	 *
	 * @throws SQLException if there is a problem executing the query.
	 */
	public HybsJDBCCategoryDataset( final Connection connection, final String query ) throws SQLException {
		super( connection );
		innerQuery( connection,query );
	}

	/**
	 * Populates the dataset by executing the supplied query against the
	 * existing database connection.  If no connection exists then no action
	 * is taken.
	 *
	 * The results from the query are extracted and cached locally, thus
	 * applying an upper limit on how many rows can be retrieved successfully.
	 *
	 * @param con  the connection.
	 * @param query  the query.
	 *
	 * @throws SQLException if there is a problem executing the query.
	 * @see org.jfree.data.jdbc.JDBCCategoryDataset#executeQuery(Connection , String )
	 */
	@Override
	public void executeQuery( final Connection con, final String query ) throws SQLException {
		innerQuery( con,query );
	}

	/**
	 * Populates the dataset by executing the supplied query against the
	 * existing database connection.  If no connection exists then no action
	 * is taken.
	 *
	 * The results from the query are extracted and cached locally, thus
	 * applying an upper limit on how many rows can be retrieved successfully.
	 *
	 * @og.rev 6.0.2.1 (2014/09/26) categoryにカラーを、指定する機能を用意します。
	 *
	 * @param con  the connection.
	 * @param query  the query.
	 *
	 * @throws SQLException if there is a problem executing the query.
	 * @see org.jfree.data.jdbc.JDBCCategoryDataset#executeQuery(Connection , String )
	 */
	private void innerQuery( final Connection con, final String query ) throws SQLException {

		Statement statement = null;
		ResultSet resultSet = null;

		Set<Comparable<?>>	categorySet	= null;			// カテゴリのチェック
		List<Color>			colorList	= null;			// カテゴリカラー

		try {
			statement = con.createStatement();
			resultSet = statement.executeQuery(query);
			ResultSetMetaData metaData = resultSet.getMetaData();

			int columnCount = metaData.getColumnCount();

			// 形式①：select category,value from … 
			// 形式②：select category,series,value from … 
			// 形式③：select category,series,color,value from … 

			if( columnCount < 2 ) {
				String errMsg = "JDBCCategoryDataset.executeQuery() : insufficient columns "
							+ "returned from the database. \n"
							+ " SQL=" + query ;
				throw new SQLException( errMsg );
			}

			// 形式③：select category,series,color,value from … 
			if( columnCount > 3 ) {
				categorySet = new HashSet<Comparable<?>>();		// カテゴリのチェック
				colorList	= new ArrayList<Color>();			// カテゴリカラー
			}

			// 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正)
			String series = metaData.getColumnLabel(1).toUpperCase( Locale.JAPAN );
			while (resultSet.next()) {
				// first column contains the row key...
				String category   = resultSet.getString(1);						// 最初は、category
				if( columnCount > 2 ) { series = resultSet.getString(2); }
				Object objVal     = resultSet.getObject(columnCount);			// 最後は、値
				int    columnType = metaData.getColumnType(columnCount);

				Number value = null;
				try {
					value = DBUtil.getNumber( columnType,objVal );
				}
				catch( RuntimeException ex ) {
					LogWriter.log( ex );
				}
//				setValue(value, series, category);
				addValue( value, series, category );

				// ここから、色コードを取り出して、Colorオブジェクトに変換します。
				if( columnCount > 3 ) {
					if( categorySet.add( category ) ) {		// このSetにcategoryがなければ、追加して、true を返す。
						String colStr = resultSet.getString(3);
						Color color   = ColorMap.getColorInstance( colStr );		// 6.0.2.1 (2014/09/26) StringUtil → ColorMap
						colorList.add( color );				// 初めてcategoryが発生する都度、Listに追加する。
					}
				}
			}
			// colorList が null でないかどうかで判定。
			if( colorList != null ) {
				categoryColor = colorList.toArray( new Color[colorList.size()] );
			}
		}
		finally {
			Closer.resultClose( resultSet ) ;
			Closer.stmtClose( statement ) ;
		}
	}

	/**
	 * categoryカラー配列を取得します。(独自メソッド)
	 *
	 * このクラスは、series を縦持ちするため、categoryにColorを指定できます。
	 * select文で指定されていなかった場合は、null を返します。
	 *
	 *   形式③：select category,series,color,value from … 
	 *
	 * なお、Colorコードは、このクラスで作成しますが、Renderer に与える必要があります。
	 * 通常のRenderer には、categoryにカラーを指定する機能がありませんので、HybsBarRenderer に
	 * 用意します。
	 * categoryColor を与えるメソッドを作成し、getItemPaint( int,int ) をオーバーライドして、
	 * categoryに対応したカラーを返すようにします。
	 * 理論的には、カテゴリとシリーズの組み合わせで色指定も可能ですが、今回は、category のみ対象とします。
	 * 処理的には、一番最初に見つかったcategoryに指定された色を採用します。
	 *
	 * @return	categoryカラー配列(なければ null)
	 */
	public Color[] getCategoryColor() {
		return categoryColor;
	}

	/**
	 * この文字列と指定されたオブジェクトを比較します。
	 *
	 * 親クラスで、equals メソッドが実装されているため、警告がでます。
	 *
	 * @og.rev 5.1.8.0 (2010/07/01) findbug対応
	 * @og.rev 5.1.9.0 (2010/08/01) findbug対応
	 *
	 * @param	object	比較するオブジェクト
	 *
	 * @return	Objectが等しい場合は true、そうでない場合は false
	 */
	@Override
	public boolean equals( final Object object ) {
		if( super.equals( object ) ) {
			return hsCode == ((HybsJDBCCategoryDataset)object).hsCode;
		}
		return false;
	}

	/**
	 * このオブジェクトのハッシュコードを取得します。
	 *
	 * @og.rev 5.1.8.0 (2010/07/01) findbug対応
	 * @og.rev 5.1.9.0 (2010/08/01) findbug対応
	 *
	 * @return	ハッシュコード
	 */
	@Override
	public int hashCode() { return hsCode ; }

}
