package edu.csusb.danby.graph;


import java.awt.*;
import java.text.NumberFormat;
/**
* static methods for graph classes
* @author Charles Stanton
* @version December 17 2000
*/
public class GraphMethods{
    final static double log10 = Math.log(10.0);
        //constants for layout
    public static final int HORIZONTAL=0;
    public static final int VERTICAL =1;
    public static final int LOW =0;
    public static final int HIGH =1;

/**
* try to determine a reasonable number of decimal places
* to show in labels
*/
    public static int setMaxFractionDigits( double max, double min){
        double spreadData, logSpreadData;
        int maxFractionDigits;
        long spreadPower;
        spreadData = max-min;

        logSpreadData = Math.log(spreadData)/log10;
        spreadPower = (long)Math.floor(logSpreadData);
        maxFractionDigits =(int) ( 2-1*spreadPower);
        return maxFractionDigits;
    }

/**
* try to find nice grid values for axes
* @lowValue is the lower endpoint of the scale
* @highValue is the upper endpoint of the scale
* @graphPixels is the dimension of the scale in pixel space
*/
    public static float[] setGrid(float lowValue, float highValue){//, int graphPixels){	
                                                                    //MAYBE PASS A SMALL GRAPH BOOLEAN
        int increment;
        int incrementFactor=1; // increase increment for small graphs
        //if (graphPixels<180){ incrementFactor=2;}
    

        //first we scale so that there are between 10 and 100 integer values
        //in the graphing range
        int pow10 = (int)Math.floor(2-Math.log(highValue-lowValue)/log10);
        float scale10 = (float)Math.exp(log10*pow10);
        int iScaledLow= (int)(lowValue*scale10);
        int iScaledHigh = (int)(highValue*scale10);

        //Now we reduce the lines, keeping multiples of 2, 5, or 10
        int numberLines = iScaledHigh - iScaledLow;


        if (numberLines>= 80){increment =10*incrementFactor;}
        else if (numberLines >= 40) {increment = 5*incrementFactor;}
        else if (numberLines >= 16 ) {increment =2*incrementFactor;}
        else {increment =1*incrementFactor;}
        
        
        //adjust the starting value to be a multiple of the increment
        //We want a positive remainder, so the grid point is in the range
        int iAdj = (iScaledLow <0) ?iScaledLow%increment+increment:iScaledLow%increment;
        int initPosition = (iAdj==0)?iScaledLow:iScaledLow-iAdj+increment;

        iAdj = (iScaledHigh<0)? iScaledHigh%increment:iScaledHigh%increment-increment;
        int finalPosition = iScaledHigh+iAdj;

        //recount the number of grid points
        numberLines = (finalPosition -initPosition)/increment+1;

        //now calculate the grid points
        int iPosition = initPosition;
        float[] grid = new float[numberLines];
        for (int i= 0; i< numberLines; i++){
            grid[i] = iPosition/scale10;
        iPosition += increment;
        }
        return grid;
    }

    public static void paintScale(Graphics g, int scalePosition, float[] grid, int direction,
                double lowValue, double highValue, int offset, int graphSize,
                Color scaleColor,   Font f, Color fontColor,
                 boolean labelAxes, String axisLabel) {
        int othogonalDirection = (direction == VERTICAL)?HORIZONTAL:VERTICAL;	
        //int scalePosition = scale(position,othogonalDirection);
        //int scalePosition = position-10;  //POSITIONING HACK		
        int[] iGrid= new int[grid.length];
        NumberFormat nf = NumberFormat.getNumberInstance();
        for (int i=0; i< grid.length; i++){
            iGrid[i] = scale(grid[i], lowValue, highValue, direction, offset, graphSize);
        }
        String scaleLabel;
        g.setFont(f);
        int maxFractionDigits = 
            GraphMethods.setMaxFractionDigits(highValue,lowValue);
        nf.setMaximumFractionDigits(maxFractionDigits);
        g.setColor(scaleColor);
        if (direction == HORIZONTAL){
            g.drawLine(offset, scalePosition, 
                offset+graphSize,scalePosition);
            for (int i=0; i <iGrid.length; i++){
                g.drawLine( iGrid[i], scalePosition-5, 
                    iGrid[i], scalePosition+5);
                scaleLabel = nf.format(grid[i]);
                g.setColor(fontColor);
                g.drawString(scaleLabel,iGrid[i]-5,scalePosition+20); 		
            }
            if (labelAxes) {
                g.setColor(fontColor);
                g.drawString(axisLabel, offset+graphSize-10, scalePosition+20);
            }
        }
        else {  // direction == VERTICAL
            g.drawLine(scalePosition, offset, 
                scalePosition, offset+graphSize);
            for (int i=0; i <iGrid.length; i++){
                g.drawLine(scalePosition-5, iGrid[i],
                     scalePosition+5, iGrid[i]);
                scaleLabel = nf.format(grid[i]);
                g.setColor(fontColor);
                g.drawString(scaleLabel,scalePosition-25,iGrid[i]+6); 
            }
            if (labelAxes){
                g.setColor(fontColor);
                g.drawString(axisLabel, scalePosition+5,offset+10);
            }
        }

    }

    //offset should be top or left offset
    //graphSize should be pixel height or width of graph, not including offsets
    //lowValue should be lowest double on scale, highValue highest double
    protected static int scale(double value, double lowValue, double highValue, int direction, int offset, int graphSize){
        int nValue;
        nValue = (int)((value-lowValue)
            *graphSize/(highValue-lowValue));
        if (direction==VERTICAL){nValue = graphSize-nValue+offset;}
        else {nValue = nValue+offset;}
        return nValue;
    }

}
    