
cc.Class({
    extends: cc.Component,

    properties: {

        // polys: {
        //     get: () => {
        //         return this._polys.map((v) => { return this._convertClipperPathToVecArray(v) });
        //     }
        // }
    },

    // LIFE-CYCLE CALLBACKS:

    onLoad() {
        //
        this.DIG_OPTIMIZE_SIZE = 1;
        //
        this._commands = [];
        this._physicsPolygonColliders = [];
        this._polys = [[]];
    },
    // get polys() {
    //     return this._polys.map((v) => { return this._convertClipperPathToVecArray(v) });
    // },
    start() {

    },
    _convertClipperPathToVecArray(poly) {
        return poly.map((p) => { return cc.v2(p.X, p.Y) });
    },
    _convertVecArrayToClipperPath(poly) {
        return poly.map((p) => { return { X: p.x, Y: p.y } });
    },
    _convertClipperPathToPoly2triPoint(poly, exclude) {
        // return poly.map((p) => { return new poly2tri.Point(p.X, p.Y) });
        let newPos = [];
        poly.forEach((p, i) => {
            let p_now = new poly2tri.Point(p.X, p.Y)
            let isIn = exclude.some((e_p) => {
                if (e_p.equals(p_now)) {
                    return true;
                }
            })
            if (!isIn) {
                newPos.push(p_now);
                exclude.push(p_now);
            }
        })
        if (newPos.length > 2)
            return newPos;
        else
            return [];
    },
    init(polys) {
        this._polys = polys.map((v) => { return this._convertVecArrayToClipperPath(v) });
        this._commands = [];
    },
    polyDifference(poly, ctx) {
        if (!ctx) {
            cc.error("no ctx")
        }
        let cpr = new ClipperLib.Clipper();
        let subj_paths = this._polys;
        let clip_paths = [this._convertVecArrayToClipperPath(poly)]
        cpr.AddPaths(subj_paths, ClipperLib.PolyType.ptSubject, true);
        cpr.AddPaths(clip_paths, ClipperLib.PolyType.ptClip, true);
        let subject_fillType = ClipperLib.PolyFillType.pftEvenOdd;
        let clip_fillType = ClipperLib.PolyFillType.pftEvenOdd;
        let solution_polytree = new ClipperLib.PolyTree();
        cpr.Execute(ClipperLib.ClipType.ctDifference, solution_polytree, subject_fillType, clip_fillType);
        let solution_expolygons = ClipperLib.JS.PolyTreeToExPolygons(solution_polytree);
        this._polys = ClipperLib.Clipper.PolyTreeToPaths(solution_polytree);
        //
        ctx && ctx.clear(true);
        let _physicsPolygonColliders_count = 0;
        for (let expolygon of solution_expolygons) {
            // let outers = ClipperLib.Clipper.SimplifyPolygon(expolygon.outer,ClipperLib.PolyFillType.pftEvenOdd);
            // cc.log(outer,"outer",expolygon.outer)
            let countor = this._convertClipperPathToPoly2triPoint(expolygon.outer);
            if (countor.length < 2) continue;
            let swctx = new poly2tri.SweepContext(countor, { cloneArrays: true });
            // let exclude = countor;
            let holes = expolygon.holes.map(h => { return this._convertClipperPathToPoly2triPoint(h, countor) });
            try {
                // 防止 addhole 失败 使用try
                swctx.addHoles(holes);
                swctx.triangulate();
                let triangles = swctx.getTriangles();
                for (let tri of triangles) {
                    // 逐一处理三角形
                    let c = this._physicsPolygonColliders[_physicsPolygonColliders_count];
                    if (!c) {
                        c = this.addComponent(cc.PhysicsPolygonCollider);
                        c.friction = 0;
                        c.restitution = 0;
                        this._physicsPolygonColliders[_physicsPolygonColliders_count] = c;
                    }
                    c.points = tri.getPoints().map((v, i) => {
                        if (ctx) {
                            if (i === 0) ctx.moveTo(v.x, v.y);
                            else ctx.lineTo(v.x, v.y);
                        }
                        return cc.v2(v.x, v.y)
                    });
                    c.apply();
                    _physicsPolygonColliders_count++;
                    if (ctx) {
                        ctx.close();
                        ctx.fill();
                    }
                }
            } catch (e) {
                console.error('polyDifference poly2tri error', _physicsPolygonColliders_count, expolygon);
                console.error(e);
                continue;
            }
        }
        this._physicsPolygonColliders.slice(_physicsPolygonColliders_count).forEach((v => {
            if (v.points.length) {
                v.points.length = 0;
                v.apply();
            }
        }));
    },

    pushCommand(name, params) {
        this._commands.push({ name, params });
    },
    lateUpdate(dt) {
        if (this._commands.length) {
            // 每帧执行命令队列
            for (let index = 0; index < 2; index++) {
                let cmd = this._commands.shift();
                if (cmd)
                    this[cmd.name](...cmd.params);
                else
                    break;
            }
        }
    },
    // update (dt) {},
});
