const Promise = require('promise');
const THREE = require('three');

module.exports = class M2 extends THREE.Mesh {

  static cache = {};

  constructor(data, skinData) {
    super();

    this.data = data;
    this.skinData = skinData;

    const geometry = this.geometry;

    // TODO: Potentially move these calculations and mesh generation to worker

    const vertices = data.vertices;

    vertices.forEach(function(vertex) {
      const {position} = vertex;
      geometry.vertices.push(
        new THREE.Vector3(position[0], position[1], position[2])
      );
    });

    const uvs = [];

    const {triangles, indices} = skinData;

    for (let i = 0, face = 0; i < triangles.length; i += 3, ++face) {
      const vindices = [
        indices[triangles[i]],
        indices[triangles[i + 1]],
        indices[triangles[i + 2]]
      ];

      geometry.faces.push(new THREE.Face3(
        vindices[0],
        vindices[1],
        vindices[2]
      ));

      uvs[face] = [];
      vindices.forEach(function(index) {
        const {textureCoords} = vertices[index];
        uvs[face].push(new THREE.Vector2(textureCoords[0], textureCoords[1]));
      });
    }

    geometry.faceVertexUvs = [uvs];

    this.material = new THREE.MeshBasicMaterial({ wireframe: true });
  }

  set texture(path) {
    const texture = THREE.ImageUtils.loadTexture(
      encodeURI(`pipeline/${path}`),
      undefined,
      () => {
        texture.flipY = false;
        this.material.wireframe = false;
        this.material.map = texture;
        this.material.needsUpdate = true;
      }
    );
  }

  static load(path) {
    if (!(path in this.cache)) {
      this.cache[path] = new Promise((resolve, reject) => {
        const worker = new Worker('/scripts/workers/pipeline.js');

        worker.addEventListener('message', (event) => {
          const [data, skinData] = event.data;
          resolve(new this(data, skinData));
        });

        worker.postMessage(['M2', path]);
      });
    }
    return this.cache[path];
  }

};

@@ -591,17 +591,16 @@
 s = %5B%5D;%0A
-%0A
     cons
@@ -659,16 +659,21 @@
  0, face
+Index
  = 0; i 
@@ -706,16 +706,21 @@
 , ++face
+Index
 ) %7B%0A    
@@ -860,28 +860,21 @@
     
-geometry.faces.push(
+const face = 
 new 
@@ -885,25 +885,16 @@
 E.Face3(
-%0A        
 vindices
@@ -897,24 +897,16 @@
 ices%5B0%5D,
-%0A       
  vindice
@@ -910,24 +910,16 @@
 ices%5B1%5D,
-%0A       
  vindice
@@ -922,24 +922,49 @@
 dices%5B2%5D
+);
 %0A      
-)
+geometry.faces.push(face
 );%0A%0A    
@@ -973,16 +973,21 @@
 uvs%5Bface
+Index
 %5D = %5B%5D;%0A
@@ -1092,16 +1092,21 @@
 uvs%5Bface
+Index
 %5D.push(n

Use faceIndex