import { __awaiter, __extends, __generator } from "tslib";
import { throttle } from "lodash";
import { Cartesian3, Color, Cartesian2, CallbackProperty, } 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_SECOND_SELECTED"] = 2] = "POINT_SECOND_SELECTED";
    State[State["POINT_LATEST_SELECTED"] = 3] = "POINT_LATEST_SELECTED";
    State[State["DONE"] = 4] = "DONE";
})(State || (State = {}));
var MeasureAnglePointChain = /** @class */ (function (_super) {
    __extends(MeasureAnglePointChain, _super);
    function MeasureAnglePointChain(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._moveDraw = {};
        /** **********************************************************
         *  这里用 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;
    }
    MeasureAnglePointChain.prototype._moveAngelLabelMid = function () {
        var _this = this;
        var points = this._points;
        return function () {
            var latest = _this._latest;
            var midpoint = new Cartesian3();
            if (points.length < 2 || !latest)
                return midpoint;
            var _a = points.slice(-2), pre_2 = _a[0], pre_1 = _a[1];
            var m1p = Cartesian3.subtract(pre_2, pre_1, new Cartesian3());
            Cartesian3.normalize(m1p, m1p);
            var m2p = Cartesian3.subtract(latest, pre_1, new Cartesian3());
            if (Cartesian3.equals(m2p, Cartesian3.ZERO))
                return midpoint;
            Cartesian3.normalize(m2p, m2p);
            Cartesian3.add(Cartesian3.add(pre_1, m1p, m1p), Cartesian3.add(pre_1, m2p, m2p), midpoint);
            Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint);
            return midpoint;
        };
    };
    MeasureAnglePointChain.prototype._moveAngelLabel = function () {
        var _this = this;
        var points = this._points;
        return function () {
            var latest = _this._latest;
            if (points.length < 2 || !latest)
                return "";
            var _a = points.slice(-2), pre_2 = _a[0], pre_1 = _a[1];
            var v1 = Cartesian3.subtract(pre_2, pre_1, new Cartesian3());
            Cartesian3.normalize(v1, v1);
            var v2 = Cartesian3.subtract(latest, pre_1, new Cartesian3());
            if (Cartesian3.equals(v2, Cartesian3.ZERO))
                return "";
            Cartesian3.normalize(v2, v2);
            var angle = (Math.acos(Cartesian3.dot(v1, v2)) * 180) / Math.PI;
            return angle.toFixed(2) + " \u00B0";
        };
    };
    MeasureAnglePointChain.prototype._moveAngelLine = function () {
        var _this = this;
        var points = this._points;
        return function () {
            var latest = _this._latest;
            if (points.length < 2 || !latest)
                return [];
            var _a = points.slice(-2), pre_2 = _a[0], pre_1 = _a[1];
            return _this._drawArc(pre_1, pre_2, latest);
        };
    };
    MeasureAnglePointChain.prototype._movelLine = function () {
        var _this = this;
        var points = this._points;
        return function () {
            var pre_1 = points.slice(-1)[0];
            var latest = _this._latest;
            if (!latest)
                return [];
            return [pre_1, latest];
        };
    };
    MeasureAnglePointChain.prototype._toSelectOrigin = function () {
        return __awaiter(this, void 0, void 0, function () {
            var points, origin;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        points = this._points;
                        return [4 /*yield*/, this._selectPoint(new Cartesian3())];
                    case 1:
                        origin = _a.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._drawPoint(origin, Color.RED, 6);
                        this._moveDraw._label = this._drawLabel(new CallbackProperty(this._moveAngelLabelMid(), false), new CallbackProperty(this._moveAngelLabel(), false));
                        this._moveDraw._angleLine = this._drawLine(new CallbackProperty(this._moveAngelLine(), false), Color.AQUA.withAlpha(0.3), 2);
                        this._moveDraw._line = this._drawLine(new CallbackProperty(this._movelLine(), false), Color.GREEN.withAlpha(0.3), 2);
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureAnglePointChain.prototype._toSelectSecond = function () {
        return __awaiter(this, void 0, void 0, function () {
            var points, second, p1, p2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        points = this._points;
                        return [4 /*yield*/, this._selectPoint(new Cartesian3())];
                    case 1:
                        second = _a.sent();
                        if (this._state === State.DONE) {
                            return [2 /*return*/];
                        }
                        points.push(second);
                        console.log("选中第二个点, 下一步选则目标对象", second);
                        this._state = State.POINT_SECOND_SELECTED;
                        p1 = points[0], p2 = points[1];
                        this._drawLine([p1, p2], Color.GREEN, 2);
                        this._drawPoint(second, Color.RED, 6);
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureAnglePointChain.prototype._toSelectLatest = function () {
        return __awaiter(this, void 0, void 0, function () {
            var points, latest, pre_2, pre_1, direction, target_1, v1, v2, angle, midpoint;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        points = this._points;
                        return [4 /*yield*/, this._selectPoint(new Cartesian3())];
                    case 1:
                        latest = _a.sent();
                        if (this._state === State.DONE) {
                            return [2 /*return*/];
                        }
                        this._state = State.POINT_LATEST_SELECTED;
                        pre_2 = points[points.length - 2];
                        pre_1 = points[points.length - 1];
                        if (Cartesian3.distance(latest, pre_1) < 0.01) {
                            // 距离太近. 跳过本次结果
                            this.next();
                        }
                        direction = Cartesian3.subtract(pre_1, pre_2, new Cartesian3());
                        target_1 = Cartesian3.add(pre_1, Cartesian3.normalize(direction, direction), new Cartesian3());
                        this._drawLine([pre_1, target_1], Color.YELLOW, 1);
                        this._drawLine([pre_1, latest], Color.GREEN, 2);
                        this._drawPoint(latest, Color.RED, 4);
                        v1 = Cartesian3.normalize(Cartesian3.subtract(pre_2, pre_1, new Cartesian3()), new Cartesian3());
                        v2 = Cartesian3.normalize(Cartesian3.subtract(latest, pre_1, new Cartesian3()), new Cartesian3());
                        angle = (Math.acos(Cartesian3.dot(v1, v2)) * 180) / Math.PI;
                        this._drawLine(this._drawArc(pre_1, pre_2, latest), Color.AQUA, 1);
                        midpoint = this._moveAngelLabelMid()();
                        this._drawLabel(midpoint, angle.toFixed(2) + " \u00B0", new Cartesian2(0, -9), new Color(0, 0, 0, 0.8));
                        points.push(latest);
                        this.next();
                        return [2 /*return*/];
                }
            });
        });
    };
    MeasureAnglePointChain.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*/];
            });
        });
    };
    MeasureAnglePointChain.prototype._doneMeasure = function () {
        this._state = State.DONE;
        this.next();
    };
    MeasureAnglePointChain.prototype._toShowResult = function () { };
    MeasureAnglePointChain.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];
    };
    MeasureAnglePointChain.prototype._toReset = function () {
        var _a = this, ps = _a._points, vs = _a._vectors;
        ps.length = 0;
        vs.length = 0;
        this._toClearResult();
        this._state = State.READY;
    };
    MeasureAnglePointChain.prototype._installSubEvents = function () {
        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
            return [2 /*return*/];
        }); });
    };
    MeasureAnglePointChain.prototype._uninstallSubEvents = function () {
        return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) {
            return [2 /*return*/];
        }); });
    };
    MeasureAnglePointChain.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*/];
                }
            });
        });
    };
    MeasureAnglePointChain.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_SECOND_SELECTED: return [3 /*break*/, 5];
                            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._toSelectSecond()];
                    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*/];
                }
            });
        });
    };
    MeasureAnglePointChain.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_SECOND_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("取消测量");
                        this._doneMeasure();
                        return [3 /*break*/, 8];
                    case 2:
                        this.emit("message", "仅选择第一个点或第二个点，结束测量");
                        this._doneMeasure();
                        return [3 /*break*/, 8];
                    case 3:
                        this.emit("message", "结束测量");
                        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:
                        this.emit("message", "终止测量");
                        return [4 /*yield*/, this._toReset()];
                    case 7:
                        _b.sent();
                        _b.label = 8;
                    case 8:
                        Object.values(this._moveDraw).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 MeasureAnglePointChain;
}(Measure));
export default MeasureAnglePointChain;
