/***********************************************************************************************
 * File Info: $Id: YAxis.java,v 1.24 2003/06/29 13:28:37 nathaniel_auvil Exp $
 * Copyright (C) 2002
 * Author: Nathaniel G. Auvil
 * Contributor(s): John Thomsen
 *
 * Copyright 2002 (C) Nathaniel G. Auvil. All Rights Reserved.
 *
 * Redistribution and use of this software and associated documentation ("Software"), with or
 * without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain copyright statements and notices.
 * 	Redistributions must also contain a copy of this document.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
 * 	conditions and the following disclaimer in the documentation and/or other materials
 * 	provided with the distribution.
 *
 * 3. The name "jCharts" or "Nathaniel G. Auvil" must not be used to endorse or promote
 * 	products derived from this Software without prior written permission of Nathaniel G.
 * 	Auvil.  For written permission, please contact nathaniel_auvil@users.sourceforge.net
 *
 * 4. Products derived from this Software may not be called "jCharts" nor may "jCharts" appear
 * 	in their names without prior written permission of Nathaniel G. Auvil. jCharts is a
 * 	registered trademark of Nathaniel G. Auvil.
 *
 * 5. Due credit should be given to the jCharts Project (http://jcharts.sourceforge.net/).
 *
 * THIS SOFTWARE IS PROVIDED BY Nathaniel G. Auvil AND CONTRIBUTORS ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 * jCharts OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
 ************************************************************************************************/


package org.jCharts.axisChart.axis;


import org.jCharts.axisChart.AxisChart;
import org.jCharts.properties.*;
import org.jCharts.properties.util.ChartFont;
import org.jCharts.test.HTMLGenerator;
import org.jCharts.test.HTMLTestable;

import java.awt.*;
import java.awt.geom.Line2D;
import java.lang.reflect.Field;


public final class YAxis extends Axis implements HTMLTestable
{

   private float lastTickY;


	/**************************************************************************************************
	 * Constructor
	 *
	 * @param axisChart
	 ***************************************************************************************************/
	public YAxis( AxisChart axisChart, int numberOfScaleItems )
	{
		super( axisChart, numberOfScaleItems );
	}


	/************************************************************************************
	 * Need this value as horizontal plots start from the top of the axis and go down
	 *
	 * @return
	 ************************************************************************************/
	public float getLastTickY()
	{
		return lastTickY;
	}


	/*************************************************************************************************
	 * Computes the minimum pixel width required for the Y-Axis.
	 *  Includes space, if needed, for: axis title + padding, axis values + tick padding, and tick marks.
	 *
	 **************************************************************************************************/
	public void computeMinimumWidthNeeded( String yAxisTitle )
	{
		AxisTypeProperties axisTypeProperties= super.getAxisChart().getAxisProperties().getYAxisProperties();


		float widthNeeded = 0;


		//---if we are displaying axis scale labels, add width of widest label
		if( axisTypeProperties.showAxisLabels() )
		{
			widthNeeded+= super.getAxisLabelsGroup().getWidestLabel();
		}


		if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
		{
			//---add the padding between scale labels and tick marks
			widthNeeded += axisTypeProperties.getPaddingBetweenLabelsAndTicks();

			//---add width of tick marks
			widthNeeded += axisTypeProperties.getAxisTickMarkPixelLength();
		}
		else
		{
			//---else, if we are not showing any ticks, add padding between labels and axis, if we are displaying labels
			if( axisTypeProperties.showAxisLabels() )
			{
				widthNeeded += axisTypeProperties.getPaddingBetweenAxisAndLabels();
			}
		}


		//---include axis title height if needed. Remember it is vertical for y-axis
		//if( super.getAxisChart().getAxisProperties().getShowAxisTitle( AxisProperties.Y_AXIS ) )
		if( yAxisTitle != null )
		{
			super.computeAxisTitleDimensions( yAxisTitle, axisTypeProperties.getTitleChartFont() );
			widthNeeded += super.getTitleHeight();
			widthNeeded += axisTypeProperties.getPaddingBetweenAxisTitleAndLabels();
		}

		super.setMinimumWidthNeeded( widthNeeded );
	}


