/*
 * LogAxis.java
 *
 * Copyright (C) 2002-2006 Alexei Drummond and Andrew Rambaut
 *
 * This file is part of BEAST.
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * BEAST is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 *  BEAST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with BEAST; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

package dr.gui.chart;

import java.text.DecimalFormat;

public class LogAxis extends Axis.AbstractAxis {

//	private int extraMinorTickCount;
	

	/**
	 * Empty constructor
	 */
	public LogAxis() {
		super();
        setSignficantFigures(0);
    }

	/**
	 * Axis flag constructor
	 */
	public LogAxis(int minAxisFlag, int maxAxisFlag) {
	 
		setAxisFlags(minAxisFlag, maxAxisFlag);
	}

	/**	
	*	Set axis flags
	*/
	public void setAxisFlags(int minAxisFlag, int maxAxisFlag) {
	
		if (minAxisFlag==AT_DATA || minAxisFlag==AT_ZERO) {
			minAxisFlag = this.minAxisFlag;
		} 
		
		if (maxAxisFlag==AT_DATA || maxAxisFlag==AT_ZERO) {
			maxAxisFlag = this.maxAxisFlag;
		}
		
		super.setAxisFlags(minAxisFlag, maxAxisFlag);
	}

	/**	
	*	Set the range of the data.
	*/
	public void setRange(double minValue, double maxValue) {
	
		if (maxValue <= 0.0)
			maxValue = 1.0E-100;
			
		if (minValue <= 0.0)
			minValue = maxValue;
		super.setRange(minValue, maxValue);
		
	}
		
	/**	
	*	Adds the range of the data.
	*/
	public void addRange(double minValue, double maxValue) {

		if (maxValue <= 0.0)
			maxValue = 1.0E-100;
			
		if (minValue <= 0.0)
			minValue = maxValue;
 		super.addRange(minValue, maxValue);
		
	}
		
	/**
	* Calculate the optimum minimum tick. For a log scale this is always a power of 10
	*/
	public void calcMinTick() {
		minTick=1;
		// Find the nearest multiple of majorTick below minData
		if (minData>1) { // work upwards
			while ((minTick*10)<minData)
				minTick*=10;
		} else if (minData<1) { // work downwards
			while (minTick>minData)
				minTick/=10;
		}
	}

	/**
	* Calculate the optimum maximum tick. For a log scale this is always a power of 10
	*/
	public void calcMaxTick() {
		maxTick=1;
		// Find the nearest multiple of majorTick above maxData
		if (maxData>1) { // work upwards
			while (maxTick<maxData)
				maxTick*=10;
		} else if (maxData<1) { // work downwards
			while ((maxTick/10)>maxData)
				maxTick/=10;
		}
	}

	/**
	* Calculate the optimum major tick distance. 
	*/
	public void calcMajorTick() {
		majorTick=10;
		majorTickCount=(int)Math.round(log10(maxTick/minTick))+1;
	}
	
	/**
	* Calculate the optimum minor tick distance.
	*/
	public void calcMinorTick() {
		minorTick=1;
		minorTickCount=8; // 1 and 10 are major ticks
	}
	
	/**
	* Handles axis flags.
	*/
	public void handleAxisFlags() {
		if (minAxisFlag==AT_MINOR_TICK) {
			if (minAxis+minTick<=minData) {
				while ((minAxis+minTick)<=minData) {
					minAxis+=minTick;
				}
				majorTickCount--;
				minTick*=10;
			}
		}

		if (maxAxisFlag==AT_MINOR_TICK) {
			if (maxAxis-(maxTick/10)>=maxData) {
				majorTickCount--;
				maxTick/=10;
				while ((maxAxis-maxTick)>=maxData) {
					maxAxis-=maxTick;
				}
			}
		}
	}
	
	/**	
	*	Transform a value onto the log axis
	*/
	public double transform(double value) {
		return log10(value);
	}

	/**
	*	Untransform a value from the log axis
	*/
	public double untransform(double value) {
		return Math.pow(value, 10.0);
	}

	/**
	*	Returns the number of minor tick marks within each major one
	*	The last major tick may have less minors that the other.
	*/
	public int getMinorTickCount(int majorTickIndex) {
		if (!isCalibrated)
			calibrate();
				
		if (majorTickIndex==majorTickCount-1)
			return (int)((maxAxis-maxTick)/maxTick);
		else if (majorTickIndex==-1) {
			return (int)((minTick-minAxis)/(minTick/10));
		} else
			return minorTickCount; 
	}
	

	/**
	*	Returns the value of the majorTickIndex'th major tick
	*/
	public double getMajorTickValue(int majorTickIndex) {
		if (!isCalibrated)
			calibrate();
				
		if (majorTickIndex==majorTickCount-1)
			return maxTick;
		else
			return Math.pow(10, majorTickIndex)*minTick;
	}
	
	/**
	*	Returns the value of the minorTickIndex'th minor tick
	*/
	public double getMinorTickValue(int minorTickIndex, int majorTickIndex) {
		if (!isCalibrated)
			calibrate();
				
		if (majorTickIndex==-1)
			return minTick-((minorTickIndex+1)*(minTick/10));
		else
			return (minorTickIndex+2)*getMajorTickValue(majorTickIndex);
			
		//	This last line is the equivalent of:
		//	return ((minorTickNo+1)*getMajorTick(majorTickNo))+getMajorTick(majorTickNo);
	}
}

