
import java.awt.*;
import java.applet.*;

public class StatsGraph extends Applet {
  int LeftMargin = 35;
  final int RightMargin = 0;
  final int TopMargin = 5;
  final int BottomMargin = 20;

  final int ShadowOffset = 10;

  FontMetrics FM;
  int    SkipBottomLabels = 1;
  int    NumLabels;
  int    MaxLabelLength;
  int    GraphHeight, GraphWidth;
  int    BarWidth;
  int    MaxValue = 0;
  int    NumDataPoints;
  int    Data[];
  String Label[];
  int    BarStyle;
  float  BarCenter = 0.5f;

  Color  BarColor, EndBarColor, BGColor, FGColor, LineColor;
  Image  GraphImage = null;

  public Color getColorParameter(String Parameter, Color Default) {
    String P = getParameter(Parameter);
    Color newC;

    if (P == null)
      return Default;

    if (P.substring(0, 1).equals("#"))
      P = P.substring(1, P.length());

    try {
    newC = new Color(Integer.valueOf(P, 16).intValue());
    } catch (Exception E) {
        System.out.println("Error!  Malformed color parameter "+Parameter);
        return Default;
    }

    if (newC == null)
      return Default;

    return newC;
  }

  public String getStringParameter(String Parameter, String Default) {
    String P = getParameter(Parameter);
    if (P == null)
      return Default;
    return P;
  }

  public int getIntegerParameter(String Parameter, int Default) {
    String P = getParameter(Parameter);
    int newI;
    if (P == null)
      return Default;

    try { newI = Integer.valueOf(P, 10).intValue(); }
    catch (Exception E) {
      System.out.println("Error!  Malformed integer parameter "+Parameter);
      return Default;
    }
    return newI;
  }

  public void init() {
    int LabelForm;
    BarColor    = getColorParameter("BarColor", Color.yellow);
    EndBarColor = getColorParameter("EndBarColor", BarColor);
    BGColor     = getColorParameter("BGColor", Color.white);
    FGColor     = getColorParameter("FGColor", Color.black);
    LabelForm   = getIntegerParameter("LabelForm", 0);
    BarStyle    = getIntegerParameter("BarStyle", 0);
    BarCenter   = (float)getIntegerParameter("BarCenter", 128)/(float)256;
    if (BarCenter < .5f)
      BarCenter = .5f+ (.5f-BarCenter);

    LineColor = new Color(((BGColor.getRed()*3)+FGColor.getRed())/4,
                          ((BGColor.getGreen()*3)+FGColor.getGreen())/4,
                          ((BGColor.getBlue()*3)+FGColor.getBlue())/4);


    FM = getGraphics().getFontMetrics();
    GraphHeight = size().height-1-TopMargin-BottomMargin;
    GraphWidth  = size().width-1-LeftMargin-RightMargin;
    NumDataPoints = getIntegerParameter("NumDataPoints", 1);
    BarWidth = GraphWidth/NumDataPoints;
    GraphWidth = BarWidth*NumDataPoints;

    Data = new int[NumDataPoints];
    Label = new String[NumDataPoints];
    NumLabels = GraphHeight / (3*(FM.getAscent()+FM.getMaxDescent())/2);

    for (int i=1; i <= NumDataPoints; i++) {
      Data[i-1] = getIntegerParameter("Data"+i, 0);
      if (Data[i-1] > MaxValue)
        MaxValue = Data[i-1];
      if (LabelForm == 0)
        Label[i-1] = getStringParameter("Label"+i, "");
      else if (LabelForm == 1)
        Label[i-1] = i+"";
      else if (LabelForm == 2)
        Label[i-1] = ((i-1) % 12)+1+":00";
      if (FM.stringWidth(Label[i-1])+2 > MaxLabelLength)
        MaxLabelLength = FM.stringWidth(Label[i-1])+2;
    }

    if (NumLabels > MaxValue) NumLabels = MaxValue;

    LeftMargin = FM.stringWidth(""+MaxValue)+5;

    SkipBottomLabels = MaxLabelLength/BarWidth+1;

    GraphImage = createImage(size().width, size().height);
    DrawChart(GraphImage.getGraphics());
  }

  private Color ColorSlider(Color C1, Color C2, int Cur, int Max) {
    int r, g, b;

    if (Max == 0)
      return C1;

    r = ((C2.getRed()  *Cur) + (Max-Cur)*C1.getRed()) / Max;
    g = ((C2.getGreen()*Cur) + (Max-Cur)*C1.getGreen()) / Max;
    b = ((C2.getBlue() *Cur) + (Max-Cur)*C1.getBlue()) / Max;
    return new Color(r, g, b);
  }

