package cnp.ew.charts;

import cnp.ew.diagram.*;
import cnp.ew.displayer.*;
import cnp.ew.converter.*;
import java.awt.*;
import cnp.ew.util.*;
import cnp.ew.lightweight.*;

public class CpValueAxisDisplayer extends CpAbstractAxisDisplayer
{

    CpGeneralStringDisplayer textDisplayer = new CpGeneralStringDisplayer();
    CpToStringConverter converter = new CpNumberToStringConverter("$#,###.00;($#,###.00);$-  ");
    boolean autoSuggestMaxAndStep=true;
    double actualMaximumValue = 100.0;
    boolean drawTicks=true;
    int tickSize=4;
    int orientation=ORIENT_BOTTOM_TO_TOP;
    static int textMargin=4;
    static int tickMargin=3;
    String [] cachedLabels;
    CpValueAxisModel axisModel;
    CpChartDataModel dataModel;
    CpRotatedDisplayer labelDisplayer;
    CpGeneralStringDisplayer innerLabelDisplayer;

    public static final int CHANGED_SCALE_MAX=0;
    public static final int CHANGED_MAJOR_STEP=1;

    static final int labelGap = 6;

    public CpValueAxisDisplayer()
    {
        super();

	    textDisplayer.setHorizontalAlignment(CpAlignable.ALIGN_RIGHT);
	    textDisplayer.setVerticalAlignment(CpAlignable.ALIGN_CENTER);
	    textDisplayer.setFont(font);
	    innerLabelDisplayer = new CpGeneralStringDisplayer();
	    innerLabelDisplayer.setHorizontalAlignment(CpAlignable.ALIGN_CENTER);
	    labelDisplayer = new CpRotatedDisplayer(innerLabelDisplayer);
    }

    public void setValueAxisModel(CpValueAxisModel newModel)
    {
        axisModel = newModel;
        axisModel.addObserver(this);
        cachedLabels = null;
    }

    public void setChartDataModel(CpChartDataModel newModel)
    {
        dataModel = newModel;
    }


    public void update(CpObservable o, int facet, Object arg)
    {
        cachedLabels = null;
    }

    /**
     * Answer the number of steps that can be drawn within the given
     * bounds.
     */
    public int getMaximumSteps(CpLightweightComponent lc, Rectangle bounds)
    {
        switch(orientation) {
        case ORIENT_BOTTOM_TO_TOP:
            return (bounds.height + textMargin) / (textDisplayer.getFontMetrics(lc).getHeight() + textMargin);
        }
        return 0;
    }

	public void paintIn(CpLightweightComponent lc, Graphics g, int x, int y, int w, int h)
	{
	    double currentValue = axisModel.getMin();
	    int numSteps = axisModel.getMajorStepCount();

	    int fontHeight = textDisplayer.getFontMetrics(lc).getHeight();
	    double valuePercentage;
	    int bottomStartY, adjustedHeight, centerY;
	    String [] labels = getLabels();

	    innerLabelDisplayer.setText(dataModel.getSeriesLabel());
	    Dimension preferredSize = labelDisplayer.preferredSize(lc);
	    labelDisplayer.paintIn(lc, g, x, y, preferredSize.width, h);

	    int startX = x + + preferredSize.width + labelGap;

    // the + 1 below is to round the fontHeight up, if it's an odd size.
	    bottomStartY = y + h - ((fontHeight + 1)/ 2);
	    adjustedHeight = h - fontHeight;

	    for (int i=0; i <= numSteps; i++) {
	        textDisplayer.setText(labels[i]);
	        valuePercentage = axisModel.getPercentageForValue(currentValue);
	        centerY = bottomStartY - (int)(valuePercentage * adjustedHeight);
	        if (drawTicks) {
	            switch(orientation) {
	            case ORIENT_BOTTOM_TO_TOP:
    	            g.drawLine(x + w - tickSize, centerY, x + w - 1, centerY);
	                break;
	            }
	        }

	        textDisplayer.paintIn(lc, g, startX, centerY - (fontHeight/2), w - tickMargin - startX, fontHeight);
	        currentValue += axisModel.getMajorStep();
	    }

        int topStartY = y + fontHeight - ((fontHeight + 1) / 2);
        g.drawLine(x + w - 1, topStartY, x + w - 1, bottomStartY);

	}


    String [] getLabels()
    {
        if (cachedLabels == null) {
            buildLabels();
        }
        return cachedLabels;
    }

    void buildLabels()
    {
        int numSteps = axisModel.getMajorStepCount();
        double currentValue = axisModel.getMin();
        cachedLabels = new String[numSteps + 1];

        for (int i=0; i <= numSteps; i++) {
        	cachedLabels[i] = converter.convert(new Double(currentValue));
        	currentValue += axisModel.getMajorStep();
        }
    }



    public void setOrientation(int newOrientation)
    {
        orientation = newOrientation;
    }

    public int getOrientation()
    {
        return orientation;
    }

    public Dimension preferredSize(CpLightweightComponent lc)
    {
        // For a vertical one, we don't care about the height, only the width.  Give a reasonable
        // default for the height

        Dimension preferredSize = new Dimension();
        Dimension textSize = new Dimension();
        String [] labels = getLabels();

        int maxWidth = 0;
        for (int i = 0; i < labels.length; i++) {
            textDisplayer.setText(labels[i]);
            textSize = textDisplayer.preferredSize(lc);
            preferredSize.width = Math.max(preferredSize.width, textSize.width);
        }

        preferredSize.height = textSize.height * 5;
        preferredSize.width += tickSize + tickMargin;

        innerLabelDisplayer.setText(dataModel.getSeriesLabel());
        preferredSize.width += labelDisplayer.preferredSize(lc).width + labelGap;

        return preferredSize;

    }
    // Since the label display in this Lc must exceed the bounds
    // of the tickmarks, we need to let anyone wanting to align
    // themselves to us to have an offset to set relative to the
    // tickmarks.
    public int getLeftOrTopTickAlignmentOffset(CpLightweightComponent lc)
    {
        // THIS -1 is SUSPECT...
        return textDisplayer.getFontMetrics(lc).getHeight()/2 - 1;
    }

    public int getRightOrBottomTickAlignmentOffset(CpLightweightComponent lc)
    {
        return textDisplayer.getFontMetrics(lc).getHeight()/2 - 1;
    }
}
