/*
 * 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.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.CategoryItemRendererState;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.GradientPaintTransformer;
import org.jfree.ui.RectangleEdge;

/**
 * HybsBarRenderer は、org.jfree.chart.renderer.category.BarRenderer を
 * 拡張したカスタマイズクラスです。
 * これは、描画に対して、予め制限を設けて、処理速度の向上を図っています。
 *
 * @og.rev 4.1.1.0 (2008/02/04) 新規作成
 *
 * @version  0.9.0	2001/05/05
 * @author	 Kazuhiko Hasegawa
 * @since	 JDK1.1,
 */
public class HybsBarRenderer extends BarRenderer implements HybsDrawItem {
	private static final long serialVersionUID = 4110L ;

	private boolean isItemLabelLastVisible = false;	// 4.1.2.0 (2008/03/12)
	private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ;	// 5.1.9.0 (2010/08/01) equals,hashCode

	// 4.3.4.4 (2009/01/01)
//	/**
//	 * Creates a new bar renderer with default settings.
//	 */
//	public HybsBarRenderer() {
//		super();
//	}

	/**
	 * itemLabelVisible 時に、最後の値のみ表示するかどうか[true:有効/false:無効]を指定します。
	 *
	 * これは、itemLabelVisible 属性に、"last" という設定値を指定した場合は、
	 * 最後のみラベル表示します。
	 * このメソッドでは、true が指定された場合は、"last" 属性が有効になったと
	 * 判断します。
	 *
	 * @og.rev 4.1.2.0 (2008/03/12) 新規追加
	 *
	 * @param	flag	最後の値のみ表示するかどうか[true:有効/false:無効]
	 */
	public void setItemLabelLastVisible( final boolean flag ) {
		isItemLabelLastVisible = flag;
	}

