/*
 *	(C) James T. Hoffman and Sun Synchrony
 *
 *
 *	SUMMARY:
 *
 *	Generate light-capture efficiency graphs, given data from Aperture.java
 *
 *	USAGE:
 *
 * 	java jt.aperture.Polar <filename>
 *
 */

package jt.aperture;

import java.util.*;
import java.text.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.image.renderable.*;
import java.awt.font.*;
import java.lang.*;
import java.lang.Object.*;
import javax.swing.*;
import javax.imageio.*;
import javax.media.jai.*;
import java.io.*;

import jt.util.*;
import jt.geom.*;
import jt.vewg.*;


class Polar extends JFrame implements Runnable {

  boolean rescaleQ = true;
  double portRad = 1.6;
  int imgWide = 1000;
  int imgHigh = 1000;
  boolean colorq = false;

  double insetMarg = 0.0;
  boolean histoQ = false;

  class Data {
    int nU,nV;
    double aInc;
    double[][] a;
    Data(int nu,int nv,double ainc) {
      nU = nu;
      nV = nv;
      aInc = ainc;
      a = new double[nU][nV];
    }
    StreamTokenizer stok;
    private double getNum() {
      try {
	switch (stok.nextToken()) {
	case StreamTokenizer.TT_NUMBER:
	  return stok.nval;
	case StreamTokenizer.TT_EOF: 
	  System.exit(1);
	case StreamTokenizer.TT_WORD:
	  SO.coml("error - word in data file");
	  break;
	case StreamTokenizer.TT_EOL:
	  SO.coml("error - EOL");
	  break;
	default:
	  SO.coml("error - bad token: "+ stok.ttype);
	}
      } catch (IOException e) {
	SO.errl("error reading number, "+ e.getMessage());
      }
      return 0d;
    }
    Data(String fnam) {
      try {
	FileReader fr = new FileReader(fnam);
	stok = new StreamTokenizer(fr);
	stok.eolIsSignificant(false);
	nU = (int)getNum();
	nV = (int)getNum();
	aInc = getNum();
	a = new double[nU][nV];
	for (int iu = 0; iu < nU; iu++)
	for (int iv = 0; iv < nV; iv++)
	  a[iu][iv] = getNum();
      } catch (IOException e) {
	SO.errl("error reading file "+ fnam +" "+ e.getMessage());
	e.printStackTrace();
      }
    }
    void put(int iu,int iv,double val) {
      a[iu][iv] = val;
    }
    double get(int iu,int iv) {		// get by indices
      if (iu >= nU || iv >= nV) return -1d;
      if (iu <  0  || iv <  0 ) return -1d;
      return a[iu][iv];
    }
    double get(double au,double av) {	// get by coords in degrees
      int iu = (int)(au/aInc);
      int iv = (int)(av/aInc);
      return get(iu,iv);
    }
  }
  /*
   *
   */
  Data data;
  Image image;
  double imgRad;
  Component pane;
  Graphics2D gr;
  static Color lightGray = new Color(0.9f,0.9f,0.9f);

  private BufferedImage getBufferedImageFromImage(Image img)
  {
    // this makes sure that the image is loaded fully
    //
    img = new ImageIcon(img).getImage();
    BufferedImage bufferedImage = new BufferedImage(
                img.getWidth(null),
                img.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);
    Graphics gr = bufferedImage.createGraphics();
    gr.drawImage(img, 0,0, null);
    gr.dispose();
    return bufferedImage;
  }
  void saveAsPNG(String nam) {
    BufferedImage bufferedImage = getBufferedImageFromImage(image);
    try {
      File f = new File("imgr/"+ nam +".png");
      ImageIO.write(bufferedImage,"png",f);
      System.out.println("Image created Successfully");
    } catch(IOException io) {
      SO.coml("error in ImageIO.write");
    }
  }
  void writeTo(String fname,String s) {
    try {
      BufferedWriter out = new BufferedWriter(new FileWriter(fname));
      out.write(s);
      out.close(); 
    } catch (IOException e) { } 
  }

