<template>
  <div>
    <object3d ref="block3d" name="Project" :obj="building" :position="building_position"/>
    <object3d ref="top" :obj="top_mesh" :position="top_position"/>
    <object3d ref="floor" :obj="floor_mesh" :position="floor_position"/>
    <!-- <light :obj="light" :position="building_position" /> -->
    <mesh ref="label3d" name="Label" :position="label_position">
      <geometry type="Plane" :args="[label_size.x, label_size.y]" />
      <material type="MeshLambert" :options="label_opts">
        <texture :options="label_texture_opts" />
      </material>
    </mesh>
    <div v-if="isOpened">
      <ContentBlock
        v-for="item in data.visibles"
        :key="item.id"
        :prtPosition="position"
        :prtSize="size"
        type="visible"
        :data="item"
        />
      <ContentBlock
        v-for="item in data.contexts"
        :key="item.id"
        :prtPosition="position"
        :prtSize="size"
        type="context"
        :data="item"
        />
      <ContentBlock
        v-for="item in data.processes"
        :key="item.id"
        :prtPosition="position"
        :prtSize="size"
        type="process"
        :data="item"
        />
      <ContentBlock
        v-for="item in data.concepts"
        :key="item.id"
        :prtPosition="position"
        :prtSize="size"
        type="concept"
        :data="item"
        />
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
// import { toCSG, fromCSG } from 'three-csg'
import { ThreeBSP } from 'three-js-csg-es6'

import mixins from 'components/mixins'
import ContentBlock from 'components/objects/ContentBlock'

// import BgVertex from 'assets/glsl/BgVertex'
// import BuildingFragment from 'assets/glsl/BuildingFragment'

