import toxi.geom.*;
import toxi.geom.mesh.subdiv.*;
import toxi.geom.mesh.*;
import toxi.processing.*;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import delaunay_triangulation.Delaunay_Triangulation;
import delaunay_triangulation.Point_dt;
import delaunay_triangulation.Triangle_dt;
import java.util.ArrayList;
import java.util.List;
import processing.core.*;
import codeanticode.glgraphics.*;
import processing.opengl.*;
import javax.media.opengl.*;

public class Buildings {
  private GLModel city;
  private float symbolRadius;
  private PApplet p;
  private List <Building> buildings;
  private Delaunay_Triangulation dt;
  private Point_dt[] roof;

  public Buildings(PApplet parent) {
    p = parent;
    buildings = new ArrayList <Building> ();
    drawBuildingsFromJSON();
  }

  private void drawBuildingsFromJSON() {
    JSONParser parser = new JSONParser();
    int i, j;
    i = j = 0;
    int c = 0;
    try {
      //Object in = parser.parse((new FileReader("C:\\Users\\solipsy\\Documents\\Processing\\!MAPS\\vector_gl\\Data\\builds.json")));
      Object in = parser.parse((new FileReader(p.dataPath("builds.json"))));
      JSONObject jsonObject = (JSONObject) in;
      JSONArray paths = (JSONArray) jsonObject.get(("paths"));

      Iterator<JSONArray> i1 = paths.iterator();
      while (i1.hasNext ()) { // seznam
        Building b = new Building(p);
        JSONArray path = (JSONArray) i1.next();
        int loopLength = path.size();
        j = 0;
        Iterator<JSONArray> i2 = path.iterator();
        while (i2.hasNext ()) { // zgradbe

          JSONArray coords = (JSONArray) i2.next();
          Double x = (Double) coords.get(0);
          Double y = (Double) coords.get(1);
          double x1 = x;
          double y1 = y;
          float jpointx =  (float) x1; // (float) coords.get(0);
          float jpointy =  (float) y1;
          b.addPair(jpointx, jpointy);
        }
        buildings.add(b);
        c++;
        j++;
      }
      i++;
    } 
    catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
    catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
    catch (ParseException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    p.println ("zgradb: " + buildings.size());
    WETriangleMesh mesh= new WETriangleMesh("iso"); 

    //build GL Model

    for (Building house : buildings) {
      List <float []> coordList = house.getCoordList();
      float [] zero = (float[]) coordList.get(0);
      float hhh = (int) (p.random (5, 20)); //200 / (p.abs (zero[0] + p.abs (zero[1]))))
      WETriangleMesh build = new WETriangleMesh();      
      for (i = 0; i < coordList.size()-1; i++) {
        float [] pair = (float[]) coordList.get(i);
        float [] pair1 = (float[]) coordList.get(i+1);
        Vec3D from = new Vec3D (pair [0], pair [1], 0);
        Vec3D to   = new Vec3D (pair1 [0], pair1 [1], 0);
        Vec3D from1 = new Vec3D (pair [0], pair [1], hhh);
        Vec3D to1   = new Vec3D (pair1 [0], pair1 [1], hhh);
        build.addFace (from, to, from1); 
        build.addFace (to, to1, from1);
      }
      //delaunay
      roof = new Point_dt [coordList.size()];
      for (i = 0; i < coordList.size(); i++) {
        float [] pair = (float[]) coordList.get(i);
        roof[i] = new Point_dt (pair[0], pair[1]);
      }
      dt = new Delaunay_Triangulation(roof);
      Iterator<Triangle_dt> tris = dt.trianglesIterator();
      while (tris.hasNext ()) {
        Triangle_dt trie = tris.next();
        Point_dt at = trie.p1();
        Point_dt bt = trie.p2();
        Point_dt ct = trie.p3();
        if (at != null && bt != null && ct != null) {
          Vec3D av = new Vec3D ((float) at.x(), (float)at.y(), hhh);
          Vec3D bv = new Vec3D ((float)bt.x(), (float)bt.y(), hhh);
          Vec3D cv = new Vec3D ((float)ct.x(), (float)ct.y(), hhh);
          build.addFace(av, bv, cv);
        }
      }

        mesh.addMesh(build);
      }
      mesh.computeVertexNormals();
      float[] verts=mesh.getMeshAsVertexArray();
      int numV=verts.length/4;  
      float[] norms=mesh.getVertexNormalsAsArray();
      p.println ("vertex array len: " + verts.length);
      p.println ("normals array len: " + norms.length);

      city = new GLModel(p, numV, p.TRIANGLES, GLModel.STATIC);
      city.beginUpdateVertices();
      for (i = 0; i < numV; i++) city.updateVertex(i, verts[4 * i], verts[4 * i + 1], verts[4 * i + 2]);
      city.endUpdateVertices();

      city.initNormals();
      city.beginUpdateNormals();
      for (i = 0; i < numV; i++) city.updateNormal(i, norms[4 * i], norms[4 * i + 1], norms[4 * i + 2]);
      city.endUpdateNormals();  

      city.initColors();
      city.beginUpdateColors();
      for (i = 0; i < numV; i++) city.updateColor(i, 255, 255, 255, 255);
      city.endUpdateColors(); 

      // Setting model shininess.
      city.setShininess(32);
    }



    public GLModel getGLModel () {
      return city;
    }

    public void drawGL ( int mx, int my, List<Car> cars) { //, List<Car> cars
      Car car = cars.get(1);
      p.fill (255, 0, 0);
      p.rect (car.getPosX(), car.getPosY(), 8, 8);
      p.rect (car.getRoad().getTo().getX(), car.getRoad().getTo().getY(), 8, 8);
      p.fill (255);
      //p.println (mx + " "  + my);
      GLGraphics renderer = (GLGraphics)p.g;
      renderer.beginGL();
      renderer.gl.glEnable(GL.GL_LIGHTING);
      //renderer.gl.glDisable(GL.GL_COLOR_MATERIAL);
      renderer.gl.glEnable(GL.GL_COLOR_MATERIAL);
      renderer.gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR); 
      //renderer.gl.glEnable(GL.GL_LIGHT0);
      //renderer.gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, new float[] {1.0f, 1.0f, 1.0f, 1}      , 0);
      //renderer.gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, new float[] {1, 1, 1, 1}, 0);  
      //renderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, new float[] {-1000, 600, 2000, 0}, 0);
      //renderer.gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, new float[] {1, 1, 1, 1}, 0); 
      int lightZ = 300;
      //p.spotLight(255.0f, 0.0f, 0.0f, 500.0f, 0.0f, 10.0f, (float) mx, (float)  my, 0.0f, p.PI/2, 100.0f); 

      //p.pointLight(0, 0, 255, p.width - mx, p.height - my, lightZ); 
      p.spotLight(255.0f, 0.0f, 0.0f, 0.0f, 0.0f, 20.0f, (float) mx, (float) my, 2.0f, p.PI/2, 60.0f); 
      //p.directionalLight(0, 0, 255, -1000, -1000, 1000); 
      //p.directionalLight(0, 255, 255, -1000, 1000, 100); 
      p.directionalLight(255, 255, 0, 0, 1000, 1000);     
      p.directionalLight(255, 0, 200, 1000, 0, 1000);   
      //for (int i = 1; i < 2; i++) {
      //Car car = cars.get(1);
      float dirX = car.getRoad().getTo().getX();
      float dirY = car.getRoad().getTo().getY();
      //p.pointLight(0, 255, 255, dirX, dirY, 0);
      p.spotLight(0.0f, 0.0f, 255.0f, car.getPosX(), car.getPosY(), 10.0f, dirX  + 1817, dirY  + 1527, 0.0f, p.PI/2, 60.0f); 
      p.fill (255, 0, 0);
      p.rect (car.getRoad().getTo().getX(), car.getRoad().getTo().getY(), 8, 8);
      p.fill (255);
      //      p.println (car.getPosX() + " " +  car.getPosY()); 
      //      p.println (car.getRoad().getFrom().getX() + " " +  car.getRoad().getFrom().getY());  
      //      p.println ("--");

      //}

      // car.getRoad().getTo()
      renderer.setBlendMode(p.ADD);
      renderer.model(city);
      renderer.endGL();
    }

    public void draw() {
      for (Building b : buildings) {
        b.draw();
      }
    }
  }

