import { __awaiter, __extends, __generator } from "tslib";
import { throttle } from "lodash";
import { Cartesian3, Color, Cartographic, CallbackProperty, Cartesian2, } from "@taotieh/cesium_extend";
import Measure from "./Measure";
// import Instance from '../../../core/Instance';
import { TIMESPAN_INSTANT } from "../../../core/Constant";
var State;
(function (State) {
    State[State["READY"] = 0] = "READY";
    State[State["POINT_ORIGIN_SELECTED"] = 1] = "POINT_ORIGIN_SELECTED";
    State[State["POINT_LATEST_SELECTED"] = 2] = "POINT_LATEST_SELECTED";
    State[State["DONE"] = 3] = "DONE";
})(State || (State = {}));
var MeasureDistanceHeight = /** @class */ (function (_super) {
    __extends(MeasureDistanceHeight, _super);
    function MeasureDistanceHeight(viewer, instance) {
        var _this = _super.call(this, viewer, instance) || this;
        _this._state = State.READY;
        _this._points = []; //[orign, ..., latest]
        _this._vectors = []; //[v_1, ...]
        _this._tracingEnts = [];
        /* 实时跟踪实体 */
        _this._moveGeo = {};
        /** **********************************************************
         *  这里用 Protected 是有原因的. 具体看基类 Measure.
         *  因为基类也实现了 _onMove 的基础功能. 这里实际是在重写属性.
         *************************************************************/
        _this._onMove = throttle(function (evt) { return __awaiter(_this, void 0, void 0, function () {
            var _a, target, points, ents, cPo, latest;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this, target = _a._target, points = _a._points, ents = _a._tracingEnts;
                        return [4 /*yield*/, this._instance.getInstancePointerControl()];
                    case 1:
                        cPo = _b.sent();
                        cPo.target.clone(target);
                        latest = points[points.length - 1];
                        if (!latest || Cartesian3.equals(target, Cartesian3.ZERO))
                            return [2 /*return*/];
                        this._latest = target;
                        return [2 /*return*/];
                }
            });
        }); }, TIMESPAN_INSTANT);
        _this._onPointerDown = function (evt) { return __awaiter(_this, void 0, void 0, function () {
            var button;
            return __generator(this, function (_a) {
                button = evt.button;
                // console.log('_onPointerDown', evt);
                if (button === 2) {
                    // 右键结束
                    this.stop();
                }
                return [2 /*return*/];
            });
        }); };
        _this._toReset();
        return _this;
    }
    /* 计算垂足点 */
    MeasureDistanceHeight.prototype._calVerticalPoint = function (prevPoint, latest) {
        var p0_graph = Cartographic.fromCartesian(prevPoint);
        var latest_graph = Cartographic.fromCartesian(latest);
        latest_graph.height = p0_graph.height;
        return Cartographic.toCartesian(latest_graph);
    };
    /* 实时回调属性 */
    MeasureDistanceHeight.prototype._getMoveNeighborMiddle = function (latest) {
        var _this = this;
        return function () {
            var middle_union_one = Cartesian3.ZERO.clone();
            latest = latest || _this._latest;
            if (!latest)
                return middle_union_one;
            var prevPoint = _this._points.slice(-1)[0];
            Cartesian3.add(prevPoint, latest, middle_union_one);
            Cartesian3.multiplyByScalar(middle_union_one, 0.5, middle_union_one);
            return middle_union_one;
        };
    };
    MeasureDistanceHeight.prototype._getMoveNeighborLabel = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return "";
            var prevPoint = _this._points.slice(-1)[0];
            return Cartesian3.distance(prevPoint, latest).toFixed(2) + " \u7C73";
        };
    };
    MeasureDistanceHeight.prototype._getMoveNeighborLine = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return [];
            var prevPoint = _this._points.slice(-1)[0];
            return [prevPoint, latest];
        };
    };
    MeasureDistanceHeight.prototype._getMoveSideMiddle = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            var middle_union_two = Cartesian3.ZERO.clone();
            if (!latest)
                return middle_union_two;
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            Cartesian3.add(prevPoint, verticalPoint, middle_union_two);
            Cartesian3.multiplyByScalar(middle_union_two, 0.5, middle_union_two);
            return middle_union_two;
        };
    };
    MeasureDistanceHeight.prototype._getMoveSideLabel = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return "";
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            return Cartesian3.distance(prevPoint, verticalPoint).toFixed(2) + " \u7C73";
        };
    };
    MeasureDistanceHeight.prototype._getMoveSideLine = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return [];
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            return [verticalPoint, prevPoint];
        };
    };
    MeasureDistanceHeight.prototype._getMoveVerticalMiddle = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            var middle_vertical = Cartesian3.ZERO.clone();
            if (!latest)
                return middle_vertical;
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            Cartesian3.add(latest, verticalPoint, middle_vertical);
            Cartesian3.multiplyByScalar(middle_vertical, 0.5, middle_vertical);
            return middle_vertical;
        };
    };
    MeasureDistanceHeight.prototype._getMoveVerticalLabel = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return "";
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            return Cartesian3.distance(latest, verticalPoint).toFixed(2) + " \u7C73";
        };
    };
    MeasureDistanceHeight.prototype._getMoveVerticalLine = function (latest) {
        var _this = this;
        return function () {
            latest = latest || _this._latest;
            if (!latest)
                return [];
            var prevPoint = _this._points.slice(-1)[0];
            var verticalPoint = _this._calVerticalPoint(prevPoint, latest);
            return [verticalPoint, latest];
        };
    };
    MeasureDistanceHeight.prototype._toSelectOrigin = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, scene, points, origin;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this, scene = _a._viewer.scene, points = _a._points;
                        return [4 /*yield*/, this._selectPoint(new Cartesian3())];
                    case 1:
                        origin = _b.sent();
                        if (this._state === State.DONE) {
                            return [2 /*return*/];
                        }
                        points.push(origin);
                        console.log("选中原点, 下一步选则目标对象", origin);
                        this.emit("message", "选中原点, 下一步萱蕚目标对象", origin);
                        this._state = State.POINT_ORIGIN_SELECTED;
                        this._moveGeo.neighborLabel = this._drawLabel(new CallbackProperty(this._getMoveNeighborMiddle(), false), new CallbackProperty(this._getMoveNeighborLabel(), false));
                        this._moveGeo.neighborLine = this._drawLine(new CallbackProperty(this._getMoveNeighborLine(), false), Color.GREEN.withAlpha(0.3), 2);
                        this._moveGeo.sideLabel = this._drawLabel(new CallbackProperty(this._getMoveSideMiddle(), false), new CallbackProperty(this._getMoveSideLabel(), false));
                        this._moveGeo.sideLine = this._drawLine(new CallbackProperty(this._getMoveSideLine(), false), Color.BLUE.withAlpha(0.3), 2);
                        this._moveGeo.verticalLabel = this._drawLabel(new CallbackProperty(this._getMoveVerticalMiddle(), false), new CallbackProperty(this._getMoveVerticalLabel(), false));
                        this._moveGeo.verticalLine = this._drawLine(new CallbackProperty(this._getMoveVerticalLine(), false), Color.YELLOW.withAlpha(0.3), 2);
                        this._drawPoint(origin, Color.RED, 6);
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureDistanceHeight.prototype._toSelectLatest = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, scene, points, latest, prevPoint, middle_union_one, verticalPoint, middle_vertical, middle_union_two;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this, scene = _a._viewer.scene, points = _a._points;
                        return [4 /*yield*/, this._selectPoint(new Cartesian3())];
                    case 1:
                        latest = _b.sent();
                        /* 完成后，鼠标up事件会继续执行，这里做判断避免无限循环 */
                        if (this._state === State.DONE) {
                            return [2 /*return*/];
                        }
                        /**
                         * 完成一次绘制
                         * 执行各种画图
                         */
                        /* 绘制点位 */
                        this._drawPoint(latest, Color.YELLOW, 6);
                        prevPoint = points.slice(-1)[0];
                        this._drawLine([prevPoint, latest], Color.GREEN, 2);
                        middle_union_one = this._getMoveNeighborMiddle(latest)();
                        this._drawLabel(middle_union_one, Cartesian3.distance(prevPoint, latest).toFixed(2) + " \u7C73", new Cartesian2(0, -9), new Color(0, 0, 0, 0.8));
                        verticalPoint = this._calVerticalPoint(prevPoint, latest);
                        this._drawLine([verticalPoint, latest], Color.YELLOW, 2);
                        middle_vertical = this._getMoveVerticalMiddle(latest)();
                        this._drawLabel(middle_vertical, Cartesian3.distance(verticalPoint, latest).toFixed(2) + " \u7C73");
                        /* 显示垂足与上个点连线 */
                        this._drawLine([prevPoint, verticalPoint], Color.BLUE, 2);
                        middle_union_two = this._getMoveSideMiddle(latest)();
                        this._drawLabel(middle_union_two, Cartesian3.distance(prevPoint, verticalPoint).toFixed(2) + " \u7C73");
                        points.push(latest);
                        console.log("选中一个新点, 右键结束选择", latest);
                        this.emit("message", "选中一个新点, 右键结束选择", latest);
                        this._state = State.POINT_LATEST_SELECTED;
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureDistanceHeight.prototype._toCalculateDistance = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, ps, vs;
            return __generator(this, function (_b) {
                _a = this, ps = _a._points, vs = _a._vectors;
                console.log("计算完毕, 开始绘图.", { origin: origin });
                this._toShowResult();
                this._state = State.DONE;
                this.next();
                return [2 /*return*/];
            });
        });
    };
    MeasureDistanceHeight.prototype._doneMeasure = function () {
        this._state = State.DONE;
        this.next();
    };
    MeasureDistanceHeight.prototype._toShowResult = function () { };
    MeasureDistanceHeight.prototype._toClearResult = function () {
        var _a = this, _b = _a._points, origin = _b[0], drop = _b[1], _c = _a._vectors, v_1 = _c[0], v_2 = _c[1], normal = _c[2], n_tmp = _c[3];
    };
    MeasureDistanceHeight.prototype._toReset = function () {
        var _a = this, ps = _a._points, vs = _a._vectors;
        ps.length = 0;
        vs.length = 0;
        this._toClearResult();
        this._state = State.READY;
    };
    MeasureDistanceHeight.prototype._installSubEvents = function () {
        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
            return [2 /*return*/];
        }); });
    };
    MeasureDistanceHeight.prototype._uninstallSubEvents = function () {
        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
            return [2 /*return*/];
        }); });
    };
    MeasureDistanceHeight.prototype.start = function () {
        return __awaiter(this, void 0, void 0, function () {
            var cPo;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        cPo = this._instance.getInstancePointerControl();
                        cPo.once('rightClick', function () { return _this.stop(); });
                        _super.prototype.start.call(this);
                        this._toReset();
                        return [4 /*yield*/, this._installSubEvents()];
                    case 1:
                        _a.sent();
                        console.log("开始测量");
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureDistanceHeight.prototype.next = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this._state;
                        switch (_a) {
                            case State.READY: return [3 /*break*/, 1];
                            case State.POINT_ORIGIN_SELECTED: return [3 /*break*/, 3];
                            case State.POINT_LATEST_SELECTED: return [3 /*break*/, 5];
                            case State.DONE: return [3 /*break*/, 7];
                        }
                        return [3 /*break*/, 9];
                    case 1: return [4 /*yield*/, this._toSelectOrigin()];
                    case 2:
                        _b.sent();
                        return [3 /*break*/, 11];
                    case 3: return [4 /*yield*/, this._toSelectLatest()];
                    case 4:
                        _b.sent();
                        return [3 /*break*/, 11];
                    case 5: return [4 /*yield*/, this._toSelectLatest()];
                    case 6:
                        _b.sent();
                        return [3 /*break*/, 11];
                    case 7: return [4 /*yield*/, this._toShowResult()];
                    case 8:
                        _b.sent();
                        this.emit("message", "完成测量");
                        return [3 /*break*/, 11];
                    case 9: return [4 /*yield*/, this._toReset()];
                    case 10:
                        _b.sent();
                        _b.label = 11;
                    case 11: return [2 /*return*/];
                }
            });
        });
    };
    MeasureDistanceHeight.prototype.stop = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _a = this._state;
                        switch (_a) {
                            case State.READY: return [3 /*break*/, 1];
                            case State.POINT_ORIGIN_SELECTED: return [3 /*break*/, 2];
                            case State.POINT_LATEST_SELECTED: return [3 /*break*/, 3];
                            case State.DONE: return [3 /*break*/, 5];
                        }
                        return [3 /*break*/, 6];
                    case 1:
                        this.emit("message", "取消测量");
                        this._doneMeasure();
                        return [3 /*break*/, 8];
                    case 2:
                        this.emit("message", "仅选择了起点, 终止测量");
                        this._doneMeasure();
                        return [3 /*break*/, 8];
                    case 3: return [4 /*yield*/, this._toCalculateDistance()];
                    case 4:
                        _b.sent();
                        return [3 /*break*/, 8];
                    case 5:
                        this.emit("message", "已经完成测量");
                        this._doneMeasure();
                        return [3 /*break*/, 8];
                    case 6: return [4 /*yield*/, this._toReset()];
                    case 7:
                        _b.sent();
                        _b.label = 8;
                    case 8:
                        Object.values(this._moveGeo).forEach(function (e) { return e && _this._clearEntity(e); });
                        _super.prototype.stop.call(this);
                        return [4 /*yield*/, this._uninstallSubEvents()];
                    case 9:
                        _b.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    return MeasureDistanceHeight;
}(Measure));
export default MeasureDistanceHeight;
