<template>
  <div :id="elId" :class="`coalesce-bg ${snapped?'snapped':''}`">
    <div class="content--canvas"></div>
    <div :class="`cover_overlay ${overlayer} ${overlayerColor}`"
         :style="`--g_x:${w}px;--g_h:${h}px;`"></div>
    <slot class="coalesce_layer"></slot>
  </div>
</template>
<script>
import elementbase from "../mixins/tools/elementbase"
import { ColorTool, hexToRgb } from ".."
import { cos, HALF_PI, rand, sin, TAU } from "../engines/three/wrapengine/mathlib"
import { cancelAnimationFrameHandle, requestAnimationFrameHandle } from "../engines/util/framehandle"

export default {
  name: "BgPipeline",
  mixins: [elementbase],
  props: {
    elementColor: {
      type: String,
      required: false,
      default: "#273e24"
    },
    backgroundColor: {
      type: String,
      required: false,
      default: "#507a4b"
    }
  },
  data() {
    return {
      framehandle: 0
    }
  },
  mounted() {
    /*    const { PI, cos, sin, abs, sqrt, pow, round, random, atan2 } = Math */
    /*    const HALF_PI = 0.5 * PI
        const TAU = 2 * PI
        const TO_RAD = PI / 180 */

    const pipeCount = 30
    const pipePropCount = 8
    const pipePropsLength = pipeCount * pipePropCount
    const turnCount = 8
    const turnAmount = (360 / turnCount) * TO_RAD
    const turnChanceRange = 58
    const baseSpeed = 0.5
    const rangeSpeed = 1
    const baseTTL = 100
    const rangeTTL = 300
    const baseWidth = 2
    const rangeWidth = 4
    let baseHue

    if (this.elementColor) {
      const r = hexToRgb(this.elementColor)
      const customhue = new ColorTool(r.r, r.g, r.b, "spe3")
      baseHue = customhue.data().h
    } else {
      baseHue = 180
    }

    const rangeHue = 50
    const backgroundColor = this.backgroundColor

    let container
    let canvas
    let ctx
    let center
    let tick
    let pipeProps

    this.setup = () => {
      this.createCanvas()
      this.resize()
      this.initPipes()
      this.draw()
    }

    this.initPipes = () => {
      pipeProps = new Float32Array(pipePropsLength)

      let i

      for (i = 0; i < pipePropsLength; i += pipePropCount) {
        this.initPipe(i)
      }
    }

    this.initPipe = (i) => {
      let x, y, direction, speed, life, ttl, width, hue
      // eslint-disable-next-line prefer-const
      x = rand(canvas.a.width)
      // eslint-disable-next-line prefer-const
      y = center[1]
      // eslint-disable-next-line prefer-const
      direction = round(rand(1)) ? HALF_PI : TAU - HALF_PI
      // eslint-disable-next-line prefer-const
      speed = baseSpeed + rand(rangeSpeed)
      // eslint-disable-next-line prefer-const
      life = 0
      // eslint-disable-next-line prefer-const
      ttl = baseTTL + rand(rangeTTL)
      // eslint-disable-next-line prefer-const
      width = baseWidth + rand(rangeWidth)
      // eslint-disable-next-line prefer-const
      hue = baseHue + rand(rangeHue)

      pipeProps.set([x, y, direction, speed, life, ttl, width, hue], i)
    }

    this.updatePipes = () => {
      tick++

      let i

      for (i = 0; i < pipePropsLength; i += pipePropCount) {
        this.updatePipe(i)
      }
    }

    this.updatePipe = (i) => {
      const i2 = 1 + i
      const i3 = 2 + i
      const i4 = 3 + i
      const i5 = 4 + i
      const i6 = 5 + i
      const i7 = 6 + i
      const i8 = 7 + i
      let x, y, direction, speed, life, ttl, width, hue, turnChance, turnBias

      x = pipeProps[i]
      y = pipeProps[i2]
      direction = pipeProps[i3]
      speed = pipeProps[i4]
      life = pipeProps[i5]
      ttl = pipeProps[i6]
      width = pipeProps[i7]
      hue = pipeProps[i8]

      this.drawPipe(x, y, life, ttl, width, hue)

      life++
      x += cos(direction) * speed
      y += sin(direction) * speed
      turnChance =
          !(tick % round(rand(turnChanceRange))) &&
          (!(round(x) % 6) || !(round(y) % 6))
      turnBias = round(rand(1)) ? -1 : 1
      direction += turnChance ? turnAmount * turnBias : 0

      pipeProps[i] = x
      pipeProps[i2] = y
      pipeProps[i3] = direction
      pipeProps[i5] = life

      this.checkBounds(x, y)
      life > ttl && this.initPipe(i)
    }

    this.drawPipe = (x, y, life, ttl, width, hue) => {
      ctx.a.save()
      ctx.a.strokeStyle = `hsla(${hue},75%,50%,${fadeInOut(life, ttl) *
      0.125})`
      ctx.a.beginPath()
      ctx.a.arc(x, y, width, 0, TAU)
      ctx.a.stroke()
      ctx.a.closePath()
      ctx.a.restore()
    }

    this.checkBounds = (x, y) => {
      if (x > canvas.a.width) {
        x = 0
      }
      if (x < 0) {
        x = canvas.a.width
      }
      if (y > canvas.a.height) {
        y = 0
      }
      if (y < 0) {
        y = canvas.a.height
      }
    }

    this.createCanvas = () => {
      container = document.querySelector(".content--canvas")
      canvas = {
        a: document.createElement("canvas"),
        b: document.createElement("canvas")
      }
      canvas.b.style = `
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
	`
      container.appendChild(canvas.b)
      ctx = {
        a: canvas.a.getContext("2d"),
        b: canvas.b.getContext("2d")
      }
      center = []
      tick = 0
    }

    this.resize = () => {
      const { innerWidth, innerHeight } = window

      canvas.a.width = innerWidth
      canvas.a.height = innerHeight

      ctx.a.drawImage(canvas.b, 0, 0)

      canvas.b.width = innerWidth
      canvas.b.height = innerHeight

      ctx.b.drawImage(canvas.a, 0, 0)

      center[0] = 0.5 * canvas.a.width
      center[1] = 0.5 * canvas.a.height
    }

    this.render = () => {
      ctx.b.save()
      ctx.b.fillStyle = backgroundColor
      ctx.b.fillRect(0, 0, canvas.b.width, canvas.b.height)
      ctx.b.restore()

      ctx.b.save()
      ctx.b.filter = "blur(12px)"
      ctx.b.drawImage(canvas.a, 0, 0)
      ctx.b.restore()

      ctx.b.save()
      ctx.b.drawImage(canvas.a, 0, 0)
      ctx.b.restore()
    }

    this.draw = () => {
      this.updatePipes()

      this.render()
      if (!this.cancel) {
        this.framehandle = requestAnimationFrameHandle(this.draw)
      }
    }

    setTimeout(() => {
      this.setup()

      window.addEventListener("resize", this.resize)
    }, 100)
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.resize)
    cancelAnimationFrameHandle(this.framehandle)
    this.cancel = true
  }
}
</script>
<style scoped>
</style>
