/*
 * @(#) MultiHistogram.java 1.0 2000/07/24 Larry Rodrigues
 * Copyright (c) 2000 Larry Rodrigues
 */
package vis.beans.plotter;
import java.awt.*;
import java.beans.*;
import vis.util.*;
import vis.beans.events.*;
import java.util.*;

/** The MultiHistogram Class draws one or more sets of histograms as bar charts.
* @version 1.0  24  July 2000
* @author Larry Rodrigues
**/
public class MultiHistogram extends PlotViewport {
    protected int freqRange;
    protected double binRange;
    protected int[] freqMinmax = new int[2];
    protected Object binMinmaxObj;
    protected int barWid, barHt;
    protected int[] barHgt;
    protected int[][] frequency;
    protected Object binMinmax;
    protected int numBars = 5;
    protected Color barColor= Color.yellow;
    protected int numPlots = 0;
    protected Vector yVector = new Vector();
    protected Color histColor[] = {Color.red, Color.green, Color.blue, Color.darkGray, Color.yellow};

    public MultiHistogram(){
       numYTicks =4;
       numSmallXTicks =0;
       numSmallYTicks =0;
       graphNum = 0;
       graphColor = null;
       setCustomizerClass(MultiHistoCustomizer.class);
    }
    /** Sets the number of bars.
     * @param the number of bars.
     */
    public void setNumBars(int bars){
       if(numBars != bars) {
          numBars = bars;
          computeHistogram();
          draw();
       }
       repaint();
    }

    /** @ return the number of bars.*/
    public int getNumBars(){
       return numBars;
    }

    /** Sets the color of the bars.
      * @param the bar color.
      */
    public void setBarColor(Color col){
       barColor = col;
       draw();
    }

    /** @return the color of the bars.**/
    public Color getBarColor(){
       return barColor;
    }

    public void drawPlot(Object x, Object y){
       drawPlot(y);
    }

    /** This method plots the histogram. This can be used as a target method for
      * for connecting other beans to the Histogram using plot events.
      * @param  e the PlotEvent
      */
    public void plotHistogram(PlotEvent e){
       y = e.getYValues();
       drawPlot(y);
    }

    /** Plots the histogram.
      * @param data an array of elements which can be of any Java primitive type.
      */
    public void drawPlot(Object data){
       if(data == null) return;
       y = data;
       barHgt = new int[numBars];
       HistoData  histoData = Util.computeHistogram(data, numBars);
       frequency[0] = histoData.getFrequency();
       binMinmax = histoData.getBinMinmax();
       freqMinmax = histoData.getFreqMinmax();
       //Reduce the min value so that the bar for the actual min value shows up
       if(freqMinmax[0] > 0) {
          freqMinmax[0] -= (int)((freqMinmax[1]-freqMinmax[0])*0.3);
          if(freqMinmax[0] <0) freqMinmax[0] =0;
       }
       freqRange = freqMinmax[1] - freqMinmax[0];
       xRange = Util.getRange(binMinmax);
       binRange = (xRange/numBars);
       enableDraw = false;
       draw();
    }

    public void computeHistogram() {
       int size = yVector.size();
       Object data[] = new Object[size];
       frequency = new int[size][];
       yVector.copyInto(data);
       barHgt = new int[numBars];
       HistoData[] histodata = new HistoData[size];
       int[] binR = new int[2];
       binMinmax = new int[2];
       ((int[])binMinmax)[1] = Integer.MIN_VALUE;
       ((int[])binMinmax)[0] = Integer.MAX_VALUE;

       int[] freqR = new int[2];
       freqMinmax = new int[2];
       freqMinmax[1] = Integer.MIN_VALUE;
       freqMinmax[0] = Integer.MAX_VALUE;

       for(int i=0; i<size; i++) {
           histodata[i] = Util.computeHistogram(data[i], numBars);
           frequency[i] = histodata[i].getFrequency();
           binMinmax = histodata[i].getBinMinmax();
           freqR= histodata[i].getFreqMinmax();
           if(freqR[0] < freqMinmax[0]) freqMinmax[0] = freqR[0];
           if(freqR[1] > freqMinmax[1]) freqMinmax[1] = freqR[1];
       }
       //Reduce the min value so that the bar for the actual min value shows up
       if(freqMinmax[0] > 0) {
          freqMinmax[0] -= (int)((freqMinmax[1]-freqMinmax[0])*0.3);
          if(freqMinmax[0] <0) freqMinmax[0] =0;
       }
       freqRange = freqMinmax[1] - freqMinmax[0];
       xRange = Util.getRange(binMinmax);
       binRange = (xRange/numBars);
    }

