import * as THREE from 'three'

//VTK解析器
const VTKLoader = function () {

  this.load = (url, callback) => {// 加载函数，url表示要加载的vtk文件的url路径，callback表示加载完成后要调用的后续处理函数，这里是异步操作，加载需要一个过程，不能将程序阻塞在这里，所以需要异步回调
    var scope = this;// 将类自身保存在scope中，scope表示域的意思，这里是为了避免this的歧义，因为，每一个地方使用this，其意义不一样。
    var request = new XMLHttpRequest();// ajax 异步请求
    request.addEventListener('load', function (event) {// 加载完成的监听器，加载完成后，将调用第二个参数定义的回调函数
      var geometry = scope.parse(event.target.responseText);// 对服务器加载下来的数据进行解析
      // scope.dispatchEvent({ type: 'load', content: geometry });// 解析完成后，发一个load事件，表示数据解析完成
      if (callback) callback(geometry);// 如果设置了回调函数，那么调用回调函数
    }, false);
    request.addEventListener('progress', function (event) {// 加载过程中，向自身发送进度progress信息，信息中包含已经加载的数据的字节数和文件总共的字节数，通过两者的百分比能够了解加载进度。
      // scope.dispatchEvent({ type: 'progress', loaded: event.loaded, total: event.total });// 发送正在加载的消息，两个参数分别是已经加载了多少字节，总共多少字节
    }, false);
    request.addEventListener('error', function () {// 加载出错的监听器，加载的过程也可能出错，这里如果出错，进行错误处理，
      // scope.dispatchEvent({ type: 'error', message: 'Couldn\'t load URL [' + url + ']' });// 加载出错之后需要发布的错误消息
    }, false);
    request.open('GET', url, true);// 初始化 HTTP 请求参数，例如 URL 和 HTTP 方法，但是并不发送请求。
    request.send(null);//发送 HTTP 请求，开始下载
  },

    this.parse = (data) => {// parse函数在上面调用过，主要负责解析数据的功能,data是从服务器传过来的数据，其实就是vtk文件中的文本数据。
      console.log(data)
      var geometry = new THREE.Geometry();// new 一个几何体
      function vertex(x, y, z) {// 定义一个内部函数vertex，用参数x,y,z生成一个顶点，并放入geometry的vertices数组中
        geometry.vertices.push(new THREE.Vector3(x, y, z));
      }
      function face3(a, b, c) {// 定义一个面索引函数face3，将面的3个点的索引放入geometry的faces数组中
        geometry.faces.push(new THREE.Face3(a, b, c));
      }
      function face4(a, b, c, d) {// 定义一个面索引函数。如果一个面由4个顶点组成，那么我们构造一个Face4放入faces中，注意面可以由在同一平面的3个点组成，也可以由同一平面的4个顶点组成。
        geometry.faces.push(new THREE.Face4(a, b, c, d));
      }
      var pattern, result;// pattern存放模式字符串，result是临时变量
      // float float float
      pattern = /([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)[ ]+([\+|\-]?[\d]+[\.][\d|\-|e]+)/g;// pattern是一个正则表达式，能够匹配2个空格隔开的float，如-0.0378297 0.12794 0.00447467都是pattern的菜。
      while ((result = pattern.exec(data)) != null) {//while 循环在data中，寻找符合正则表示式的数据，将符合条件的数据，转换为一个顶点, exec是正则表达式的执行匹配函数，result返回一个包含3个字符串的数组，如果data读到了最后，那么result将返回null
        // ["1.0 2.0 3.0", "1.0", "2.0", "3.0"]
        vertex(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3]));// 将字符串转换为float，并放入geometry中
      }
      // 3 int int int
      pattern = /3[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;// 这里匹配面数据，如3 21216 21215 20399，这类数据是面索引数据
      while ((result = pattern.exec(data)) != null) {// 取出data中的所有面索引数据
        // ["3 1 2 3", "1", "2", "3"]
        face3(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]));// 将面数据放入geometry的faces中
      }
      // 4 int int int int
      pattern = /4[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)[ ]+([\d]+)/g;// 这里是4个顶点一个面的情况，本例的vtk文件，没有这种情况
      while ((result = pattern.exec(data)) != null) {
        // ["4 1 2 3 4", "1", "2", "3", "4"]
        face4(parseInt(result[1]), parseInt(result[2]), parseInt(result[3]), parseInt(result[4]));
      }


      //这4个函数的计算结果，在threejs引擎中，会用到，所以，你自己写加载某种模型的解析器时，最好也调用一下，这几个函数。

      // geometry.computeCentroids();//计算geometry中每一个面的重心，无论在平面坐标系还是空间坐标系中，重心可以求坐标的平均值来得到
      // geometry.computeFaceNormals();//计算每一个面归一化后的法向量，法向量垂直于面。计算之后的法向量被存放在了face.normal中。法向量与模型受光情况有关
      // geometry.computeVertexNormals();//计算每一个顶点的法向量。
      // geometry.computeBoundingSphere();//计算一个可以包围geometry的一个椭圆，中心点就是geometry的中心，sphere的最大半径是离中心点最远的那一个点。
      console.log(geometry)
      return geometry;
    }
}

export {
  VTKLoader
}
