/*
 * 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 org.opengion.fukurou.util.Closer;
import org.opengion.fukurou.util.LogWriter;

import org.jfree.data.jdbc.JDBCCategoryDataset;

/**
 * HybsJDBCCategoryDataset は、org.jfree.data.jdbc.JDBCCategoryDataset を継承したサブクラスで、
 * executeQuery(Connection , String )  をオーバーライドしています。
 * これは、元のソースが、series と category の扱いが異なる為で、QUERY には、
 * select series,values from ･･･ または、select series,category,values from ･･･
 * の形式で検索することを想定した作りに修正しています。
 * series の縦持ち 対応です。
 * 参考:JFreeChart : a free chart library for the Java(tm) platform(jfreechart-1.0.6)
 *
 * @og.rev 3.8.9.2 (2007/07/28) 新規作成
 *
 * @version  0.9.0  2001/05/05
 * @author   Kazuhiko Hasegawa
 * @since    JDK1.1,
 */
public class HybsJDBCCategoryDataset extends JDBCCategoryDataset {
	private static final long serialVersionUID = 518020100701L ;

	/**
	 * 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 4.0.0.0 (2007/11/30) public な executeQuery メソッドを private 化します。
	 * @og.rev 5.1.8.0 (2010/07/01) column名は大文字化し、項目名の取得は#getColumnLabel()で行う。(PotgreSQL対応&バグ修正)
	 *
	 * @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;
		try {
			statement = con.createStatement();
			resultSet = statement.executeQuery(query);
			ResultSetMetaData metaData = resultSet.getMetaData();

			int columnCount = metaData.getColumnCount();

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

			// 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);
				Object objVal     = resultSet.getObject(columnCount);
				int    columnType = metaData.getColumnType(columnCount);

				if( columnCount > 2 ) { series = resultSet.getString(2); }

				Number value = null;
				switch (columnType) {
					case Types.TINYINT:
					case Types.SMALLINT:
					case Types.INTEGER:
					case Types.BIGINT:
					case Types.FLOAT:
					case Types.DOUBLE:
					case Types.DECIMAL:
					case Types.NUMERIC:
					case Types.REAL: {
						value = (Number)objVal;
						break;
					}
					case Types.DATE:
					case Types.TIME:
					case Types.TIMESTAMP: {
						Date date = (Date) objVal;
						value = Long.valueOf(date.getTime());
						break;
					}
					case Types.CHAR:
					case Types.VARCHAR:
					case Types.LONGVARCHAR: {
						String string = (String)objVal;
						try {
							value = Double.valueOf(string);
						}
						catch (NumberFormatException ex) {
							LogWriter.log( ex );
							// suppress (value defaults to null)
						}
						break;
					}
					default:
						// not a value, can't use it (defaults to null)
						break;
				}
				setValue(value, series, category);
			}
		}
		finally {
			Closer.resultClose( resultSet ) ;
			Closer.stmtClose( statement ) ;
		}
	}

}