    public void draw(){
        if(enableDraw) return;
        setOffScrGc();
        createPlotTemplate();
        String ymaxstr = Util.maxString(binMinmax);
        if(ymaxstr == null) ymaxstr = "       ";
        String xmaxstr = Util.maxString(freqMinmax);
        if(xmaxstr == null) xmaxstr = "       ";
        drawAxis(xmaxstr, ymaxstr);
        barWid = (int)(graphWid/(double)numBars);
        barHt = orig.y - (border.y+fontSize+5)- headerHt;
        drawXLabel();
        drawYLabel(ymaxstr);
        drawXTicks(binMinmax);
        numSmallYTicks =1;
        drawYTicks(freqMinmax);
        if(legendOn) drawLegends();
        repaint();
    }

    public void drawXTicks(Object minmax){
        String xstr=null;
        int xwid=0;
        int xl=0;
        int xTick;
        int xBar;

        double valPerTick = xRange/numBars;
        double valPerTickPix= ((double) graphWid)/numBars;
        xBar = orig.x;
        xTick = orig.x;
        double yValPerTick = (double)freqRange/(double)numYTicks;
        double yValPerTickPix= ((double)graphHt)/(double)numYTicks;

        for(int i= 0; i<numBars;i++){
            offScrGc.setColor(Color.red);
            offScrGc.drawLine(xTick, orig.y, xTick, orig.y + tickLen);
            offScrGc.setColor(Color.green);
            if((i%xLabelsPerTick) ==0){
                String str = Util.getInBetString(minmax,  (i*binRange)+1);
                if(str!=null) offScrGc.drawString(str, xTick, orig.y + tickLen + fontSize+1);
            }
            for(int j= 0; j< numPlots; j++) {
            int curBarHt =(int)(graphHt*((double)(frequency[j][i] - freqMinmax[0])/(double)freqRange));
            int barWidth = (int)(barWid/numPlots) +1;
            if(frequency[j][i] !=0){
               offScrGc.setFont(new Font("Helevetica", Font.BOLD, fontSize-2));
               FontMetrics mt = offScrGc.getFontMetrics();
               String vstr = Integer.toString(frequency[j][i]);

               int wid = mt.stringWidth(vstr);
               offScrGc.setFont(font);
            }
            offScrGc.setColor(Color.white);
            offScrGc.drawRect(xBar+ (barWidth*j)+1, orig.y -curBarHt,
                     barWidth-2, curBarHt-2);
            offScrGc.setColor(histColor[j]);
            offScrGc.fillRect(xBar+(barWidth*j)+1, orig.y -curBarHt,
                     barWidth-2, curBarHt-2);
            }
            xTick += (barWid);
            xBar  += (barWid);
        }
    }

    protected void drawYTicks(int[] minmax){
        String str = null;
        int yTick = orig.y;
         // Draw Y ticks
        offScrGc.setColor(Color.red);
        double valPerTick = (double)freqRange/(double)numYTicks;
        double valPerTickPix= ((double)graphHt)/(double)numYTicks;

        for(int i =0; i<= numYTicks;i++){
            yTick = orig.y - (int)(valPerTickPix*i);
            offScrGc.setColor(Color.cyan);
            offScrGc.drawLine(orig.x, yTick, orig.x-tickLen, yTick  );
            offScrGc.setColor(Color.green);
            if((i%yLabelsPerTick) ==0){
                str = Integer.toString((new Double(Util.trunc(minmax[0]+(i*valPerTick)))).intValue());
                offScrGc.drawString(str, orig.x- (pFont.stringWidth(str)+tickLen/2+1),
                        yTick-2 );
            }
         }
    }

    public void addGraph(Object x, Object y){
        if(y == null) return;
        yVector.addElement(y);
        computeHistogram();
        graphNum++;
        numPlots++;
    }

    public void resetPlotViewport() {
        super.resetPlotViewport();
        graphNum =0;
        numPlots =0;
        yVector = new Vector();
    }
    public void paintGraphs() {}
}