  private Color BarColor(int Bar) {
    return ColorSlider(BarColor, EndBarColor, Bar, NumDataPoints-1);
  }

  private void Color2Array(int CA[], Color C) {
    CA[0] = C.getRed();
    CA[1] = C.getGreen();
    CA[2] = C.getBlue();
  }

  private Color ParaColorSlider(Color y1, Color Yvert, float Xvert, float X) {
    int c1[] = new int[3];
    float b[] = new float[3];
    int Y1[] = new int[3];
    int i;
    float x;
    Color2Array(c1, Yvert);
    Color2Array(Y1, y1);

    x = Xvert-X;
    for (i = 0; i < 3; i++)
        b[i] = (Y1[i]-c1[i])/(Xvert*Xvert);

    return new Color((int)(c1[0]+x*x*b[0]),
                     (int)(c1[1]+x*x*b[1]),
                     (int)(c1[2]+x*x*b[2]));
  }

  private void DrawBar(Graphics G, int Bar, int x1, int y1, int width, int height) {
    Color C1 = BarColor(Bar);
    Color EdgeColor = ColorSlider(C1, Color.black, 8, 8);;
    int X1;

    if (BarStyle == 1) {
      for (X1 = x1+1; X1 < x1+width; X1++) {
        G.setColor(ColorSlider(EdgeColor, C1, X1-(x1+1), width-2));
        G.drawLine(X1, y1, X1, y1+height);
      }
    } else if (BarStyle == 2) {
      for (X1 = x1+1; X1 < x1+width; X1++) {
        G.setColor(ParaColorSlider(EdgeColor, C1, BarCenter, (float)(X1-x1-1)/(float)(width-2)));
        G.drawLine(X1, y1, X1, y1+height);
      }
    } else {
      G.setColor(C1);
      G.fillRect(x1, y1, width, height);
    }
    G.setColor(FGColor);
    G.drawRect(x1, y1, width, height);
  }

  public boolean mouseEnter(Event evt, int x, int y) {
    showStatus("StatsGraph 1.24 Copyright (c) 1997-2000 Chris Lattner");
    return(true);
  }

  public boolean mouseExit(Event evt, int x, int y) {
    showStatus("");
    return(true);
  }

  public void update(Graphics g) {
    paint(g);
  }

  public void DrawChart(Graphics g) {
    String LabelText;
    int MaxLabelWidth = FM.stringWidth(""+MaxValue);
    int LabelX, Y;

    g.setColor(BGColor);
    g.fillRect(0, 0, size().width, size().height);

    if (NumLabels > 0) {
      for (int i=0; i <= NumLabels; i++) {     // Print the data labels on the left
        Y = TopMargin+GraphHeight*i/NumLabels; // of the graph.

        g.setColor(LineColor);
        g.drawLine(LeftMargin, Y, GraphWidth+LeftMargin, Y);

        g.setColor(FGColor);
        LabelText  = ""+MaxValue*(NumLabels-i)/NumLabels;
        LabelX = MaxLabelWidth/2-FM.stringWidth(LabelText)/2;
        g.drawLine(FM.stringWidth(LabelText)+LabelX, Y,
                   LeftMargin,                       Y);
        g.drawString(LabelText, LabelX, GraphHeight*i/NumLabels+10);
      }
    }

    Y = TopMargin+GraphHeight+BottomMargin-1;
    for (int i=0; i < NumDataPoints; i += SkipBottomLabels) {
      LabelX = LeftMargin+GraphWidth*i/NumDataPoints+BarWidth/2;
      g.drawString(Label[i], LabelX-FM.stringWidth(Label[i])/2, Y);
      g.drawLine(LabelX, TopMargin+GraphHeight, LabelX, Y-FM.getMaxAscent());
    }

    g.setColor(FGColor);
    g.drawRect(LeftMargin, TopMargin, GraphWidth, GraphHeight);
    if (MaxValue == 0) MaxValue = 1;
    for (int i=0; i < NumDataPoints; i++)
      DrawBar(g, i, LeftMargin+i*BarWidth, TopMargin+GraphHeight-Data[i]*GraphHeight/MaxValue,
                    BarWidth, Data[i]*GraphHeight/MaxValue);
  }

  public void paint(Graphics g) {
    if (GraphImage != null)
      g.drawImage(GraphImage, 0, 0, this);
    else {
      g.setColor(Color.white);
      g.fillRect(0, 0, size().width, size().height);
    }

  }
}
