import { __awaiter, __extends, __generator } from "tslib";
import { throttle } from 'lodash';
import { MOUSE } from 'three';
import { EventEmitter } from 'events';
import { Cartesian3, Cartesian2, Color } from '@msign/angularis';
var FreeMode = /** @class */ (function (_super) {
    __extends(FreeMode, _super);
    function FreeMode(conPointer, viewer) {
        var _this = _super.call(this) || this;
        _this._isPanning = false;
        _this._isRotating = false;
        _this._isActive = false;
        _this._target = Cartesian3.ZERO.clone();
        _this._targetLock = Cartesian3.ZERO.clone();
        _this._targetEntity = {
            id: 'target_entity_marker',
            position: undefined,
            billboard: {
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
                color: Color.WHITE,
                height: 32,
                width: 32
            }
        };
        _this._direction = Cartesian3.ZERO.clone();
        _this._onKeyDown = function (evt) { };
        _this._onKeyUp = function (evt) { };
        _this._minCameraDistance = 0.5;
        _this._onDown = function (evt) {
            // console.log('down', evt);
            var button = evt.button, x = evt.layerX, y = evt.layerY;
            _this._lastDownPoint = { x: x, y: y };
            switch (button) {
                case MOUSE.LEFT:
                    _this._isPanning = true;
                    _this._targetMarkerVisible('pan');
                    break;
                case MOUSE.MIDDLE:
                    _this._isRotating = true;
                    _this._targetMarkerVisible('rotate');
                    break;
                case MOUSE.RIGHT:
                    _this._targetMarkerVisible('setting');
                    break;
            }
            _this._targetLock = _this._target.clone();
        };
        _this._onUp = function (evt) {
            var x = evt.layerX, y = evt.layerY;
            _this._isPanning = false;
            _this._isRotating = false;
            var _lastDownPoint = _this._lastDownPoint;
            if (Math.abs(_lastDownPoint.x - x) < 3 &&
                Math.abs(_lastDownPoint.y - y) < 3) {
                var feat = _this._targetFeature;
                // console.log(feat);
                if (evt.button === 0) {
                    feat ? _this.emit('pick', feat) : _this.emit('picknone');
                }
            }
            _this._targetMarkerVisible(false);
        };
        _this._onClick = function (evt) { };
        _this._onDblClick = function (evt) { };
        _this._onRightClick = function (evt) {
            evt.stopPropagation();
            evt.returnValue = false;
            evt.cancelBubble = true;
            var feat = _this._targetFeature;
            _this.emit('rightClick', {
                feature: feat || null,
                detail: evt
            });
        };
        _this._onMovePan = function (evt) {
            // console.log('move', evt);
            var _a = _this, viewer = _a.viewer, target = _a._target;
            var movementX = evt.movementX, movementY = evt.movementY;
            if (!movementX && !movementY)
                return;
            // debugger;
            // console.log({ movementX, movementY });
            // 平移相机
            var camera = viewer.camera;
            var position = camera.position, direction = camera.direction, up = camera.up;
            var speed = 0.5;
            var step = Cartesian3.ZERO.clone();
            var cross = Cartesian3.cross(direction, up, Cartesian3.ZERO.clone());
            var upClone = up.clone();
            var dist = Cartesian3.distance(target, position);
            movementX && Cartesian3.multiplyByScalar(cross, movementX, cross);
            movementY && Cartesian3.multiplyByScalar(upClone, movementY, upClone);
            movementX && Cartesian3.subtract(step, cross, step);
            movementY && Cartesian3.add(step, upClone, step);
            try {
                camera.move(step, (speed * dist) / 1000);
                // console.log(step);
            }
            catch (e) {
                debugger;
            }
        };
        _this._onMoveRotate = function (evt) { return __awaiter(_this, void 0, void 0, function () {
            var _a, viewer, target, movementX, movementY, camera, position, direction, up, speed, step, cross, upClone, dist, dd, dist2;
            return __generator(this, function (_b) {
                _a = this, viewer = _a.viewer, target = _a._targetLock;
                if (!target)
                    return [2 /*return*/];
                movementX = evt.movementX, movementY = evt.movementY;
                if (!movementX && !movementY)
                    return [2 /*return*/];
                camera = viewer.camera;
                position = camera.position, direction = camera.direction, up = camera.up;
                speed = 1;
                step = Cartesian3.ZERO.clone();
                cross = Cartesian3.cross(direction, up, Cartesian3.ZERO.clone());
                upClone = up.clone();
                dist = Cartesian3.distance(target, position);
                movementX && Cartesian3.multiplyByScalar(cross, movementX, cross);
                movementY && Cartesian3.multiplyByScalar(upClone, movementY, upClone);
                movementX && Cartesian3.subtract(step, cross, step);
                movementY && Cartesian3.add(step, upClone, step);
                camera.move(step, (speed * dist) / 500);
                // Cartesian3.subtract(target, camera.position, camera.direction);
                /** ****************************************************************
                 *  一开始的版本是以鼠标集中点作为视线目标,
                 *  这样有个问题, 旋转开始的那一刻会相机视线突变
                 *  我们需要实现一个渐变的方案. 有两种选择:
                 *  1. 动画函数固定一个渐变变化时间, 只要开始触发, 即使无操作也动画过度
                 *  2. 以用户鼠标move回调作为触发, 每移动一点, 就按一个比例缩小, 最终收敛
                 *
                 *  测试方案1 体验不佳
                 * _direction
                 *******************************************************************/
                Cartesian3.subtract(target, camera.position, this._direction);
                // this._direction 和 camera.direction 不一定一致, 计算两者的夹角. 保留
                Cartesian3.normalize(this._direction, this._direction);
                if (Cartesian3.distance(this._direction, camera.direction) > 0.1) {
                    dd = Cartesian3.subtract(this._direction, camera.direction, Cartesian3.ZERO.clone());
                    Cartesian3.multiplyByScalar(dd, 0.1, dd);
                    Cartesian3.add(camera.direction, dd, camera.direction);
                    Cartesian3.normalize(camera.direction, camera.direction);
                }
                else {
                    Cartesian3.normalize(this._direction, camera.direction);
                }
                dist2 = Cartesian3.distance(target, camera.position);
                camera.move(camera.direction, dist2 - dist);
                Cartesian3.normalize(target, camera.up);
                return [2 /*return*/];
            });
        }); };
        _this._onMove = throttle(function (evt) {
            if (_this._isPanning) {
                var target = _this._target;
                if (Cartesian3.equals(target, Cartesian3.ZERO))
                    return;
                _this._onMovePan(evt);
            }
            else if (_this._isRotating) {
                // 旋转
                var target = _this._target;
                if (Cartesian3.equals(target, Cartesian3.ZERO))
                    return;
                _this._onMoveRotate(evt);
            }
            else {
                var _a = _this, scene = _a.viewer.scene, target = _a._target;
                var _b = evt, x = _b.layerX, y = _b.layerY;
                // console.log(evt);
                var cart2 = new Cartesian2(x, y);
                scene.pickPosition(cart2, target);
                var feature = void 0;
                try {
                    feature = scene.pick(cart2);
                }
                catch (e) {
                    return;
                }
                // console.log('cart2', cart2);
                window['move_feat'] = feature;
                if (_this._targetFeature && feature !== _this._targetFeature) {
                    // 之前有选中对象 且 和当前不一样
                    _this._targetFeature.setProperty &&
                        _this._targetFeature.setProperty('isHovered', false);
                    _this.emit('unhover', _this._targetFeature);
                }
                if (feature && feature !== _this._targetFeature) {
                    // 选中新对象
                    // console.log('选中新对象', feature);
                    feature.setProperty && feature.setProperty('isHovered', true);
                    _this.emit('hover', feature);
                    _this._targetFeature = feature;
                }
                else if (!feature && _this._targetFeature) {
                    // 没有选中对象
                    // console.log('对象选中丢失', feature);
                    _this._targetFeature = undefined;
                }
                // target 是击中三维的笛卡尔坐标点 可用于推导击中点的法线
                if (target) {
                    try {
                        var targetClamp = Cartesian3.ZERO.clone();
                        scene['clampToHeight'](target, [], 0.1, targetClamp);
                        // console.log('target', { target, targetClamp });
                    }
                    catch (e) { }
                }
            }
        }, 10);
        _this._onWheel = function (evt) {
            // console.log('wheel', evt);
            var _a = _this, viewer = _a.viewer, target = _a._target, dirc = _a._direction, miniDist = _a._minCameraDistance;
            var deltaY = evt.deltaY;
            if (Cartesian3.equals(target, Cartesian3.ZERO))
                return;
            if (!deltaY)
                return;
            // debugger;
            // console.log({ deltaY, target });
            // 平移相机
            var camera = viewer.camera;
            var position = camera.position, direction = camera.direction, up = camera.up;
            var speed = 1;
            var step = Cartesian3.ZERO.clone();
            var dist = Cartesian3.distance(target, position);
            // console.log(dist, miniDist);
            if (dist <= miniDist && deltaY < 0)
                return;
            Cartesian3.subtract(target, position, dirc);
            Cartesian3.normalize(dirc, dirc);
            try {
                camera.move(dirc, speed * (dist / 4) * (deltaY > 0 ? -1 : 1));
            }
            catch (e) {
                debugger;
            }
        };
        _this.viewer = viewer;
        _this._conPointer = conPointer;
        return _this;
    }
    FreeMode.prototype._installEvents = function () {
        var viewer = this.viewer;
        /** ****************************
         * 1. 关闭 Cesium 自带的鼠标行为
         * 2. 注册自定义的鼠标事件
         *  a. pointerdown
         *  b. pointermove
         *  c. pointerup
         *******************************/
        viewer.scene.screenSpaceCameraController.enableRotate = false;
        viewer.scene.screenSpaceCameraController.enableTranslate = false;
        viewer.scene.screenSpaceCameraController.enableZoom = false;
        viewer.scene.screenSpaceCameraController.enableTilt = false;
        viewer.scene.screenSpaceCameraController.enableLook = false;
        viewer.container.addEventListener('pointermove', this._onMove);
        viewer.container.addEventListener('pointerdown', this._onDown);
        viewer.container.addEventListener('pointerup', this._onUp);
        viewer.container.addEventListener('wheel', this._onWheel);
        viewer.container.addEventListener('click', this._onClick);
        viewer.container.addEventListener('dblclick', this._onDblClick);
        viewer.container.addEventListener('contextmenu', this._onRightClick, false);
        // console.log('mouse_pan on');
    };
    FreeMode.prototype._uninstallEvents = function () {
        var viewer = this.viewer;
        viewer.scene.screenSpaceCameraController.enableRotate = true;
        viewer.scene.screenSpaceCameraController.enableTranslate = true;
        viewer.scene.screenSpaceCameraController.enableZoom = true;
        viewer.scene.screenSpaceCameraController.enableTilt = true;
        viewer.scene.screenSpaceCameraController.enableLook = true;
        viewer.container.removeEventListener('pointermove', this._onMove);
        viewer.container.removeEventListener('pointerdown', this._onDown);
        viewer.container.removeEventListener('pointerup', this._onUp);
        viewer.container.removeEventListener('click', this._onClick);
        viewer.container.removeEventListener('dblclick', this._onDblClick);
        viewer.container.removeEventListener('contextmenu', this._onRightClick);
        // console.log('mouse_pan off');
    };
    FreeMode.prototype._targetMarkerVisible = function (marker) {
        var v = this.viewer;
        var target = this._target;
        var entity = this._targetEntity;
        entity.position = target;
        v.entities.remove(entity);
        if (marker === true) {
            entity.billboard.image = require('../../../assets/icon/marker_pan.png');
            v.entities.add(entity);
        }
        else if (marker === 'pan') {
            entity.billboard.image = require('../../../assets/icon/marker_pan.png');
            v.entities.add(entity);
        }
        else if (marker === 'rotate') {
            entity.billboard.image = require('../../../assets/icon/marker_rotate.png');
            v.entities.add(entity);
        }
        else if (marker === 'zoom') {
            entity.billboard.image = require('../../../assets/icon/marker_zoom.png');
            v.entities.add(entity);
        }
        else if (marker === 'setting') {
            entity.billboard.image = require('../../../assets/icon/marker_setting.png');
            v.entities.add(entity);
        }
        else {
            v.entities.remove(entity);
        }
    };
    Object.defineProperty(FreeMode.prototype, "isActive", {
        get: function () {
            return this._isActive;
        },
        set: function (val) {
            var conP = this._conPointer;
            if (val === this._isActive)
                return;
            if (val) {
                this._installEvents();
            }
            else {
                this._uninstallEvents();
            }
            this._isActive = val;
        },
        enumerable: true,
        configurable: true
    });
    return FreeMode;
}(EventEmitter));
export default FreeMode;
