double dValue, dMinValue = Double.MAX_VALUE, dMaxValue = Double.MIN_VALUE;
double dValue, dMinValue = Double.MAX_VALUE, dMaxValue = -Double.MAX_VALUE;
	static final AutoScale computeScale( IDisplayServer xs, OneAxis ax,			DataSetIterator dsi, int iType, double dStart, double dEnd,			DataElement oMinimum, DataElement oMaximum, Double oStep,			FormatSpecifier fs, RunTimeContext rtc, boolean forward )			throws ChartException	{		final Label la = ax.getLabel( );		final int iLabelLocation = ax.getLabelPosition( );		final int iOrientation = ax.getOrientation( );		AutoScale sc = null;		AutoScale scCloned = null;		if ( ( iType & TEXT ) == TEXT || ax.isCategoryScale( ) )		{			sc = new AutoScale( iType );			sc.fs = fs;			sc.rtc = rtc;			sc.bCategoryScale = true;			sc.bAxisLabelStaggered = ax.isAxisLabelStaggered( );			sc.setData( dsi );			sc.setAlwaysForward( forward );			sc.computeTicks( xs,					ax.getLabel( ),					iLabelLocation,					iOrientation,					dStart,					dEnd,					false,					null );		}		else if ( ( iType & LINEAR ) == LINEAR )		{			Object oValue;			double dValue, dMinValue = Double.MAX_VALUE, dMaxValue = Double.MIN_VALUE;			dsi.reset( );			while ( dsi.hasNext( ) )			{				oValue = dsi.next( );				if ( oValue == null ) // NULL VALUE CHECK				{					continue;				}				dValue = ( (Double) oValue ).doubleValue( );				if ( dValue < dMinValue )					dMinValue = dValue;				if ( dValue > dMaxValue )					dMaxValue = dValue;			}			double dDelta = dMaxValue - dMinValue;			if ( dDelta == 0 ) // PREVENT INFINITE LOOP DUE TO LOG(dDelta) IN			// AUTO SCALING ALGORITHM			{				dDelta = 1;			}			final double dAbsMax = Math.abs( dMaxValue );			final double dAbsMin = Math.abs( dMinValue );			double dStep = Math.max( dAbsMax, dAbsMin );			dStep = Math.floor( Math.log( dDelta ) / LOG_10 );			dStep = Math.pow( 10, dStep );			sc = new AutoScale( iType,					new Double( 0 ),					new Double( 0 ),					new Double( dStep ) );			sc.setData( dsi );			sc.setAlwaysForward( forward );			sc.fs = fs; // FORMAT SPECIFIER			sc.rtc = rtc; // LOCALE			sc.bAxisLabelStaggered = ax.isAxisLabelStaggered( );			// OVERRIDE MINIMUM IF SPECIFIED			if ( oMinimum != null )			{				if ( oMinimum instanceof NumberDataElement )				{					sc.oMinimum = new Double( ( (NumberDataElement) oMinimum ).getValue( ) );				}				/*				 * else if (oMinimum instanceof DateTimeDataElement) {				 * sc.oMinimum = ((DateTimeDataElement)				 * oMinimum).getValueAsCDateTime(); }				 */				else				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.invalid.minimum.scale.value", //$NON-NLS-1$							new Object[]{									sc.oMinimum,									ax.getModelAxis( ).getType( ).getName( )							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}				sc.bMinimumFixed = true;			}			// OVERRIDE MAXIMUM IF SPECIFIED			if ( oMaximum != null )			{				if ( oMaximum instanceof NumberDataElement )				{					sc.oMaximum = new Double( ( (NumberDataElement) oMaximum ).getValue( ) );				}				/*				 * else if (oMaximum instanceof DateTimeDataElement) {				 * sc.oMaximum = ((DateTimeDataElement)				 * oMaximum).getValueAsCDateTime(); }				 */				else				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.invalid.maximum.scale.value", //$NON-NLS-1$							new Object[]{									sc.oMaximum,									ax.getModelAxis( ).getType( ).getName( )							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}				sc.bMaximumFixed = true;			}			// OVERRIDE STEP IF SPECIFIED			if ( oStep != null )			{				sc.oStep = oStep;				sc.bStepFixed = true;				// VALIDATE OVERRIDDEN STEP				if ( ( (Double) sc.oStep ).doubleValue( ) <= 0 )				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.invalid.step.value", //$NON-NLS-1$							new Object[]{								oStep							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}			}			// VALIDATE OVERRIDDEN MIN/MAX			if ( sc.bMaximumFixed && sc.bMinimumFixed )			{				if ( ( (Double) sc.oMinimum ).doubleValue( ) > ( (Double) sc.oMaximum ).doubleValue( ) )				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.min.largerthan.max", //$NON-NLS-1$ 							new Object[]{									sc.oMinimum, sc.oMaximum							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}			}			final Object oMinValue = new Double( dMinValue );			final Object oMaxValue = new Double( dMaxValue );			sc.updateAxisMinMax( oMinValue, oMaxValue );			sc.computeTicks( xs,					ax.getLabel( ),					iLabelLocation,					iOrientation,					dStart,					dEnd,					false,					null );			dStart = sc.dStart;			dEnd = sc.dEnd;			boolean bFirstFit = sc.checkFit( xs, la, iLabelLocation );			boolean bFits = bFirstFit;			boolean bZoomSuccess = false;			// THE AUTO ZOOM LOOP			while ( bFits == bFirstFit )			{				bZoomSuccess = true;				scCloned = (AutoScale) sc.clone( );				if ( sc.bStepFixed ) // DO NOT AUTO ZOOM IF STEP IS FIXED				{					break;				}				if ( bFirstFit )				{					if ( !bFits )					{						break;					}					bZoomSuccess = sc.zoomIn( );				}				else				{					if ( !bFits && sc.getTickCount( ) == 2 )					{						break;					}					bZoomSuccess = sc.zoomOut( );				}				if ( !bZoomSuccess )					break;				sc.updateAxisMinMax( oMinValue, oMaxValue );				sc.computeTicks( xs,						ax.getLabel( ),						iLabelLocation,						iOrientation,						dStart,						dEnd,						false,						null );				bFits = sc.checkFit( xs, la, iLabelLocation );				if ( !bFits && sc.getTickCount( ) == 2 )				{					sc = scCloned;					break;				}			}			// RESTORE TO LAST SCALE BEFORE ZOOM			if ( scCloned != null && bFirstFit && bZoomSuccess )			{				sc = scCloned;			}		}		else if ( ( iType & LOGARITHMIC ) == LOGARITHMIC )		{			Object oValue;			double dValue, dMinValue = Double.MAX_VALUE, dMaxValue = Double.MIN_VALUE;			if ( ( iType & PERCENT ) == PERCENT )			{				dMinValue = 0;				dMaxValue = 100;			}			else			{				dsi.reset( );				while ( dsi.hasNext( ) )				{					oValue = dsi.next( );					if ( oValue == null ) // NULL VALUE CHECK					{						continue;					}					dValue = ( (Double) oValue ).doubleValue( );					if ( dValue < dMinValue )						dMinValue = dValue;					if ( dValue > dMaxValue )						dMaxValue = dValue;				}			}			final Object oMinValue = new Double( dMinValue );			final Object oMaxValue = new Double( dMaxValue );			sc = new AutoScale( iType,					new Double( 0 ),					new Double( 0 ),					new Double( 10 ) );			sc.fs = fs; // FORMAT SPECIFIER			sc.rtc = rtc; // LOCALE			sc.bAxisLabelStaggered = ax.isAxisLabelStaggered( );			sc.setData( dsi );			sc.setAlwaysForward( forward );			sc.updateAxisMinMax( oMinValue, oMaxValue );			if ( ( iType & PERCENT ) == PERCENT )			{				sc.bStepFixed = true;				sc.bMaximumFixed = true;				sc.bMinimumFixed = true;			}			sc.computeTicks( xs,					ax.getLabel( ),					iLabelLocation,					iOrientation,					dStart,					dEnd,					false,					null );			if ( ( iType & PERCENT ) == PERCENT )			{				return sc;			}			dStart = sc.dStart;			dEnd = sc.dEnd;			boolean bFirstFit = sc.checkFit( xs, la, iLabelLocation );			boolean bFits = bFirstFit;			boolean bZoomSuccess = false;			// sc.oDebug = String.valueOf(bFirstFit);			while ( bFits == bFirstFit )			{				bZoomSuccess = true;				scCloned = (AutoScale) sc.clone( );				if ( sc.bStepFixed ) // DO NOT AUTO ZOOM IF STEP IS FIXED				{					break;				}				if ( bFirstFit )				{					if ( !bFits )					{						break;					}					bZoomSuccess = sc.zoomIn( );				}				else				{					if ( !bFits && sc.getTickCount( ) == 2 )					{						break;					}					bZoomSuccess = sc.zoomOut( );				}				if ( !bZoomSuccess )					break;				sc.updateAxisMinMax( oMinValue, oMaxValue );				sc.computeTicks( xs,						ax.getLabel( ),						iLabelLocation,						iOrientation,						dStart,						dEnd,						false,						null );				bFits = sc.checkFit( xs, la, iLabelLocation );				if ( !bFits && sc.getTickCount( ) == 2 )				{					sc = scCloned;					break;				}			}			// RESTORE TO LAST SCALE BEFORE ZOOM			if ( scCloned != null && bFirstFit && bZoomSuccess )			{				sc = scCloned;			}		}		else if ( ( iType & DATE_TIME ) == DATE_TIME )		{			Calendar cValue;			Calendar caMin = null, caMax = null;			dsi.reset( );			while ( dsi.hasNext( ) )			{				cValue = (Calendar) dsi.next( );				if ( cValue == null ) // NULL VALUE CHECK				{					continue;				}				if ( caMin == null )				{					caMin = cValue;				}				if ( caMax == null )				{					caMax = cValue;				}				if ( cValue.before( caMin ) )					caMin = cValue;				else if ( cValue.after( caMax ) )					caMax = cValue;			}			CDateTime cdtMinValue = new CDateTime( caMin );			CDateTime cdtMaxValue = new CDateTime( caMax );			int iUnit = CDateTime.getDifference( cdtMinValue, cdtMaxValue );			CDateTime cdtMinAxis = cdtMinValue.backward( iUnit, 1 );			CDateTime cdtMaxAxis = cdtMaxValue.forward( iUnit, 1 );			cdtMinAxis.clearBelow( iUnit );			cdtMaxAxis.clearBelow( iUnit );			sc = new AutoScale( DATE_TIME,					cdtMinAxis,					cdtMaxAxis,					new Integer( iUnit ),					new Integer( 1 ) );			sc.setAlwaysForward( forward );			sc.computeTicks( xs,					la,					iLabelLocation,					iOrientation,					dStart,					dEnd,					false,					null );			sc.fs = fs; // FORMAT SPECIFIER			sc.rtc = rtc; // LOCALE			sc.bAxisLabelStaggered = ax.isAxisLabelStaggered( );			dStart = sc.dStart;			dEnd = sc.dEnd;			// OVERRIDE MINIMUM IF SPECIFIED			if ( oMinimum != null )			{				if ( oMinimum instanceof DateTimeDataElement )				{					sc.oMinimum = ( (DateTimeDataElement) oMinimum ).getValueAsCDateTime( );				}				else				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.invalid.minimum.scale.value", //$NON-NLS-1$ 							new Object[]{								sc.oMinimum										+ ax.getModelAxis( )												.getType( )												.getName( )							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}				sc.bMinimumFixed = true;			}			// OVERRIDE MAXIMUM IF SPECIFIED			if ( oMaximum != null )			{				if ( oMaximum instanceof DateTimeDataElement )				{					sc.oMaximum = ( (DateTimeDataElement) oMaximum ).getValueAsCDateTime( );				}				else				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.invalid.maximum.scale.value", //$NON-NLS-1$							new Object[]{								sc.oMaximum										+ ax.getModelAxis( )												.getType( )												.getName( )							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}				sc.bMaximumFixed = true;			}			// OVERRIDE STEP IF SPECIFIED			/*			 * if (oStep != null) { sc.oStep = oStep; sc.bStepFixed = true; //			 * VALIDATE OVERRIDDEN STEP if (((Double) sc.oStep).doubleValue() <=			 * 0) { throw new GenerationException("Invalid 'step({0}) <= 0'			 * specified for axis scale" + oStep ); //			 * i18n_CONCATENATIONS_REMOVED } }			 */			// VALIDATE OVERRIDDEN MIN/MAX			if ( sc.bMaximumFixed && sc.bMinimumFixed )			{				if ( ( (CDateTime) sc.oMinimum ).after( ( (CDateTime) sc.oMaximum ) ) )				{					throw new ChartException( ChartEnginePlugin.ID,							ChartException.GENERATION,							"exception.min.largerthan.max", //$NON-NLS-1$							new Object[]{									sc.oMinimum, sc.oMaximum							},							ResourceBundle.getBundle( Messages.ENGINE,									rtc.getLocale( ) ) );				}			}			boolean bFirstFit = sc.checkFit( xs, la, iLabelLocation );			boolean bFits = bFirstFit, bZoomSuccess = false;			while ( bFits == bFirstFit )			{				bZoomSuccess = true;				scCloned = (AutoScale) sc.clone( );				if ( sc.bStepFixed ) // DO NOT AUTO ZOOM IF STEP IS FIXED				{					break;				}				if ( bFirstFit )				{					if ( !bFits )					{						break;					}					bZoomSuccess = sc.zoomIn( );				}				else				{					if ( !bFits && sc.getTickCount( ) == 2 )					{						break;					}					bZoomSuccess = sc.zoomOut( );				}				if ( !bZoomSuccess )					break;				sc.adjustAxisMinMax( cdtMinValue, cdtMaxValue );				sc.computeTicks( xs,						la,						iLabelLocation,						iOrientation,						dStart,						dEnd,						false,						null );				bFits = sc.checkFit( xs, la, iLabelLocation );				if ( !bFits && sc.getTickCount( ) == 2 )				{					sc = scCloned;					break;				}			}			// RESTORE TO LAST SCALE BEFORE ZOOM			if ( scCloned != null && bFirstFit && bZoomSuccess )			{				sc = scCloned;			}		}		sc.setData( dsi );		return sc;	}