export default {
  name: 'Project',
  components: {
    ContentBlock
  },
  mixins: [mixins],
  // props: { size: Object, texture: String, position: Object, color: Number },
  props: { data: Object, len: Number, index: Number },
  data () {
    console.log('Project data() : data', this.data)
    // get size and positions from project store
    let size = { ...this.data.size }
    let position = { ...this.data.position }

    // http://learningthreejs.com/blog/2011/12/10/constructive-solid-geometry-with-csg-js/
    // console.log('ThreeBSP', ThreeBSP)

    let wallW = 0.001

    let backGeom = new THREE.BoxGeometry(size.x, size.y, wallW)
    let backMesh = new THREE.Mesh(backGeom)
    backMesh.position.z = -0.5 * size.z
    let backBSP = new ThreeBSP(backMesh)

    // dig windows on face and back
    let winW = 2 + Math.random() * 2
    let winH = 4 + Math.random() * 4
    let margin = 2
    let nbrWinX = 0
    let paddingX = 0
    let a = 0
    // removing windows until padding is enough
    while (paddingX < 0.4) {
      nbrWinX = Math.floor((size.x - 2 * margin) / winW) - a
      paddingX = (size.x - 2 * margin - winW * nbrWinX) / (nbrWinX - 1)
      a++
    }
    // console.log('paddingX', paddingX)
    let nbrWinY = 0
    let paddingY = 0
    a = 0
    // removing windows until padding is enough
    while (paddingY < 0.4) {
      nbrWinY = Math.floor((size.y - 2 * margin) / winH) - a
      paddingY = (size.y - 2 * margin - winH * nbrWinY) / (nbrWinY - 1)
      a++
    }
    let winGeom = new THREE.BoxGeometry(winW, winH, wallW)
    let winMesh, winBSP
    for (var i = 0; i < nbrWinX; i++) {
      for (var j = 0; j < nbrWinY; j++) {
        // back
        winMesh = new THREE.Mesh(winGeom)
        winMesh.position.z = -0.5 * size.z
        winMesh.position.x = -0.5 * size.x + margin + winW * 0.5 + i * (winW + paddingX)
        winMesh.position.y = 0.5 * size.y - margin - winH * 0.5 - j * (winH + paddingY)
        winBSP = new ThreeBSP(winMesh)
        backBSP = backBSP.subtract(winBSP)
      }
    }

    // let abovewWaterH = position.y + size.y / 2
    // let underWaterHThd = (-1 * position.y - size.y / 2) / 3
    // let levelH = 4
    // let levelGeom = new THREE.BoxGeometry(size.x, levelH, wallW)
    // let levelMesh, levelBSP
    // for (var l = 0; l < 2; l++) {
    //   levelMesh = new THREE.Mesh(levelGeom)
    //   levelMesh.position.z = -0.5 * size.z
    //   levelMesh.position.y = 0.5 * size.y - abovewWaterH - underWaterHThd - underWaterHThd * l + levelH * 0.5
    //   levelBSP = new ThreeBSP(levelMesh)
    //   backBSP = backBSP.union(levelBSP)
    // }

    backMesh = backBSP.toMesh()
    let faceMesh = backMesh.clone()
    faceMesh.position.z = 0.5 * size.z
    let faceBSP = new ThreeBSP(faceMesh)

    let rightGeom = new THREE.BoxGeometry(wallW, size.y, size.z)
    let rightMesh = new THREE.Mesh(rightGeom)
    rightMesh.position.x = 0.5 * size.x
    // rightMesh.position.z = 0.5 * size.z
    let rightBSP = new ThreeBSP(rightMesh)

    // WE MAY NO NEED TO DIG WINDOWS ON SIDE WALLS
    // // dig windows on right
    // let nbrWinZ = Math.floor((size.z - 2 * margin) / winW)
    // let paddingZ = (size.z - 2 * margin - winW * nbrWinZ) / (nbrWinX - 1)
    // winGeom = new THREE.BoxGeometry(wallW, winH, winW)
    // for (i = 0; i < nbrWinZ; i++) {
    //   for (j = 0; j < nbrWinY; j++) {
    //     // right
    //     winMesh = new THREE.Mesh(winGeom)
    //     winMesh.position.x = 0.5 * size.x
    //     winMesh.position.z = -0.5 * size.z + margin + winW * 0.5 + i * (winW + paddingZ)
    //     winMesh.position.y = 0.5 * size.y - margin - winH * 0.5 - j * (winH + paddingY)
    //     winBSP = new ThreeBSP(winMesh)
    //     rightBSP = rightBSP.subtract(winBSP)
    //   }
    // }
    // rightMesh = rightBSP.toMesh()

    let leftMesh = rightMesh.clone()
    leftMesh.position.x = -0.5 * size.x
    // leftMesh.position.z = 0.5 * size.z
    let leftBSP = new ThreeBSP(leftMesh)
    //
    // let topGeom = new THREE.BoxGeometry(size.x, wallW, size.z)
    // let topMesh = new THREE.Mesh(topGeom)
    // // topMesh.position.y = -0.5 * size.y
    // // let topBSP = new ThreeBSP(topMesh)
    //
    // let floorGeom = new THREE.BoxGeometry(size.x, wallW, size.z)
    // let floorMesh = new THREE.Mesh(floorGeom)
    // // floorMesh.position.y = 0.5 * size.y
    // // let floorBSP = new ThreeBSP(floorMesh)

    let buildingBSP = backBSP.union(rightBSP)
    buildingBSP = buildingBSP.union(faceBSP)
    buildingBSP = buildingBSP.union(leftBSP)
    // buildingBSP = buildingBSP.union(topBSP)
    // buildingBSP = buildingBSP.union(floorBSP)

    // convert back to three.js mesh
    let building = buildingBSP.toMesh()
    console.log('building.faces', building)

    // create a custom shaderMaterial to had gradian colors
    // var uniforms = THREE.UniformsUtils.merge([
    //   THREE.UniformsLib['lights'],
    //   {
    //     'topColor': { value: new THREE.Color(0xffffff) },
    //     'groundColor': { value: new THREE.Color(0xbcd6e4) },
    //     'bottomColor': { value: new THREE.Color(0x07223b) },
    //     // 'bottomColor': { value: new THREE.Color(0x000000) },
    //     // 'groundColor': { value: new THREE.Color(0xff0000) },
    //     // 'bottomColor': { value: new THREE.Color(0x00ff00) },
    //     lightIntensity: { type: 'f', value: 1.0 }
    //   }
    // ])
    // var buildingMat = new THREE.ShaderMaterial({
    //   uniforms: uniforms,
    //   vertexShader: BgVertex,
    //   fragmentShader: BuildingFragment,
    //   side: THREE.DoubleSide,
    //   lights: true
    // })
    // building.material = buildingMat

    // create a classical material for building
    // let topColor = `hsla(201, 100%, 95%, 1)`
    let hTop = Math.round(195 + Math.random() * 10)
    let sTop = Math.round(100)
    let lTop = Math.round(95)
    let hFloor = Math.round(205 + Math.random() * 10)
    let sFloor = Math.round(40 + Math.random() * 20)
    let lFloor = Math.round(5 + Math.random() * 15)

    let topColor = `hsla(${hTop}, ${sTop}%, ${lTop}%, 1)`
    let bottomColor = `hsla(${hFloor}, ${sFloor}%, ${lFloor}%, 1)`
    let gradientTexture = new THREE.CanvasTexture(this.createGradientCanvas(topColor, bottomColor))
    let materialOpts = {
      color: 0xffffff,
      side: THREE.DoubleSide,
      shininess: 30,
      map: gradientTexture
      // wireframe: true,
      // transparent: true,
      // opacity: 0.6
      // renderOrder: 0
    }
    building.material = new THREE.MeshPhongMaterial(materialOpts)

    // building.castShadow = true
    // building.receiveShadow = true

    // let buildingGeom = fromCSG(boxCSG)
    // buildingGeom.computeVertexNormals()

    // result
    // let subtractCSG = boxMeshCSG.subtract(holeMeshCSG)
    // let building = fromCSG(boxMeshCSG) // converting CSG back into ThreeJS object
    //
    let buildingPos = { ...position }
    buildingPos.z -= 0.5 * size.z

    // let light = new THREE.PointLight(0xfcfcf9, 1)
    // var sun = new THREE.DirectionalLight(0xfcfcf9, 2)
    // sun.position.set(-150, 200, 110)

    let topGeom = new THREE.BoxGeometry(size.x, wallW, size.z)
    let topOpts = {
      color: new THREE.Color(`hsl(${hTop}, ${sTop}%, ${lTop}%)`),
      // side: THREE.DoubleSide,
      shininess: 30
    }
    let topMat = new THREE.MeshPhongMaterial(topOpts)
    let topMesh = new THREE.Mesh(topGeom, topMat)
    let topPosition = { ...position }
    topPosition.y += 0.5 * size.y

    let floorGeom = new THREE.BoxGeometry(size.x, wallW, size.z)
    let floorOpts = {
      color: new THREE.Color(`hsl(${hFloor}, ${sFloor}%, ${lFloor}%)`),
      // side: THREE.DoubleSide,
      shininess: 10
    }
    let floorMat = new THREE.MeshPhongMaterial(floorOpts)
    let floorMesh = new THREE.Mesh(floorGeom, floorMat)
    let floorPosition = { ...position }
    floorPosition.y -= 0.5 * size.y

    return {
      block3d: null,
      // block_opts: materialOpts,
      label3d: null,
      label_opts: {
        side: THREE.DoubleSide,
        // wireframe: false,
        transparent: true
        // opacity: 0.6
        // renderOrder: 0
      },
      // size and positions are defined in store project
      size: size,
      position: position,

      // geometry: geometry,
      // light: light,
      building: building,
      building_position: buildingPos,
      top_mesh: topMesh,
      top_position: topPosition,
      floor_mesh: floorMesh,
      floor_position: floorPosition,
      label_position: { x: 0, y: 0, z: 0 },
      color: 0xffffff,
      label_canvas: null,
      label_size: null,
      isOpened: false
    }
  },
  computed: {
    label_texture_opts () {
      return {
        canvas: this.label_canvas,
        minFilter: THREE.LinearFilter,
        wrapS: THREE.ClampToEdgeWrapping,
        wrapT: THREE.ClampToEdgeWrapping
      }
    }
  },
  created () {
    console.log('Project created: data', this, this.data)

    this.label_canvas = this.createLabelCanvas(this.data.Titre.replace(/ /g, '\n').toUpperCase(), 48, 21, '#000000', '#ffffff')
    this.label_position.x = this.position.x - this.size.x / 2 + this.label_size.x / 2 + 1
    this.label_position.y = this.position.y + this.size.y / 2 - this.label_size.y / 2 - 1
    this.label_position.z = this.position.z + this.size.z / 2 + 0.5
    // console.log('this.label_canvas', this.label_canvas)
  },
  mounted () {
    console.log('project mounted', this)
    // record self references

    this.block3d = this.$refs.block3d.curObj
    // this.block3d.castShadow = true
    // this.block3d.receiveShadow = true

    this.block3d.userData = {
      vnode: this
    }
    this.label3d = this.$refs.label3d.curObj

    // light
    // console.log('project mounted', this.$env3d)
    // var light = new THREE.AmbientLight(0xbf1a1a) // soft white light
    // this.$env3d.scene.add(light)
  }
  // ,
  // methods: {
  //
  // }
}
</script>