	/**
	 * drawItem と同等の機能を持った、高速版メソッドです。
	 *
	 * @og.rev 4.1.1.0 (2008/02/04) 新規追加
	 * @og.rev 4.1.2.0 (2008/03/12) ラベルのアンダーライン時にItemLavelを表示しない
	 *
	 * @param g2			Graphics2Dオブジェクト
	 * @param state			CategoryItemRendererStateオブジェクト
	 * @param dataArea		Rectangle2Dオブジェクト
	 * @param plot			CategoryPlotオブジェクト
	 * @param domainAxis	CategoryAxisオブジェクト
	 * @param rangeAxis		ValueAxisオブジェクト
	 * @param dataset		CategoryDatasetオブジェクト
	 * @param serNo			シリアル番号
	 */
	public void drawItem2( final Graphics2D g2, final CategoryItemRendererState state,
			final Rectangle2D dataArea, final CategoryPlot plot, final CategoryAxis domainAxis,
			final ValueAxis rangeAxis, final CategoryDataset dataset, final int serNo ) {

		int clmCount = dataset.getColumnCount();
		int rowCount = dataset.getRowCount();
		RectangleEdge edge = plot.getRangeAxisEdge();

		PlotOrientation orientation = plot.getOrientation();
		double minBarLen = getMinimumBarLength();
		double barWidth  = state.getBarWidth();
		boolean isDrawOutline = isDrawBarOutline() &&
									state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD ;

		// 4.1.2.0 (2008/03/12)
		HybsCategoryAxis hybsAxis = null;
		if( domainAxis instanceof HybsCategoryAxis ) {
			hybsAxis = (HybsCategoryAxis)domainAxis;
			hybsAxis.setItemLabelLastVisible( isItemLabelLastVisible );
		}

		for( int row=0; row<rowCount; row++ ) {
			boolean isItemLabelsVisible = isSeriesItemLabelsVisible( row );

			for( int column=0; column<clmCount; column++ ) {
				Number v1Num = dataset.getValue( row,column );
				if(v1Num == null) { continue; }
				double value = v1Num.doubleValue();

				// 書き出し開始位置をずらす。
				double barW0 = calculateBarW0( plot,orientation,dataArea,domainAxis,state,row,column );
				double[] barL0L1 = calculateBarL0L1( value );
				if (barL0L1 == null) { continue; }

				double transL0 = rangeAxis.valueToJava2D( barL0L1[0],dataArea,edge );
				double transL1 = rangeAxis.valueToJava2D( barL0L1[1],dataArea,edge );
				double barL0 = Math.min( transL0,transL1 );
				double barLength = Math.max( Math.abs( transL1 - transL0 ),minBarLen );

				// Bar の描画
				Rectangle2D bar = null;
				if( orientation == PlotOrientation.HORIZONTAL ) {
					bar = new Rectangle2D.Double( barL0,barW0,barLength,barWidth );
				}
				else {
					bar = new Rectangle2D.Double( barW0,barL0,barWidth,barLength );
				}

				Paint itemPaint = getItemPaint( row,column );
				// 4.3.1.1 (2008/08/23) 変数名を t ⇒ gpt に変更
				GradientPaintTransformer gpt = getGradientPaintTransformer();
				if( gpt != null && itemPaint instanceof GradientPaint ) {
					itemPaint = gpt.transform( (GradientPaint) itemPaint,bar );
				}
				g2.setPaint( itemPaint );
				g2.fill( bar );

				// outline の描画
				if( isDrawOutline ) {
					Stroke stroke = getItemOutlineStroke( row,column );
					Paint paint = getItemOutlinePaint( row,column );
					if( stroke != null && paint != null ) {
						g2.setStroke( stroke );
						g2.setPaint( paint );
						g2.draw( bar );
					}
				}

				// ItemLabel の描画
				CategoryItemLabelGenerator generator = getItemLabelGenerator( row,column );
				if( generator != null && isItemLabelsVisible ) {
					// 4.1.2.0 (2008/03/12) アンダースコアの場合は、表示しない。
					if( hybsAxis != null && hybsAxis.isViewItemLabel( column ) ) {
						drawItemLabel( g2,dataset,row,column,plot,generator,bar,(value < 0.0) );
					}
				}
				// 4.3.1.0 (2008/08/09) item entity の追加
				EntityCollection entities = state.getEntityCollection();
				if( entities != null ) {
					addItemEntity( entities, dataset, row, column, bar );
				}
			}
		}
	}

	/**
	 * この文字列と指定されたオブジェクトを比較します。
	 *
	 * 親クラスで、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 ) {
//		return super.equals( object );
		if( super.equals( object ) ) {
			return hsCode == ((HybsBarRenderer)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	ハッシュコード
	 */
//	public int hashCode() { return super.hashCode() ; }
	@Override
	public int hashCode() { return hsCode ; }

	/**
	 * このオブジェクトと指定されたオブジェクトを比較します。
	 *
	 * @og.rev 4.3.1.1 (2008/08/23) 新規追加
	 * @og.rev 5.1.8.0 (2010/07/01) 廃止
	 *
	 * @param anObject Object 比較されるオブジェクト
	 *
	 * @return	指定されたオブジェクトが等しい場合は true、そうでない場合は false
	 */
//	public boolean equals( final Object anObject ) {
//		if( super.equals( anObject ) ) {
//			HybsBarRenderer other = ((HybsBarRenderer)anObject);
//			return ( isItemLabelLastVisible == other.isItemLabelLastVisible );
//		}
//		return false;
//	}

	/**
	 * このオブジェクトのハッシュコードを返します。
	 *
	 * @og.rev 4.3.1.1 (2008/08/23) 新規追加
	 * @og.rev 5.1.8.0 (2010/07/01) 廃止
	 *
	 * @return	このオブジェクトのハッシュコード値
	 */
//	public int hashCode() {
//		return super.hashCode() + ( (isItemLabelLastVisible) ? 1 : 0 );
//	}
}
