/**
 * Copyright (c) 2018 Bitbloq (BQ)
 *
 * @license MIT
 *
 * long description for the file
 *
 * @summary short description for the file
 * @author David García <https://github.com/empoalp>
 * @author Alberto Valero <https://github.com/avalero>
 *
 * Created at     : 2018-09-14 10:49:04
 * Last modified  : 2018-10-08 21:37:26
 */
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    }
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
import React from 'react';
import { connect } from 'react-redux';
import * as Three from 'three';
import { selectObject, deselectAllObjects, undo, redo } from '../../actions/threed';
import { getObjects, getSelectedObjects } from '../../reducers/threed/';
import OrbitCamera from '../../lib/object3dts/OrbitCamera.ts';
import styled, { css } from 'react-emotion';
import ThreeDNavigationBox from './ThreeDNavigationBox';
import UndoIcon from '../../assets/images/undo.svg';
import Cube from '../../lib/object3dts/Cube.ts';
import Cylinder from '../../lib/object3dts/Cylinder.ts';
var Wrap = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n  position: relative;\n  flex: 1;\n  display: flex;\n  overflow: hidden;\n"], ["\n  position: relative;\n  flex: 1;\n  display: flex;\n  overflow: hidden;\n"])));
var Container = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n  flex: 1;\n  display: flex;\n  overflow: hidden;\n"], ["\n  flex: 1;\n  display: flex;\n  overflow: hidden;\n"])));
var TopRightButtons = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n  position: absolute;\n  right: 18px;\n  top: 18px;\n  display: flex;\n  background-color: white;\n  border-radius: 6px;\n"], ["\n  position: absolute;\n  right: 18px;\n  top: 18px;\n  display: flex;\n  background-color: white;\n  border-radius: 6px;\n"])));
var UndoButton = styled.div(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n  border: 1px solid #979797;\n  background-color: #eee;\n  height: 32px;\n  width: 40px;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: 6px 0px 0px 6px;\n\n  ", "\n\n  img {\n    transform: scaleX(-1);\n  }\n"], ["\n  border: 1px solid #979797;\n  background-color: #eee;\n  height: 32px;\n  width: 40px;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: 6px 0px 0px 6px;\n\n  ",
    "\n\n  img {\n    transform: scaleX(-1);\n  }\n"])), function (props) { return props.disabled && css(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n    opacity: 0.3;\n  "], ["\n    opacity: 0.3;\n  "]))); });
var RedoButton = styled(UndoButton)(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n  border-radius: 0px 6px 6px 0px;\n  margin-left: -1px;\n  img {\n    transform: none;\n  }\n"], ["\n  border-radius: 0px 6px 6px 0px;\n  margin-left: -1px;\n  img {\n    transform: none;\n  }\n"])));
var outlineMaterial = new Three.MeshBasicMaterial({
    color: 0x6a8d2f,
    side: Three.BackSide,
});
var ThreeDViewer = /** @class */ (function (_super) {
    __extends(ThreeDViewer, _super);
    function ThreeDViewer() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.container = React.createRef();
        _this.navigationBox = React.createRef();
        _this.containerRect = { left: 0, top: 0, width: 0, height: 0 };
        _this.renderer = new Three.WebGLRenderer({ antialias: true });
        _this.scene = new Three.Scene();
        _this.outlineGroup = new Three.Group();
        _this.helpersGroup = new Three.Group();
        _this.objectsGroup = new Three.Group();
        _this.instances = {};
        _this.meshes = {};
        _this.activeHelper = null;
        _this.raycaster = new Three.Raycaster();
        _this.mousePosition = new Three.Vector2();
        _this.state = {
            mouseDownObject: null,
            selectOnMouseUp: false,
        };
        _this.onMouseDown = function (e) {
            var object = _this.getObjectFromPosition(e.clientX, e.clientY);
            _this.setState({ mouseDownObject: object, selectOnMouseUp: true });
        };
        _this.onMouseMove = function (e) {
            var selectOnMouseUp = _this.state.selectOnMouseUp;
            if (selectOnMouseUp) {
                _this.setState({ selectOnMouseUp: false });
            }
        };
        _this.onMouseUp = function (e) {
            var _a = _this.state, mouseDownObject = _a.mouseDownObject, selectOnMouseUp = _a.selectOnMouseUp;
            var _b = _this.props, selectObject = _b.selectObject, deselectAllObjects = _b.deselectAllObjects, controlPressed = _b.controlPressed, shiftPressed = _b.shiftPressed;
            if (selectOnMouseUp) {
                if (mouseDownObject) {
                    selectObject(mouseDownObject, controlPressed || shiftPressed);
                }
                else {
                    deselectAllObjects();
                }
            }
        };
        _this.onClick = function (e) {
            var _a = _this.props, selectObject = _a.selectObject, deselectAllObjects = _a.deselectAllObjects, controlPressed = _a.controlPressed, shiftPressed = _a.shiftPressed;
            var object = _this.getObjectFromPosition(e.clientX, e.clientY);
            if (object) {
                selectObject(object, controlPressed || shiftPressed);
            }
            else {
                deselectAllObjects();
            }
        };
        _this.getObjectFromPosition = function (x, y) {
            var _a = _this.containerRect, left = _a.left, top = _a.top, width = _a.width, height = _a.height;
            _this.mousePosition.x = ((x - left) / width) * 2 - 1;
            _this.mousePosition.y = -((y - top) / height) * 2 + 1;
            _this.raycaster.setFromCamera(_this.mousePosition, _this.camera);
            var intersects = _this.raycaster.intersectObjects(_this.objectsGroup.children, true);
            if (intersects.length > 0) {
                var mesh = intersects[0].object;
                if (mesh.objectID) {
                    return _this.instances[mesh.objectID];
                }
            }
        };
        _this.updateCameraAngle = function (theta, phi) {
            _this.cameraControls.rotateTo(theta, phi, true);
        };
        _this.renderLoop = function () {
            _this.updateSize();
            var delta = _this.clock.getDelta();
            var cameraNeedsUpdate = _this.cameraControls.update(delta);
            if (cameraNeedsUpdate) {
                _this.updateNavigationBox();
            }
            requestAnimationFrame(_this.renderLoop);
            _this.renderer.render(_this.scene, _this.camera);
        };
        return _this;
    }
    ThreeDViewer.prototype.componentDidUpdate = function (prevProps) {
        this.updateSceneObjects(prevProps.objects);
    };
    ThreeDViewer.prototype.componentDidMount = function () {
        this.container.current.appendChild(this.renderer.domElement);
        this.setupScene();
        this.updateSize();
        this.updateSceneObjects();
        this.renderLoop();
    };
    ThreeDViewer.prototype.updateSceneObjects = function (prevObjects) {
        //TODO
        if (prevObjects === void 0) { prevObjects = []; }
        var cube1 = new Cube({ width: 10, height: 10, depth: 10, name: 'myCube' }, [{ type: 'translation', x: 15, y: 0, z: 0, relative: false }]).getMesh();
        var cyl1 = new Cylinder({ r0: 3, r1: 0, height: 10, name: 'myCyl' }, [{ type: 'translation', x: -15, y: 0, z: 0, relative: false }]).getMesh();
        this.scene.add(cube1);
        this.scene.add(cyl1);
    };
    ThreeDViewer.prototype.updateSize = function () {
        var containerRect = this.container.current.getBoundingClientRect();
        var width = containerRect.width, height = containerRect.height;
        this.containerRect = containerRect;
        this.renderer.setSize(width, height);
        this.camera.aspect = width / height;
        this.camera.updateProjectionMatrix();
    };
    ThreeDViewer.prototype.setupScene = function () {
        this.renderer.setClearColor(0xfafafa);
        this.clock = new Three.Clock();
        this.scene.add(new Three.AmbientLight(0x555555));
        var spotLight = new Three.SpotLight(0xeeeeee);
        spotLight.position.set(80, -100, 60);
        this.scene.add(spotLight);
        var plane = new Three.Plane(new Three.Vector3(0, 0, 1));
        var helper = new Three.PlaneHelper(plane, 200, 0x98f5ff);
        this.scene.add(helper);
        var grid = new Three.GridHelper(200, 20);
        grid.geometry.rotateX(Math.PI / 2);
        this.scene.add(grid);
        this.camera = new Three.PerspectiveCamera(50, 1, 0.1, 1000);
        this.camera.position.set(0, -150, 80);
        this.camera.up.set(0, 0, 1);
        this.camera.lookAt(this.scene.position);
        this.cameraControls = new OrbitCamera(this.camera, this.renderer.domElement);
        this.updateNavigationBox();
        this.scene.add(this.outlineGroup);
        this.scene.add(this.objectsGroup);
        this.scene.add(this.helpersGroup);
        this.renderer.render(this.scene, this.camera);
    };
    ThreeDViewer.prototype.updateNavigationBox = function () {
        var direction = new Three.Vector3();
        this.camera.getWorldDirection(direction);
        var x = direction.x, y = direction.y, z = direction.z;
        this.navigationBox.current.updateCamera(-x, -y, -z);
    };
    ThreeDViewer.prototype.render = function () {
        var _a = this.props, undo = _a.undo, redo = _a.redo, canUndo = _a.canUndo, canRedo = _a.canRedo;
        return (React.createElement(Wrap, null,
            React.createElement(Container, { innerRef: this.container, onMouseDown: this.onMouseDown, onMouseMove: this.onMouseMove, onMouseUp: this.onMouseUp }),
            React.createElement(ThreeDNavigationBox, { ref: this.navigationBox, onChangeCameraAngle: this.updateCameraAngle }),
            React.createElement(TopRightButtons, null,
                React.createElement(UndoButton, { onClick: undo, disabled: !canUndo },
                    React.createElement("img", { src: UndoIcon })),
                React.createElement(RedoButton, { onClick: redo, disabled: !canRedo },
                    React.createElement("img", { src: UndoIcon })))));
    };
    return ThreeDViewer;
}(React.Component));
var mapStateToProps = function (_a) {
    var ui = _a.ui, threed = _a.threed;
    return ({
        objects: getObjects(threed),
        selectedObjects: getSelectedObjects(threed),
        activeOperation: threed.ui.activeOperation,
        controlPressed: ui.controlPressed,
        shiftPressed: ui.shiftPressed,
        canUndo: threed.scene.past.length > 0,
        canRedo: threed.scene.future.length > 0,
    });
};
var mapDispatchToProps = {
    selectObject: selectObject,
    deselectAllObjects: deselectAllObjects,
    undo: undo,
    redo: redo,
};
export default connect(mapStateToProps, mapDispatchToProps)(ThreeDViewer);
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6;
//# sourceMappingURL=DummyThreeDViewer.js.map