package graphics.draw2d;


import java.awt.*;
import java.util.Vector;

class Shapes extends Shape {
  //ComponentMoveFrame cmf;

  // Number of times ray reflects befor fading away
  final static int maxCount = 3;

  // Refractive index
  final static double refIndex = 1.2;

  Circle2d closestCircle;


  private Vector v = new Vector();

  public void add(Paintable d) {
    if (d == null) {
      System.out.println("d==null!!");
    }
    v.addElement(d);
    //cmf.add((Component)d);
    //cmf.repaint();
  }

  public void paint(Graphics g) {
    for (int i = 0; i < v.size(); i++) {
      Paintable d =
          (Paintable) v.elementAt(i);
      d.paint(g);
    }
  }

  public Line2d getLastLine() {
    for (int i = v.size() - 1; i >= 0; i--)
      if (v.elementAt(i) instanceof Line2d)
        return
            (Line2d) v.elementAt(i);
    return null;
  }

  public Circle2d getLastCircle() {
    for (int i = v.size() - 1; i >= 0; i--)
      if (v.elementAt(i) instanceof Circle2d)
        return
            (Circle2d) v.elementAt(i);
    return null;
  }

  public Vec2d getClosestPoint(Ray2d ray) {
    double maxDist = 1000000;
    Vec2d closestSoFar = null;

    for (int i = v.size() - 1; i >= 0; i--) {
      if (!(v.elementAt(i) instanceof Intersects))
        continue;
      Intersects inter = (Intersects) v.elementAt(i);
      Vec2d vc = inter.intersect(ray);
      if (vc == null) continue;
      if (ray.t >= maxDist) continue;
      closestSoFar = vc;
      if (v.elementAt(i) instanceof Circle2d) {
        closestCircle = (Circle2d) v.elementAt(i);
      } else {
        closestCircle = null;
      }
      maxDist = ray.t;
    }
    return closestSoFar;
  }

  public void addLineToLastCircle() {

    Ray2d rl;
    Ray2d rf;

    Line2d l = getLastLine();
    if (l == null) return;
    Ray2d r = new Ray2d(l);
    addLineToLastCircle(r);
  }

  public void addLineToLastCircle(Ray2d r) {

    Vec2d v = getClosestPoint(r);
    if (v == null) return;

    if (closestCircle != null) {

      Ray2d rl = getReflectRay(closestCircle, v, r.d);
      Ray2d rf = getRefractRay(closestCircle, r.p, v, r.d);

      rl.p.add(rl.d);
      rf.p.add(rf.d);

      add(new Line2d(rl.p, rl.vecOnLine(50)));
      add(new Line2d(rf.p, rf.vecOnLine(50)));

      if (r.count < maxCount) {
        rl.count = r.count + 1;
        addLineToLastCircle(rl);
      }
      if (r.count < maxCount) {
        rf.count = r.count + 1;
        addLineToLastCircle(rf);
      }
    }
    add(new Line2d(r.p, v));
  }

  public Ray2d getReflectRay(Circle2d c, Vec2d p, Vec2d d) {

    Vec2d n = new Vec2d(p);
    n.sub(c.center);
    n.normalize();

    n.mult(2 * d.dot(n));
    d.sub(n);
    Ray2d ref = new Ray2d(p, d);
    return ref;
  }

  public Ray2d getRefractRay(Circle2d c, Vec2d o, Vec2d p, Vec2d d) {

    double t;
    double idx;

    Vec2d n = new Vec2d(p);
    n.sub(c.center);
    n.normalize();


    if (c.inside(o)) {
      idx = 1 / refIndex;
      n.mult(-1);
    } else {
      idx = refIndex;
    }


    t = 1 / d.dot(n);

    Vec2d u = new Vec2d(d);
    Vec2d v = new Vec2d(n);

    u.mult(t);
    v.add(u);


    t = 1 / ((idx * idx) * u.dot(u) - v.dot(v));

    u.mult(t);
    u.sub(n);
    n.mult(t);
    u.add(n);
    u.normalize();

    Ray2d ref = new Ray2d(p, u);
    return ref;

  }

}