//written by chgnhyk

//--------------------------------------------------------------------------
//IMPORTING

//import threejs libraries
import * as THREE from './libs/three.module.js';
import Stats from './libs/stats.module.js';
import { GLTFLoader } from './libs/GLTFLoader.js';

//import shader
import { italic_vert_sh, italic_frag_sh } from './shader/italic_sh.js';


window.history.pushState({}, document.title, window.location.pathname);
console.log(urlParams);

if (urlParams.startCanvas != "0" || !urlParams.startCanvas) {
  //--------------------------------------------------------------------------
  //VARIABLES
  var renderer, renderer_2;
  var width, height, width_2;
  var width_2_scale = 1.3;
  var logo_height = 0.3;
  var logo_camera, logo_scene, logo_model;
  var doone_camera, doone_scene, doone_model;
  var logo_buffer, back_buffer;
  var l_scale = 3.2;
  var quad, quad_camera, quad_scene;
  var logo_copy = [];
  var gltf_loader;
  var loading_manager;
  var pixel_density = 2.0;
  var box;
  var logo_length = 3;
  if(1.0 < window.innerWidth / window.innerHeight) logo_length *= Math.round(1.5 * window.innerWidth / window.innerHeight);
  console.log(logo_length, window.innerWidth / window.innerHeight);
  var logo_interval = 0;
  var logo_width = 0;
  var logo_init_scale = 0;
  var stats;
  var env_map, cubeRenderTarget;
  var italic_shader_material;
  var italic_intensity = 0.0;
  var italic_tar_intensity = 0.0;

  var is_doone_rotating = true;

  var dom_loading = document.getElementById("loading");
  var dom_stats = document.getElementById("stats");
  var dom_smp_img = document.getElementById("smp_img");

  
  //VARIABLES
  //--------------------------------------------------------------------------


  //--------------------------------------------------------------------------
  //for USER events
  function onScroll(e) {
    //console.log(e.deltaY);
    italic_tar_intensity = e.deltaY * 0.002;
  }

  function permission () {
    if ( typeof( DeviceMotionEvent ) !== "undefined" && typeof( DeviceMotionEvent.requestPermission ) === "function" ) {
      // (optional) Do something before API request prompt.
      DeviceMotionEvent.requestPermission()
        .then( response => {
        // (optional) Do something after API prompt dismissed.
        if ( response == "granted" ) {
          window.addEventListener( "deviceorientation", onOrientationChange);
        }
      })
      .catch( console.error )
    } else {
      alert( "DeviceMotionEvent is not defined" );
    }
  }

  function onMouseMove() {
    italic_tar_intensity += 0.015;
  }

  function rotateDoone() {
    is_doone_rotating = false;
  }

  function rotateDooneStop() {
    is_doone_rotating = true;
  }

  //--> on window resize
  function onWindowResize() {
    width = window.innerWidth;
    height = window.innerHeight * logo_height;
    width_2 = height * width_2_scale;

    renderer.setSize(width, height, pixel_density);
    renderer_2.setSize(width_2, height, pixel_density);
    logo_buffer.setSize(width * pixel_density, height * pixel_density);
    logo_camera.aspect = width / height;
    logo_camera.updateProjectionMatrix();
    doone_camera.aspect = width_2 / height;
    doone_camera.updateProjectionMatrix();

    let logo_scale = l_scale * height / 400;

    for (let i = 0; i < logo_length; i++) {
      logo_copy[i].scale.set(logo_scale, logo_scale, logo_scale);
      box.setFromObject(logo_copy[i]);
      logo_interval = (box.max.x - box.min.x) * (1.1);
      console.log(logo_interval);
      logo_copy[i].position.x = (i - logo_length / 2) * logo_interval;
    }

    if(window.innerWidth < 813){
      doone_model.scale.set(logo_scale * 0.6, logo_scale * 0.6, logo_scale * 0.6);
    }else{
      doone_model.scale.set(logo_scale * 0.8, logo_scale * 0.8, logo_scale * 0.8);
    }
  }

  //--> on orientatin change
  function onOrientationChange(e){
    //console.log(e);
    var mobile_rotation = event.beta;
    var angle = Math.abs(mobile_rotation - 180);

    let all_stats = stats.update();
    let fps = all_stats.fps.toPrecision(4);
    if(fps < 1) fps = 60;
    if(!isIOS()){
      italic_tar_intensity += ((0.8 * (30 / fps)) * angle / 360 - italic_tar_intensity) * 0.5;
    }else{
      italic_tar_intensity += ((0.4 * (30 / fps)) * angle / 360 - italic_tar_intensity) * 0.5;
    }
  }

  //--------------------------------------------------------------------------
  //basic THREE functions

  //--> function to initiating whole THREE scene
  function init() {

    width = window.innerWidth;
    height = window.innerHeight * logo_height;
    width_2 = height * width_2_scale;

    console.log(dom_smp_img);
    const env_img = new THREE.Texture(dom_smp_img);

    env_img.needsUpdate = true;
    console.log(env_img);

    cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, {
      format: THREE.RGBFormat,
      generateMipmaps: true,
      minFilter: THREE.LinearMipmapLinearFilter
    });

    loading_manager = new THREE.LoadingManager();
    gltf_loader = new GLTFLoader(loading_manager);

    //--> Stats object for calculating fps
    stats = new Stats();
    dom_stats = document.getElementById('stats');

    //--> container for threejs canvas
    const container = document.getElementById('three_container');
    const container_2 = document.getElementById('three_container_2');

    //--> webgl renderer, webgl render targets
    renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(width, height, pixel_density);

    renderer.setClearColor(0xffffff, 0);
    //renderer.setClearColor(0x000000, 1);
    //renderer.autoClear = false;

    renderer_2 = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer_2.setSize(width_2, height, pixel_density);

    renderer_2.setClearColor(0xffffff, 0);
    //renderer_2.setClearColor(0x000000, 1);

    //--> add webgl rendering context to canvas dom
    container.appendChild(renderer.domElement);
    container_2.appendChild(renderer_2.domElement);

    const pmremGenerator = new THREE.PMREMGenerator(renderer);
    const pmremGenerator_2 = new THREE.PMREMGenerator(renderer_2);

    logo_buffer = new THREE.WebGLRenderTarget(width * pixel_density, height * pixel_density);
    //back_buffer = new THREE.WebGLRenderTarget(window.innerWidth * pixel_density, window.innerHeight * pixel_density);
    //--> scene, camera settings
    //--> camera distances have huge affect on performace, so don't use any arbitrary large number
    logo_camera = new THREE.PerspectiveCamera(35, width / height, 0.1, 30);
    logo_scene = new THREE.Scene();
    //logo_scene.background = new THREE.Color(0xffffff);

    doone_camera = new THREE.PerspectiveCamera(25, width_2 / height, 0.1, 30);
    doone_scene = new THREE.Scene();

    logo_camera.position.z = 6.0;
    logo_camera.position.y = 0.0;
    logo_camera.lookAt(0, 0, 0);

    doone_camera.position.z = 6.0;
    doone_camera.position.y = 0.0;
    doone_camera.lookAt(0.2, 0, 0);

    quad_camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
    quad_scene = new THREE.Scene();

    box = new THREE.Box3();

    //--> shader material for blur effect
    italic_shader_material = new THREE.ShaderMaterial({
      vertexShader: italic_vert_sh,
      fragmentShader: italic_frag_sh,
      uniforms: {
        buffer: { value: null },
        res: {
          value: [
            window.innerWidth * pixel_density,
            window.innerHeight * pixel_density
          ]
        },
        italic_intensity: { value: italic_intensity },
        logo_topbttom: {
          value: [
            0, 0
          ]
        }
      }
    });

    //--> for quad use for post-processing or copying rendered scenes, video etc.
    const quad_geometry = new THREE.PlaneBufferGeometry(2, 2, 1, 1);
    quad = new THREE.Mesh(quad_geometry, italic_shader_material);
    quad_scene.add(quad);

    gltf_loader.load('./assets/models/peaches_fvr2_it1_8perc_bool_opt.glb', function(gltf) {
      console.log(gltf);

      gltf.scene.traverse(function(child) {
        if (child.isMesh) {
          //child.material.emissive.set(0x303030);
          child.material.color.set(0xf0f0f0);
          child.material.clearcoat = 1.0;
          child.material.roughness = 0.0;
          let env_cube = cubeRenderTarget.fromEquirectangularTexture(renderer, env_img).texture;
          env_map = pmremGenerator.fromCubemap(env_cube).texture
          child.material.envMap = env_map;
          let logo_scale = l_scale * height / 400;
          logo_init_scale = logo_scale;
          child.scale.set(logo_scale, logo_scale, logo_scale);
          for (let i = 0; i < logo_length; i++) {
            logo_copy[i] = child.clone();
            box.setFromObject(logo_copy[i]);
            logo_interval = (box.max.x - box.min.x) * (1.1);
            console.log(logo_interval);
            logo_copy[i].position.x = (i - logo_length / 2) * logo_interval;

            logo_scene.add(logo_copy[i]);
          }
        }
      });
    });

    gltf_loader.load('./assets/models/doone_ring_14K.glb', function(gltf) {
      console.log(gltf);

      gltf.scene.traverse(function(child) {
        if (child.isMesh) {
            //child.material.emissive.set(0x303030);
            child.geometry.translate(0.5, 0.0, 0.0);
            child.material.color.set(0xf0f0f0);
            child.material.clearcoat = 1.0;
            child.material.roughness = 0.0;
            let env_cube = cubeRenderTarget.fromEquirectangularTexture(renderer_2, env_img).texture;
            env_map = pmremGenerator_2.fromCubemap(env_cube).texture
            child.material.envMap = env_map;
            let logo_scale = l_scale * 0.8 * height / 400;
            if(window.innerWidth < 813){
              logo_scale = l_scale * 0.6 * height / 400;
            }
            child.scale.set(logo_scale, logo_scale, logo_scale);
            //child.position.y = -0.9;
            doone_model = child;
            doone_scene.add(child);
        }
      });
    });

    if(!isPointerAvailable()){
      window.addEventListener('deviceorientation', onOrientationChange);
      if(isIOS()) document.body.addEventListener('click', permission);
    }

    //window.addEventListener('wheel', onScroll);
    window.addEventListener('mousemove', onMouseMove);
    window.addEventListener('resize', onWindowResize);
    renderer_2.domElement.addEventListener('mouseenter', rotateDoone);
    renderer_2.domElement.addEventListener('mouseleave', rotateDooneStop);
    
    var loader_progress = 0;
    var loader_counter = 0;
    var loader_count = 0;
    var i = setInterval(function(){
      console.log(loader_progress);
      loader_count = Math.min(loader_count, 100);
      
      $(".loader .loader-counter h1").html(loader_count + "%");
      $(".loader").css("width", loader_count + "%");

      if(Math.floor(loader_progress * 100.0) >= loader_counter){
        loader_counter++;
        loader_count++;
      }

      if(loader_counter >= 100){
        clearInterval(i);
        $('.loader').fadeOut(); }
    }, 50);

    loading_manager.onProgress = function(url, itemsLoaded, itemsTotal){
      loader_progress = itemsLoaded / itemsTotal;

      console.log( 'Loading file: ' + url + '.\nLoaded ' + itemsLoaded + ' of ' + itemsTotal + ' files.' );
    };

    loading_manager.onLoad = function() {
        console.log("fully loaded.");
        $(dom_loading).delay(100).fadeOut(300);
        animate();
    };
  }

  //--> requestAnimationFrame is here
  function animate() {
    requestAnimationFrame(animate);

    update();
    render();
  }

  //--> update
  function update() {
    italic_intensity += (italic_tar_intensity - italic_intensity) * 0.2;

    italic_tar_intensity += (0 - italic_tar_intensity) * 0.1;

    let logo_scale = l_scale * height / 400;

    for (let i = 0; i < logo_copy.length; i++) {
      logo_copy[i].scale.set(logo_scale, logo_scale, logo_scale);
      logo_copy[i].position.x -= (0.005 + italic_intensity * 1.5);
      box.setFromObject(logo_copy[i]);
      let logo_pos = toScreenSpace(box.max, logo_camera);

      if (logo_pos.x < getWorldPos(new THREE.Vector3(0, 0, 0), logo_camera).x) {
        logo_copy[i].position.x += logo_interval * logo_copy.length;
        //console.log("up!");
      }

    }

    if (is_doone_rotating) {
      doone_model.rotation.z -= 0.01;
    } else {
      doone_model.rotation.z += (0 - doone_model.rotation.z) * 0.1;
    }
  }

  //--> mostly rendering --> but most ring animations are here (re-organize later)
  function render() {
    renderer.setRenderTarget(logo_buffer); // --> use as current camera frame
    renderer.render(logo_scene, logo_camera);

    quad.material = italic_shader_material;

    italic_shader_material.uniforms.buffer.value = logo_buffer.texture;
    italic_shader_material.uniforms.italic_intensity.value = italic_intensity;
    italic_shader_material.uniforms.res.value = [
      width * pixel_density,
      height * pixel_density
    ];
    italic_shader_material.uniforms.logo_topbttom.value = [
      box.max.y,
      box.min.y
    ];
    //renderer.setRenderTarget(back_buffer);
    //renderer.render(quad_scene, quad_camera);

    renderer.setRenderTarget(null);
    renderer.render(quad_scene, quad_camera);

    renderer_2.setRenderTarget(null);
    renderer_2.render(doone_scene, doone_camera);
  }

  //--------------------------------------------------------------------------
  //for SPECIAL EFFECT


  //--------------------------------------------------------------------------
  //util for THREE scene

  //--> function to converting 3d space coordinates to screen
  function toScreenSpace(_pos, _cam) {
    let screen_pos = _pos.clone();
    let projScreenMat = new THREE.Matrix4();
    projScreenMat.multiplyMatrices(_cam.projectionMatrix, _cam.matrixWorldInverse);
    screen_pos.applyMatrix4(projScreenMat);

    return new THREE.Vector2(
      (screen_pos.x + 1.0) * 0.5,
      (screen_pos.y * -1.0 + 1.0) * 0.5
    );
  }

  function getWorldPos(_pos, _cam) {
    let dir = new THREE.Vector3();
    let pos = new THREE.Vector3();
    dir.set(_pos.x, _pos.y, _pos.z);
    dir.unproject(_cam);
    dir.sub(_cam.position).normalize();

    const _dst = -_cam.position.z / dir.z;
    pos.copy(_cam.position).add(dir.multiplyScalar(_dst));
    return pos;
  }

  //--------------------------------------------------------------------------
  //initial execution of functions
  var env_img = new Image();
  //dom_smp_img.src = './assets/imgs/env_1.png';
  env_img.onload = function() {
    console.log('env map ready');
    init();
  }
  env_img.src = './assets/imgs/env_1.png';
}
