
class Mesh {
  static construct (gl, vertices, indices, uvs, normals) {
    // VBO for model vertices
    let pos = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, pos)
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)

    // Indices Buffer
    let ebo = gl.createBuffer()
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW)

    let mesh = new Mesh()
    mesh.posBuffer = pos
    mesh.ebo = ebo
    mesh.indices = indices.length

    // VBO for model UVs
    if (uvs) {
      let uv = gl.createBuffer()
      gl.bindBuffer(gl.ARRAY_BUFFER, uv)
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvs), gl.STATIC_DRAW)
      mesh.uvs = uv
    }

    // Normals buffer
    if (normals) {
      let nms = gl.createBuffer()
      gl.bindBuffer(gl.ARRAY_BUFFER, nms)
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW)
      mesh.nms = nms
    }

    gl.bindBuffer(gl.ARRAY_BUFFER, null)

    return mesh
  }

  bindBuffers (gl, shader) {
    gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer)
    shader.setAttribute(gl, 'aVertexPosition', 3, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0)

    if (this.nms && shader.hasAttribute(gl, 'aNormal')) {
      gl.bindBuffer(gl.ARRAY_BUFFER, this.nms)
      shader.setAttribute(gl, 'aNormal', 3, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0)
    }

    if (this.uvs && shader.hasAttribute(gl, 'aTexCoords')) {
      gl.bindBuffer(gl.ARRAY_BUFFER, this.uvs)
      shader.setAttribute(gl, 'aTexCoords', 2, false, 2 * Float32Array.BYTES_PER_ELEMENT, 0)
    }

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ebo)
  }

  prepare (gl, shader) {
    // Bind attrib arrays
    this.bindBuffers(gl, shader)

    // Give materials to shader
    if (this.material) {
      this.material.apply(gl, shader)
    }
  }

  draw (gl, shader) {
    gl.drawElements(gl.TRIANGLES, this.indices, gl.UNSIGNED_SHORT, 0)
  }
}

export { Mesh }
