import java.awt.*;
import java.io.*;
import java.net.*;
import java.util.*;
import Renderable;
import Vector3D;
import Ray;
import Surface;
import Sphere;

public class RayTrace {

  Vector objectList;
  Vector lightList;
  Color background = new Color(0,0,0);
  Image screen;
  Graphics gc;
  int height, width;
  boolean viewSet = false;
  Vector3D Eye, Du, Dv, Vp;
  
  public RayTrace(Vector objects, Vector lights, Image scr) {
    lightList = lights;
    objectList = objects;
    screen = scr;
    height = screen.getHeight(null);
    width = screen.getWidth(null);
    gc = screen.getGraphics();
  }

  public void setBackground(Color bgnd) {
    background = bgnd;
  }

  public Image getScreen() {
    return screen;
  }

  public void setView(Vector3D eye, Vector3D lookat, Vector3D up, float fov) {
    // Compute mapping from screen coordinate to a ray direction
    Vector3D look = new Vector3D(lookat.x - eye.x, lookat.y - eye.y, lookat.z - eye.z);
    float fl = (float)(width / (2*Math.tan((0.5*fov)*Math.PI/180)));

    Eye = eye;
    Du = Vector3D.normalize(look.cross(up));
    Dv = Vector3D.normalize(look.cross(Du));
    Vp = Vector3D.normalize(look);
    Vp.x = Vp.x*fl - 0.5f*(width*Du.x + height*Dv.x);
    Vp.y = Vp.y*fl - 0.5f*(width*Du.y + height*Dv.y);
    Vp.z = Vp.z*fl - 0.5f*(width*Du.z + height*Dv.z);
    viewSet=true;
  }
   
  public void renderPixel(int i, int j) {
    Vector3D dir = new Vector3D(
                                i*Du.x + j*Dv.x + Vp.x,
                                i*Du.y + j*Dv.y + Vp.y,
                                i*Du.z + j*Dv.z + Vp.z);
    Ray ray = new Ray(Eye, dir);
    if (ray.trace(objectList)) {
      gc.setColor(ray.Shade(lightList, objectList, background));
    } else {
      gc.setColor(background);
    }
    gc.drawLine(i, j, i, j);        // oh well, it works.
  }

  public void renderScanLine(int j) {
    if (!viewSet)
      setView(new Vector3D(0,0,10), new Vector3D(0,0,0), new Vector3D(0,1,0), 30);

    if (j >= 0 && j < height)
      for (int i = 0; i < width; i++) {
        renderPixel(i, j);
      }
  }

  public void renderScreen() {
    if (!viewSet)
      setView(new Vector3D(0,0,10), new Vector3D(0,0,0), new Vector3D(0,1,0), 30);

    for (int j = 0; j < height; j++) {
      for (int i = 0; i < width; i++) {
        renderPixel(i, j);
      }
    }
  }

}
