import java.lang.reflect.Array;
import java.awt.*;

class Graph extends Panel {
  public static void main(String [] args) {
    double [] x=new double[101];
    double [] y=new double[101];
    double n=.05;

    Color c=new Color(180,180,0);

    for(int i=0;i<=100;i++) {
      x[i]=n;
      y[i]=Graph.loan(100000.0,n,360.0,12.0);
//System.out.println(x[i]+":"+y[i]);
      n=n+.001;
    }
    Graph g=new Graph(x,y);
    Frame f=new Frame();
    f.setSize(300,200);
    f.setBackground(c);

    f.add(g);
    f.show();

    double [] x1=new double[301];
    double [] y1=new double[301];
    int i=0;

    for(n=60;n<=360;n++) {
      x1[i]=n;
      y1[i]=Graph.loan(100000.0,.07,n,12.0);
      i++;
    }
    g=new Graph(x1,y1);
    f=new Frame();
    f.setSize(300,200);
    f.add(g);
    f.show();

  }

  public Graph(double [] x,double [] y) {
    xMar=.01;
    yMar=.01;
    xOff=.04;
    yOff=.04;
    myX=x;
    myY=y;
    xLen=Array.getLength(x);
    yLen=Array.getLength(y);
    if(xLen<yLen)
      cLen=xLen;
    else
      cLen=yLen;

    // find min and max value
    xMin=x[0];
    xMax=xMin;
    yMin=y[0];
    yMax=yMin;
    for(int i=0;i<cLen;i++) {
      if(xMin>x[i])
        xMin=x[i];
      if(xMax<x[i])
        xMax=x[i];
      if(yMin>y[i])
        yMin=y[i];
      if(yMax<y[i])
        yMax=y[i];
    }

    choose(xMin,xMax);
    xLMin=cLMin;
    xLDelta=cLDelta;
    xLMax=cLMax;
    
    choose(yMin,yMax);
    yLMin=cLMin;
    yLDelta=cLDelta;
    yLMax=cLMax;
    
/*    choose(.01345,100);
    choose(.000326,.000327);
    choose(125e7,125e8);
    choose(120.5,130.75);
    choose(500000,1500000);
*/
  }

  public void paint(Graphics g) {
    Rectangle r=getBounds();
    double x1=(1-xMar*2-xOff)*r.width/(xLMax-xLMin);
    double x2=r.width*(xMar+xOff);
    double y1=(1-yMar*2-yOff)*r.height/(yLMax-yLMin);
    double y2=r.height*(yMar+yOff);

    // paint graph
    for(int i=0;i<cLen-1;i++) {
      g.drawLine((int)((myX[i]-xLMin)*x1+x2),
        r.height-(int)((myY[i]-yLMin)*y1+y2),
        (int)((myX[i+1]-xLMin)*x1+x2),
        r.height-(int)((myY[i+1]-yLMin)*y1+y2));
    }

    // draw grid lines
    double gh=.005;
    FontMetrics fm=g.getFontMetrics();
    int fHeight=(int)(fm.getHeight()+yOff*r.height)/2;
    String s,s2;
    int fWidth,len;
    // draw x grid and label
    for(double d=xLMin;d<=xLMax;d=d+xLDelta) {
      g.drawLine((int)((d-xLMin)*x1+x2),
        r.height-(int)(y2-r.height*gh),
        (int)((d-xLMin)*x1+x2),
        r.height-(int)(y2+r.height*gh));
      s=format(d,xLDelta);
      fWidth=fm.stringWidth(s)/2;
      g.drawString(s,(int)((d-xLMin)*x1+x2)-fWidth,
        r.height-(int)(y2+r.height*gh)+fHeight);
    }

    // draw y grid and label
    fHeight=fm.getHeight();
    fWidth=fm.getMaxAdvance();
    for(double d=yLMin;d<=yLMax;d=d+yLDelta) {
      g.drawLine((int)(x2-r.width*gh),      
        r.height-(int)((d-yLMin)*y1+y2),
        (int)(x2+r.width*gh),
        r.height-(int)((d-yLMin)*y1+y2));
      s=format(d,yLDelta);
      len=s.length();
      for(int i=0;i<len;i++) {
        g.drawString(s.substring(i,i+1),-fWidth+(int)(x2-r.width*gh),
          r.height-(int)((d-yLMin)*y1+y2)+fHeight*(i-len/2));
      }
    }

    // draw border lines
    g.drawLine((int)(x2),r.height-(int)(y2),
      (int)(x2),r.height-(int)((yLMax-yLMin)*y1+y2));
    g.drawLine((int)(x2),r.height-(int)(y2),
      (int)((xLMax-xLMin)*x1+x2),r.height-(int)(y2));
  }

  public void choose(double min, double max) {
    // Choose a good range and label points for graph
    // find min
    double delta=max-min;
    cLMin=findBest(min-delta*.05,min);
    cLDelta=findBest(delta/8,delta/4);
System.out.println("for:"+min+":"+max);
System.out.println("delta:"+cLDelta);

    int i;
    for(i=0;cLDelta*i<max-cLMin;i++) {
System.out.print(" "+format(cLMin+cLDelta*i,cLDelta));
    }
    cLMax=cLMin+cLDelta*i;
System.out.println(" "+format(cLMax,cLDelta));
  }

