package ip.raul;

import java.awt.*;
import java.awt.event.*;

public class SnowMan extends Frame
    implements Runnable, KeyListener, WindowListener,
    MouseListener, MouseMotionListener {

  Thread idx_Thread = null;
  boolean initialized = false;
  public idx3d demo;
  float oldx,oldy;
  float xrot = 64;
  float yrot = 32;
  float zrot = 17;
  float dx = 0;
  float dy = 0;
  float dz = 0;
  int mode;
  boolean autorot = true;

  public static void main(String args[]) {
    SnowMan f = new SnowMan();
    f.setSize(400, 400);
    f.setVisible(true);
    f.initialize();
    f.start();
    f.addSnowMan();
    for (int i = 1; i <= f.demo.objects; i++)
      f.demo.object[i].mode = 6;
  }

  public static void image3D() {
    SnowMan f = new SnowMan();
    f.setSize(400, 400);
    f.setVisible(true);
    f.initialize();
    f.start();
    for (int i = 1; i <= f.demo.objects; i++)
      f.demo.object[i].mode = 6;
  }

  void addImageField(short s[][]) {
    int fieldres = 40;
    int fieldcolor = demo.getIntColor(255, 96, 0);
    float map[][] = new float[fieldres][fieldres];
    for (int i = 1; i < fieldres - 1; i++) {
      for (int j = 1; j < fieldres - 1; j++) {
        int x = s.length * i / fieldres;
        int y = s[0].length * j / fieldres;
        map[i][j] = (float) (s[x][y] / 255.0);
      }
    }
    demo.generateField(map, fieldres, fieldres, mode, fieldcolor);
    demo.object[1].texture = 1;
  }

  public void initialize(Image i, short s[][]) {
    addListeners();
    demo = new idx3d(getSize().width, getSize().height);
    int mode = 1;
    demo.addTexture(i);
    addImageField(s);
    addLights();
    demo.reflectivity = 200;
    demo.setStatic();
    demo.scaleWorld(1.6f);
    demo.rotateWorld(0f, 0f, 150f);
    demo.shiftObject(1, 0, -.8f, 0);
    initialized = true;
//      autorot=false;
  }

  public static void image3D(Image img, short s[][]) {
    SnowMan f = new SnowMan();
    f.setSize(s.length, s[0].length);
    f.setVisible(true);
    f.initialize(img, s);
    f.start();
    for (int i = 1; i <= f.demo.objects; i++) {
      f.demo.object[i].mode = 6;
    }
  }


  public void addSphere(double xc, double yc, double zc, double radius, int texture) {
    float r = 0;
    float ry = 0;
    int scancolor = demo.getIntColor(60, 255, 20);
    demo.addObject(mode, scancolor);
    int obj = demo.objects;
    float twoPi = 2f * (float) Math.PI;
    float x1, y1, z1;
    int numberOfSteps = 8;
    int h = 8;
    float deltaTheta = (float) (twoPi / (numberOfSteps - 1f));
    float deltaY = (float) (2f * radius / (float) (h - 1f));
    for (int i = 0; i <= numberOfSteps; i++)
      for (int y = 0; y < h; y++) {
        ry = (float) (y * deltaY);
        r = (float) (ry * (float) (2f * radius - ry));
        r = (float) Math.sqrt(r);
        x1 = (float) xc + (float) (r * Math.sin((float) (i * deltaTheta)));
        y1 = (float) yc - (float) radius + ry;
        z1 = (float) zc + (float) (r * Math.cos((float) (i * deltaTheta)));
        demo.addNode(obj, x1, y1, z1);
      }
    demo.generateScanObject1(obj, h, numberOfSteps);
    demo.object[obj].texture = texture;
  }

  public void addCylinder(double xc, double yc, double zc, double R, double H, int texture) {
    float r = 0;
    float ry = 0;
    int scancolor = demo.getIntColor(60, 255, 20);
    demo.addObject(mode, scancolor);
    int obj = demo.objects;
    float twoPi = 2f * (float) Math.PI;
    float x1, y1, z1;
    int numberOfSteps = 12;
    int h = 2;
    float deltaTheta = (float) (twoPi / (numberOfSteps - 1f));
    double deltaY = (double) (H / (double) (h - 1f));
    for (int i = 0; i <= numberOfSteps; i++) {
      for (int y = 0; y < h; y++) {
        x1 = (float) xc + (float) (R * Math.sin((float) (i * deltaTheta)));
        y1 = (float) yc + (float) (y * deltaY);
        z1 = (float) zc + (float) (R * Math.cos((float) (i * deltaTheta)));
        if (y == 0)
          demo.addNode(obj, (float) xc, (float) yc, (float) zc);
        demo.addNode(obj, x1, y1, z1);
        if (y == h - 1)
          demo.addNode(obj, (float) xc, (float) (yc + H), (float) zc);
      }
    }
    demo.generateScanObject1(obj, h + 2, numberOfSteps);
    demo.object[obj].texture = texture;
  }

  public void addParalelipiped(double xc, double yc, double zc, double W, double L, double H, int texture) {
    int scancolor = demo.getIntColor(60, 255, 20);
    demo.addObject(mode, scancolor);
    int obj = demo.objects;
    float x1, y1, z1;
    x1 = (float) xc - (float) (W / 2f);
    y1 = (float) yc - (float) (H / 2f);
    z1 = (float) zc - (float) (L / 2f);
    //side 1
    demo.addNode(obj, (float) xc, (float) (yc - H / 2), (float) zc);
    demo.addNode(obj, x1, y1, z1);
    y1 = (float) yc + (float) (H / 2f);
    demo.addNode(obj, x1, y1, z1);
    demo.addNode(obj, (float) xc, (float) (yc + H / 2), (float) zc);
    y1 = (float) yc - (float) (H / 2f);
    //side 2
    x1 = (float) xc + (float) (W / 2f);
    demo.addNode(obj, (float) xc, (float) (yc - H / 2), (float) zc);
    demo.addNode(obj, x1, y1, z1);
    y1 = (float) yc + (float) (H / 2f);
    demo.addNode(obj, x1, y1, z1);
    demo.addNode(obj, (float) xc, (float) (yc + H / 2), (float) zc);
    y1 = (float) yc - (float) (H / 2f);
    //side 3
    z1 = (float) zc + (float) (L / 2f);
    demo.addNode(obj, (float) xc, (float) (yc - H / 2), (float) zc);
    demo.addNode(obj, x1, y1, z1);
    y1 = (float) yc + (float) (H / 2f);
    demo.addNode(obj, x1, y1, z1);
    demo.addNode(obj, (float) xc, (float) (yc + H / 2), (float) zc);
    y1 = (float) yc - (float) (H / 2f);
    //side4
    x1 = (float) xc - (float) (W / 2f);
    demo.addNode(obj, (float) xc, (float) (yc - H / 2), (float) zc);
    demo.addNode(obj, x1, y1, z1);
    y1 = (float) yc + (float) (H / 2f);
    demo.addNode(obj, x1, y1, z1);
    demo.addNode(obj, (float) xc, (float) (yc + H / 2), (float) zc);
    y1 = (float) yc - (float) (H / 2f);
    //side5
    z1 = (float) zc - (float) (L / 2f);
    demo.addNode(obj, (float) xc, (float) (yc - H / 2), (float) zc);
    demo.addNode(obj, x1, y1, z1);
    y1 = (float) yc + (float) (H / 2f);
    demo.addNode(obj, x1, y1, z1);
    demo.addNode(obj, (float) xc, (float) (yc + H / 2), (float) zc);
    y1 = (float) yc - (float) (H / 2f);

    demo.generateScanObject1(obj, 4, 4);
    demo.object[obj].texture = texture;
  }


  public void initialize() {
    addListeners();
    demo = new idx3d(getSize().width, getSize().height);
    int mode = 2;
    demo.addTexture(NumImage.getImage());
    addLights();
    demo.reflectivity = 200;
    demo.setStatic();
    autorot = false;
    initialized = true;
  }

  public void addSnowMan() {
    addSphere(0.05, -0.3, 0.0, 0.3, 0);
    addSphere(0.05, 0.06, 0.0, 0.24, 0);
    addSphere(0.05, 0.19, -0.205, 0.01, 0);
    addSphere(0.05, 0.09, -0.237, 0.01, 0);
    addSphere(0.05, 0.0, -0.230, 0.01, 0);
    addSphere(0.05, 0.32, -0.205, 0.018, 0);
    addSphere(0.05, 0.34, 0.0, 0.2, 0);
    addSphere(0.1, 0.4, -0.195, 0.02, 0);
    addSphere(-0.02, 0.393, -0.185, 0.02, 0);
  }

  public void paint(Graphics gx) {
    gx.setColor(Color.black);
    gx.fillRect(0, 0, this.getSize().width, this.getSize().height);
    gx.setColor(new Color(0, 255, 0));
  }

  public void start() {
    if (idx_Thread == null) {
      idx_Thread = new Thread(this);
      idx_Thread.start();
    }
  }

  public void stop() {
    if (idx_Thread != null) {
      idx_Thread = null;
    }
  }

  public void run() {
    while (true) {
      repaint();
      try {
        idx_Thread.sleep(20);
      } catch (InterruptedException e) {
        System.out.println("graphics.idx://interrupted");
      }
    }
  }

  public void update(Graphics g) {
    if (initialized) {
      if (autorot) {
        demo.rotateWorld(0, 5, 0);
      }
      g.drawImage(demo.renderScene(), 0, 0, this);
    } else {
      paint(g);
      initialize();
    }
  }

  void addImageField() {
    int fieldres = 20;
    int fieldcolor = demo.getIntColor(255, 96, 0);
    float map[][] = new float[fieldres][fieldres];
    for (int i = 2; i < fieldres; i++) {
      for (int j = 2; j < fieldres; j++) {
        int x = NumImage.gray.length * i / fieldres;
        int y = NumImage.gray[0].length * j / fieldres;
        map[i][j] = (float) (NumImage.gray[x][y] / 255.0);
      }
    }
    demo.generateField(map, fieldres, fieldres, mode, fieldcolor);
    demo.object[1].texture = 1;
    demo.rotateObject(1, 0, (float) 180, (float) 180);
    demo.shiftObject(1, 0, (float) 0.5, 0);
  }

  void addLights() {
    demo.ambient = 48;
    demo.setPhong(64);
    demo.addLight(new idx3d_vector((float) 0, (float) 0, (float) -1), 1, 164);
    demo.addLight(new idx3d_vector((float) 2, (float) -4, (float) -1), 1, 144);
  }

  private static void waitForImage(Component component, Image image) {
    MediaTracker tracker = new MediaTracker(component);
    try {
      tracker.addImage(image, 0);
      tracker.waitForID(0);
      if (!tracker.checkID(0))
        System.out.println("Load failure!");
    } catch (InterruptedException e) {
    }
  }

  public void addListeners() {
    addWindowListener(this);
    addMouseListener(this);
    addMouseMotionListener(this);
    addKeyListener(this);
  }

  public void keyTyped(KeyEvent e) {
    mode = (mode + 1) % 8;
    for (int i = 1; i <= demo.objects; i++)
      demo.object[i].mode = mode;
  }

  public void mousePressed(MouseEvent evt) {
    autorot = false;
    oldx = evt.getX();
    oldy = evt.getY();
  }

  public void mouseReleased(MouseEvent evt) {
    autorot = true;
    oldx = evt.getX();
    oldy = evt.getY();
  }

  public void mouseDragged(MouseEvent evt) {
    int x = evt.getX();
    int y = evt.getY();
    demo.rotateWorld((oldy - y), (oldx - x), 0);
    dx = (dx + oldx - x + 360) % 360;
    dy = (dy + oldy - y + 360) % 360;
    oldx = x;
    oldy = y;
  }

  public void mouseMoved(MouseEvent evt) {
  };
  public void mouseClicked(MouseEvent evt) {
  };
  public void mouseEntered(MouseEvent evt) {
  };
  public void mouseExited(MouseEvent evt) {
  };

  public void windowClosing(WindowEvent e) {
    dispose();
  }

  public void windowClosed(WindowEvent e) {
  };
  public void windowDeiconified(WindowEvent e) {
  };
  public void windowIconified(WindowEvent e) {
  };
  public void windowActivated(WindowEvent e) {
  };
  public void windowDeactivated(WindowEvent e) {
  };
  public void windowOpened(WindowEvent e) {
  };
  public void keyPressed(KeyEvent e) {
  };
  public void keyReleased(KeyEvent e) {
  };

}