import * as THREE from 'three';
import { STLLoader } from 'STLLoader';
import { OrbitControls } from 'OrbitControls';

export class ThreeRendererElement extends HTMLElement {
  constructor() {
    super();

    var scene = this.scene = new THREE.Scene();
    var camera = this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

    var light = this.light = new THREE.AmbientLight(0xffffff, 1);
    this.scene.add(light);
    var point_light = this.point_light = new THREE.DirectionalLight(0xffffff, 0.5);
    this.point_light.position.set(0, 0, 10);
    this.point_light.target.position.set(-5, 0, 0);
    this.scene.add(point_light);
    this.scene.add(point_light.target);

    var renderer = this.renderer = new THREE.WebGLRenderer();
    var bb = this.parentElement.getBoundingClientRect();
    this.renderer.setSize(bb.width, bb.height);
    this.controls = new OrbitControls(camera, renderer.domElement);

    this.geometry = new THREE.BoxGeometry();
    this.material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );

    this.scene.background = new THREE.Color(0xababab);

    this.camera.position.z = 5;
    var group = this.group = new THREE.Group();
    //group.rotation.x = group.rotation.y = Math.PI / 2;
    this.scene.add(group);

    // ground plane
    const planeSize = 40;
    const loader = new THREE.TextureLoader();
    const texture = loader.load('static/three.js-master/examples/textures/checker.png');
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.magFilter = THREE.NearestFilter;
    const repeats = planeSize / 2;
    texture.repeat.set(repeats, repeats);

    const planeGeo = new THREE.PlaneGeometry(planeSize, planeSize);
    const planeMat = new THREE.MeshPhongMaterial({
      map: texture,
      side: THREE.DoubleSide,
    });
    const plane_mesh = new THREE.Mesh(planeGeo, planeMat);
    window.plane_mesh = plane_mesh;
    //plane_mesh.rotation.x = Math.PI * -.5;
    plane_mesh.position.z = -10;
    this.scene.add(plane_mesh);

    if(this.hasAttribute('src')) {
      this.loadObject(this.getAttribute('src'));
    }


    // XXX applWHY?
    this.do_animate = this.do_animate.bind(this);
    this.do_animate();
  }

  loadObject(src) {
    const loader = new STLLoader();
    const group = this.group;

    loader.load(src, function (geometry) {
        group.clear();

        const material = new THREE.MeshStandardMaterial({
          color: 0xababab,
          metalness: 0.5,
          specular: 0x111111,
          shininess: 300
        });

        const mesh = new THREE.Mesh(geometry, material);

        mesh.castShadow = true;
        mesh.receiveShadow = true;

        const edges = new THREE.EdgesGeometry(geometry);
        const lines = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({
          color: 0xff0000
        }));

        geometry.center();
        edges.center();
        group.add(mesh);
        group.add(lines);
    });
  }

  set src(url) {
    return this.setAttribute('src', url);
  }

  get src() {
    return this.getAttribute('src');
  }

  static get observedAttributes() {
    return [ 'src' ];
  }

  do_animate() {
    // TODO handle pausing
    requestAnimationFrame(this.do_animate);

    this.renderer.render(this.scene, this.camera);
  }

  attributeChangedCallback(name, old_value, value) {
    if(name == 'src') {
      this.loadObject(value);
    }
  }

  connectedCallback() {
    this.appendChild(this.renderer.domElement);
  }
}

customElements.define('three-renderer', ThreeRendererElement);