  void setup() {
    pack();
    setVisible(false);
    pane = getContentPane();
    // ((JComponent)pane).setOpaque(true);
    imgRad = imgWide;
    image = pane.createImage(imgWide,imgHigh);
    gr = (Graphics2D)image.getGraphics();
    // gr.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1f));
    gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
	 histoQ ? RenderingHints.VALUE_ANTIALIAS_OFF
		: RenderingHints.VALUE_ANTIALIAS_ON);
  }
  void clear(Color col) {
    gr.clearRect(0,0,imgWide,imgHigh);
    gr.setColor(col);
    gr.fillRect(0,0,imgWide,imgHigh);
  }

  /*
   *	Spaces: 
   *
   */
  double maxAng = 60d;
  double incAng = 5d;
				// rad2ang
  double radToAng(double r) {
    return Math.asin(r)/Math.PI*180d;
  }
  double angToRad(double a) {
    return Math.sin(a*Math.PI/180d);
  }
  double maxRad = angToRad(maxAng);
				// rad2img
  double radToImg(double r) {
    return r/maxRad*imgRad;
  }
  double imgToRad(double i) {
    return i/imgRad*maxRad;
  }
				// img2ang compound inverse transforms
  double imgToAng(double i) {
    return radToAng(imgToRad(i));
  }
  double angToImg(double a) {
    return radToImg(angToRad(a));
  }
  double pwr = 0.32;
  double mul = 38;
  double startCol = 0.80;
  int getColor(double val) {
    Vec3 vc = Vec3.spectrum(startCol + Math.pow(val*mul,pwr));
    int r = (int)(vc.x()*256)%256;
    int g = (int)(vc.y()*256)%256;
    int b = (int)(vc.z()*256)%256;
    return r << 16 | g << 8 | b | 0xFF000000;
  }
  void drawString(int x,int y,String s) {
    FontRenderContext frc = gr.getFontRenderContext();
    Font f = new Font("Helvetica",Font.BOLD, 18);
    TextLayout tl = new TextLayout(s, f, frc);
    tl.draw(gr, x,y);
  }
  double spwr = 6d;
  void drawKey() {
    int ih1 = 400;
    int ih2 = 998;
    int iw1 = 900;
    int iw2 = 998;
    int ihd = ih2 - ih1;
    int iwd = iw2 - iw1;
    for (int ih = ih1; ih < ih2; ih++) {
      float frac = (float)(ih - ih1)/(float)ihd;
      double lg = 1d - Math.pow(1d - frac,1d/spwr);
      gr.setColor(new Color(getColor(lg),false));
      gr.drawLine(iw1,ih,iw2,ih);
    }
    gr.setColor(Color.white);
    gr.drawLine(iw1,ih1,iw1,ih2);
    gr.drawLine(iw1,ih1,iw2,ih1);
    for (int i = 1; i < 10; i++) {
      float frac = (float)i/(float)10;
      double lg = Math.pow(frac,spwr);
      int ih = ih2 - (int)(ihd*lg);
      gr.drawLine(iw1,ih,iw2,ih);
      if (i > 4)
        drawString(iw1 + 12,ih2 - (int)(ihd*lg) - 2,"."+ Integer.toString(i));
    }
    for (int i = 80; i < 100; i++) {
      float frac = (float)i/(float)100;
      double lg = Math.pow(frac,spwr);
      int ih = ih2 - (int)(ihd*lg);
      gr.drawLine(iw1,ih,iw1 + 10,ih);
    }
  }
  void drawGraphic(String name) {
    setup();
    clear(Color.gray);
    BufferedImage bufImg = getBufferedImageFromImage(image);
    data = new Data("ratios/"+ name);
    int col;
    int gray = 160 << 16 | 160 << 8 | 160;
    int mod;
    for (int iw = 0; iw < imgWide; iw++) {
      for (int ih = 0; ih < imgHigh; ih++) {
	double rx = imgToRad((double)iw);
	double ry = imgToRad((double)ih);
	double radP = Math.hypot(rx,ry);	// polar rad
	double angP = Math.asin(ry/radP);	// polar ang
	double ra = rescaleQ			// nonlinear rescale
		? Math.asin(radP)/Math.PI*180d
		: radP*maxAng;
	double ax = Math.cos(angP)*ra;
	double ay = Math.sin(angP)*ra/Math.cos(rx/maxRad);
	double val = data.get(ay,ax);
	if (val < 0.0 || radP > 1d) col = gray;
	else if (ra > 45 && 
		(mod = (79 - (int)ra)/5) > 0 && 
		(10000 + iw - ih*2)%(mod*4) < 5) col = gray;
	else col = getColor(val);
	bufImg.setRGB(iw,ih,col);
      }
    }
    gr.drawImage(bufImg, 0,0,null);
    gr.setStroke(new BasicStroke(0.8f));
    gr.setColor(Color.black);
    double ang;
    for (ang = 0d; ang <= maxAng; ang += incAng) {
      double r  = angToRad(ang);
      double ri = radToImg(r);
      Shape shape = new Arc2D.Double(-ri,-ri, ri*2,ri*2, 270d,90d, Arc2D.OPEN) ;
      gr.draw(shape);
      drawString((int)ri + 4,20,Integer.toString((int)ang));
    }
    for (ang = 0d; ang <= 90d; ang += 15d) {
      double a = ang*Math.PI/180d;
      Shape shape = new Line2D.Double(0d,0d,
	Math.cos(a)*imgRad,Math.sin(a)*imgRad);
      gr.draw(shape);
    }
    for (int i = 0; i < 5; i++)		// kludge for transparency
      drawKey();
    saveAsPNG(name);
    writeTo("sample",name);
  }

  void parseOpts(String[] argv) {
    int iarg = 0;
    while (iarg < argv.length) {
      iarg++;
    }
    String fnam = argv[0];
    drawGraphic(fnam);
    System.exit(0);
  }
  public void run() {
	// todo
  }
  public static void main(String[] argv) {
    Polar that = new Polar();
    that.parseOpts(argv);
  }
}