	/****************************************************************************************************
	 *
	 * @param axisTitle
	 * @param graphics2D
	 * @param axisTypeProperties
	 ***************************************************************************************************/
	private void renderAxisTitle( String axisTitle, Graphics2D graphics2D, AxisTypeProperties axisTypeProperties )
	{
		if( axisTitle != null )
		{
			float titleY; // = super.getAxisChart().getChartProperties().getEdgePadding();
			float titleX = super.getAxisChart().getXAxis().getOrigin() - super.getMinimumWidthNeeded() + super.getTitleHeight();

			//---if YAxis title is larger than the YAxis itself, center it on image.
			if( super.getTitleWidth() > super.getPixelLength() )
			{
				//titleY= super.getTitleWidth();
				titleY= super.getAxisChart().getImageHeight() - ( ( super.getAxisChart().getImageHeight() - super.getTitleWidth() ) / 2 );
			}
			//---else, center on YAxis.
			else
			{
				titleY = this.getOrigin() - ( ( super.getPixelLength() - super.getTitleWidth() ) / 2 );
			}

//TODO this should use a TextTag
			graphics2D.setFont( axisTypeProperties.getAxisTitleChartFont().getFont().deriveFont( ChartFont.VERTICAL_ROTATION ) );
			graphics2D.setPaint( axisTypeProperties.getAxisTitleChartFont().getPaint() );
			graphics2D.drawString( axisTitle, titleX, titleY );
		}
	}


	/*********************************************************************************************
	 * Renders the YAxis on the passes Graphics2D object
	 *
	 * @param graphics2D
	 * @param axisProperties
	 * @param yAxisTitle
	 **********************************************************************************************/
	public void render( Graphics2D graphics2D, AxisProperties axisProperties, String yAxisTitle )
	{
		AxisTypeProperties axisTypeProperties = axisProperties.getYAxisProperties();


		//---AXIS TITLE
		this.renderAxisTitle( yAxisTitle, graphics2D, axisProperties.getYAxisProperties() );


		Line2D.Float line2D;
		float stringY= 0;


		if( axisTypeProperties instanceof DataAxisProperties )
		{
			//---start at the axis
			line2D = new Line2D.Float( 0.0f, super.getOrigin(), 0.0f, super.getOrigin() );

			if( axisTypeProperties.showAxisLabels() )
			{
				stringY = super.getOrigin() + ( super.getAxisLabelsGroup().getTallestLabel() / 4 );
			}
		}
		else
		{
			//--start at half a axis item width
			float y = super.getOrigin() - ( super.getScalePixelWidth() / 2 );
			line2D = new Line2D.Float( 0.0f, y, 0.0f, y );

			if( axisTypeProperties.showAxisLabels() )
			{
				stringY = y + ( super.getAxisLabelsGroup().getTallestLabel() / 4 );

				//---horizontal plots start at top of axis and go down
				super.getAxisLabelsGroup().reverse();
			}
		}


		float tickX1 = super.getAxisChart().getXAxis().getOrigin() - axisTypeProperties.getAxisTickMarkPixelLength();
		float tickX2 = super.getAxisChart().getXAxis().getOrigin();
		float gridLineX1 = super.getAxisChart().getXAxis().getOrigin() + 1;
		float gridLineX2 = super.getAxisChart().getXAxis().getOrigin() + super.getAxisChart().getXAxis().getPixelLength();


		float stringX = super.getAxisChart().getXAxis().getOrigin() - axisTypeProperties.getAxisTickMarkPixelLength();

		if( axisTypeProperties.showAxisLabels() )
		{
			stringX-= axisTypeProperties.getPaddingBetweenLabelsAndTicks();
		}


		for( int i = 0; i < super.getNumberOfScaleItems(); i++ )
		{
			//---GRID LINES
			if( axisTypeProperties.getShowGridLines() != AxisTypeProperties.GRID_LINES_NONE )
			{
				//---we do not want to draw a grid line over the axis as data axis first value is on the axis
				if( i > 0 || ( i == 0 && !( axisTypeProperties instanceof DataAxisProperties ) ) )
				{
					line2D.x1 = gridLineX1;
					line2D.x2 = gridLineX2;

					//TODO what is this doing????  How could i ever equal the size?

					if( i < super.getAxisLabelsGroup().size()
						|| ( i == super.getAxisLabelsGroup().size() && !axisTypeProperties.getShowEndBorder() ) )

//					if( i == super.getNumberOfScaleItems() - 1 && !axisTypeProperties.getShowEndBorder() )
					{
						axisTypeProperties.getGridLineChartStroke().draw( graphics2D, line2D );
					}
					else
					{
						//---draw top border with the same ChartStroke as the X-Axis
						axisProperties.getXAxisProperties().getAxisStroke().draw( graphics2D, line2D );
					}
				}
			}

			//---TICK MARKS
			if( axisTypeProperties.getShowTicks() != AxisTypeProperties.TICKS_NONE )
			{
				line2D.x1 = tickX1;
				line2D.x2 = tickX2;
				axisTypeProperties.getTickChartStroke().draw( graphics2D, line2D );
			}

			//---need this value as horizontal plots start from the top of the axis and go down
			//---must set this no matter if no ticks are present as horizontal plots start their rendering based on this screen coordinate.
			this.lastTickY= line2D.y1;

			line2D.y1 -= super.getScalePixelWidth();
			line2D.y2 = line2D.y1;


			//---AXIS LABEL
			if( axisTypeProperties.showAxisLabels() )
			{
				super.getAxisLabelsGroup().render( i, graphics2D, stringX - super.getAxisLabelsGroup().getTextTag( i ).getWidth(), stringY );
				//graphics2D.setPaint( axisProperties.getScaleFontColor() );
				//graphics2D.drawString( this.formattedLabels[ i ], stringX - this.labelWidths[ i ], stringY );
			}

			stringY -= super.getScalePixelWidth();
		}


		//---AXIS----------------------------------------------------------------------
		line2D.x1 = super.getAxisChart().getXAxis().getOrigin();
		line2D.x2 = line2D.x1;
		line2D.y1 = super.getOrigin() - super.getPixelLength();
		line2D.y2 = super.getOrigin();
		axisTypeProperties.getAxisStroke().draw( graphics2D, line2D );


		//---TOP BORDER----------------------------------------------------------------
		if( axisTypeProperties.getShowEndBorder() )
		{
			line2D.x1 = super.getAxisChart().getXAxis().getOrigin();
			line2D.x2 = super.getAxisChart().getXAxis().getOrigin() + super.getAxisChart().getXAxis().getPixelLength();
			line2D.y1 = super.getOrigin() - super.getPixelLength();
			line2D.y2 = line2D.y1;
			axisProperties.getXAxisProperties().getAxisStroke().draw( graphics2D, line2D );
		}


		//---ZERO LINE-----------------------------------------------------------------
		if( axisTypeProperties instanceof DataAxisProperties )
		{
			DataAxisProperties dataAxisProperties = ( DataAxisProperties ) axisTypeProperties;

			if( dataAxisProperties.showZeroLine()
				&& super.getScaleCalculator().getMinValue() < 0.0d
				&& super.getScaleCalculator().getMaxValue() > 0.0d )
			{
				line2D.y1 = super.getZeroLineCoordinate();
				line2D.y2 = line2D.y1;
				line2D.x1 = super.getAxisChart().getXAxis().getOrigin();
				line2D.x2 = super.getAxisChart().getXAxis().getOrigin() + super.getAxisChart().getXAxis().getPixelLength();
				dataAxisProperties.getZeroLineChartStroke().draw( graphics2D, line2D );
			}
		}
	}