  public double chop(double min,double max) {
    double log10=Math.log(10);

    // find exponent
    double a=Math.log(min)/log10;
    if(a<0) 
      a=a-1;
    int exp=(int)a;

    // begin chopping completely and then chop less
    double lnum,cnum1,cnum2,div,cnum=min;
    long ltmp;
    while(true) {
      lnum=cnum;
      div=Math.pow(10,exp);
      ltmp=(long)(min/div);
      cnum1=ltmp*div;
      cnum2=(ltmp+1)*div;
      if(cnum1==min) {
        return cnum1;        
      }
      if(cnum2<max) {
        return cnum2;
      }
      exp--;
    }
  }

  public double findBest(double min,double max) {
    double cnum1,cnum2;
    int digits=0;
    while(true) {
      cnum1=tChop(min,digits,false);
      cnum2=tChop(min,digits,true);
      if(cnum1>=min && cnum1<=max) {
        return cnum1;        
      }
      if(cnum2>=min && cnum2<=max ) {
        return cnum2;
      }
      digits++;
    }
  }

  public double tChop(double n,int place, boolean inc) {
    // chop least significant digits leaving PLACE significant digits
    // inc adds one to chopped mantissa

    if(place==0) {
      if(inc) 
        return 1;
      else
        return 0;
    }
    //double f=n+.5*Math.pow(10.0,(double)place);
    String s=Double.toString(n);

    // find exponent part of xx.yyEee
    int e=s.indexOf('E');
    String s1;
    String exp;
    if(e>=0) {
      s1=s.substring(0,e);
      exp=s.substring(e+1,s.length());
    }
    else {
      s1=s;
      exp="0";
    }
    int nExp=Integer.valueOf(exp).intValue();

    // find period
    int len=s1.length();
    int p1=s1.indexOf('.');
    if(p1>0) {
      nExp=nExp+p1-len+1;
      s1=s1.substring(0,p1)+s1.substring(p1+1,len);
    }

    // check for zeros in mantissa
    int zero;
    len=s1.length();
    for(zero=len-1;s1.charAt(zero)=='0';zero--);
    nExp=nExp+len-zero-1;
    s1=s1.substring(0,zero+1);

    String s2;
    len=s1.length();
    if(len<place) {
      s2=s1;
    }
    else {
      int rPlace=place;
      if(s1.charAt(0)=='-') {
        rPlace++;
        nExp--;
      }
      s2=s1.substring(0,rPlace);
      nExp=nExp-place+len;
    }
    exp=Integer.toString(nExp);
    if(inc)
      s2=Integer.toString(Integer.valueOf(s2).intValue()+1);
    return Double.valueOf(s2+"E"+exp).doubleValue();
  }

  public String format(double n,double delta) {
    // convert to text
    String s=Double.toString(n);

    // find exponent part of xx.yyEee
    int e=s.indexOf('E');
    String s1;
    String exp;
    if(e>=0) {
      s1=s.substring(0,e);
      exp=s.substring(e+1,s.length());
    }
    else {
      s1=s;
      exp="0";
    }
    int nExp=Integer.valueOf(exp).intValue();

    // find period
    int len=s1.length();
    int p1=s1.indexOf('.');
    if(p1>0) {
      nExp=nExp+p1-len+1;
      s1=s1.substring(0,p1)+s1.substring(p1+1,len);
    }
    len=s1.length();

    // deal with negative
    String neg;
    if(s1.charAt(0)=='-') {
      neg="-";
      s1=s1.substring(1,len);
      len--;
    }
    else
      neg="";

    // chop off at place
    int place=(int)(Math.log(delta)/Math.log(10.0)-1.5);
    place=len+nExp-place;
    if(place>len)
      place=len;
    else if(place<0)
      place=0;
    s1=s1.substring(0,place);
    nExp=nExp+len-place;

    // check for zeros in mantissa
    int zero;
    len=s1.length();
    for(zero=len-1;zero>=0 && s1.charAt(zero)=='0';zero--);
    nExp=nExp+len-zero-1;
    s1=s1.substring(0,zero+1);

    len=s1.length();
    if(len==0)
      return "0";
    else {
      if(nExp+len>7 || nExp+len<-7 
         || nExp>7 || nExp<-7) {   // use exponent notation
        return neg+s1+"E"+Integer.toString(nExp);
      }
      else {   // use standard notation
        String sZero="0000000";
        int diff=len+nExp;
        if(diff<0) {  // add leading zeros
          s1=sZero.substring(0,-diff)+s1;
          len=len-diff;
          diff=0;
        }

        if(nExp>0) {  // add trailing zeros
          s1=s1+sZero.substring(0,nExp);
        }
        else if(nExp<0 && diff>0) {  // add decimal point
          s1=s1.substring(0,diff)+"."+s1.substring(diff,len);
        }
        else if(diff==0) {
          s1="."+s1;
        }
        return neg+s1;
      }
    }
  }

  public static double loan(double loanAmount, double interest,
                     double numPayments, double numPayYear) {
    // returns payment for given loan
    double e=interest/numPayYear+1;
    double a=e;
    double b=1;
    for(int i=0;i<numPayments-1;i++) {
      b+=a;
      a*=e;
    }
    return loanAmount*a/b;
  }

  double [] myX;
  double [] myY;
  int xLen,yLen,cLen;    // number of values
  double xMin,yMin,xMax,yMax;
  double xLMin,xLDelta,xLMax;  // label values
  double yLMin,yLDelta,yLMax;
  double cLMin,cLDelta,cLMax;  // used to return info
  double xMar,xOff;            // Margin and Offset
  double yMar,yOff;
}