	/*************************************************************************************************
	 * Takes a value and determines the screen coordinate it should be drawn at. THe only difference
	 * 	between this and the x-axis is we subtract to the origin versus subtract from it.

	 *
	 * @param origin
	 * @param value
	 * @param axisMinValue the minimum value on the axis
	 * @return float the screen pixel coordinate
	 **************************************************************************************************/
	public float computeAxisCoordinate( float origin, double value, double axisMinValue )
	{
		double returnValue = origin - ( value - axisMinValue ) * this.getOneUnitPixelSize();
		return ( float ) returnValue;
	}


	/*********************************************************************************************
	 * Enables the testing routines to display the contents of this Object.
	 *
	 * @param htmlGenerator
	 **********************************************************************************************/
//todo is this method needed?
	public void toHTML( HTMLGenerator htmlGenerator )
	{
		htmlGenerator.propertiesTableStart( this.getClass().getName() );

		super.toHTML( htmlGenerator );

		Field[] fields = this.getClass().getDeclaredFields();
		for( int i = 0; i < fields.length; i++ )
		{
			try
			{
				htmlGenerator.addField( fields[ i ].getName(), fields[ i ].get( this ) );
			}
			catch( IllegalAccessException illegalAccessException )
			{
				illegalAccessException.printStackTrace();
			}
		}

		htmlGenerator.propertiesTableEnd();
	}

}
