"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Inlined from
// https://github.com/rowanwins/sweepline-intersections
// Needed to go through babel to transform ES6 classes
var commonjsGlobal = typeof globalThis !== "undefined"
    ? globalThis
    : typeof window !== "undefined"
        ? window
        : typeof global !== "undefined"
            ? global
            : typeof self !== "undefined"
                ? self
                : {};
function createCommonjsModule(fn, module) {
    return (module = { exports: {} }), fn(module, module.exports), module.exports;
}
var tinyqueue = createCommonjsModule(function (module) {
    (function (global, factory) {
        module.exports = factory();
    })(commonjsGlobal, function () {
        var TinyQueue = function TinyQueue(data, compare) {
            if (data === void 0)
                data = [];
            if (compare === void 0)
                compare = defaultCompare;
            this.data = data;
            this.length = this.data.length;
            this.compare = compare;
            if (this.length > 0) {
                for (var i = (this.length >> 1) - 1; i >= 0; i--) {
                    this._down(i);
                }
            }
        };
        TinyQueue.prototype.push = function push(item) {
            this.data.push(item);
            this.length++;
            this._up(this.length - 1);
        };
        TinyQueue.prototype.pop = function pop() {
            if (this.length === 0) {
                return undefined;
            }
            var top = this.data[0];
            var bottom = this.data.pop();
            this.length--;
            if (this.length > 0) {
                this.data[0] = bottom;
                this._down(0);
            }
            return top;
        };
        TinyQueue.prototype.peek = function peek() {
            return this.data[0];
        };
        TinyQueue.prototype._up = function _up(pos) {
            var ref = this;
            var data = ref.data;
            var compare = ref.compare;
            var item = data[pos];
            while (pos > 0) {
                var parent = (pos - 1) >> 1;
                var current = data[parent];
                if (compare(item, current) >= 0) {
                    break;
                }
                data[pos] = current;
                pos = parent;
            }
            data[pos] = item;
        };
        TinyQueue.prototype._down = function _down(pos) {
            var ref = this;
            var data = ref.data;
            var compare = ref.compare;
            var halfLength = this.length >> 1;
            var item = data[pos];
            while (pos < halfLength) {
                var left = (pos << 1) + 1;
                var best = data[left];
                var right = left + 1;
                if (right < this.length && compare(data[right], best) < 0) {
                    left = right;
                    best = data[right];
                }
                if (compare(best, item) >= 0) {
                    break;
                }
                data[pos] = best;
                pos = left;
            }
            data[pos] = item;
        };
        function defaultCompare(a, b) {
            return a < b ? -1 : a > b ? 1 : 0;
        }
        return TinyQueue;
    });
});
function checkWhichEventIsLeft(e1, e2) {
    if (e1.p.x > e2.p.x)
        return 1;
    if (e1.p.x < e2.p.x)
        return -1;
    if (e1.p.y !== e2.p.y)
        return e1.p.y > e2.p.y ? 1 : -1;
    return 1;
}
function checkWhichSegmentHasRightEndpointFirst(seg1, seg2) {
    if (seg1.rightSweepEvent.p.x > seg2.rightSweepEvent.p.x)
        return 1;
    if (seg1.rightSweepEvent.p.x < seg2.rightSweepEvent.p.x)
        return -1;
    if (seg1.rightSweepEvent.p.y !== seg2.rightSweepEvent.p.y)
        return seg1.rightSweepEvent.p.y < seg2.rightSweepEvent.p.y ? 1 : -1;
    return 1;
}
function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}
function _defineProperties(target, props) {
    for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor)
            descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function _createClass(Constructor, protoProps, staticProps) {
    if (protoProps)
        _defineProperties(Constructor.prototype, protoProps);
    if (staticProps)
        _defineProperties(Constructor, staticProps);
    return Constructor;
}
var Event = /*#__PURE__*/ (function () {
    function Event(p, featureId, ringId, eventId) {
        _classCallCheck(this, Event);
        this.p = {
            x: p[0],
            y: p[1],
        };
        this.featureId = featureId;
        this.ringId = ringId;
        this.eventId = eventId;
        this.otherEvent = null;
        this.isLeftEndpoint = null;
    }
    _createClass(Event, [
        {
            key: "isSamePoint",
            value: function isSamePoint(eventToCheck) {
                return this.p.x === eventToCheck.p.x && this.p.y === eventToCheck.p.y;
            },
        },
    ]);
    return Event;
})();
function fillEventQueue(geojson, eventQueue) {
    if (geojson.type === "FeatureCollection") {
        var features = geojson.features;
        for (var i = 0; i < features.length; i++) {
            processFeature(features[i], eventQueue);
        }
    }
    else {
        processFeature(geojson, eventQueue);
    }
}
var featureId = 0;
var ringId = 0;
var eventId = 0;
function processFeature(featureOrGeometry, eventQueue) {
    var geom = featureOrGeometry.type === "Feature"
        ? featureOrGeometry.geometry
        : featureOrGeometry;
    var coords = geom.coordinates; // standardise the input
    if (geom.type === "Polygon" || geom.type === "MultiLineString")
        coords = [coords];
    if (geom.type === "LineString")
        coords = [[coords]];
    for (var i = 0; i < coords.length; i++) {
        for (var ii = 0; ii < coords[i].length; ii++) {
            var currentP = coords[i][ii][0];
            var nextP = null;
            ringId = ringId + 1;
            for (var iii = 0; iii < coords[i][ii].length - 1; iii++) {
                nextP = coords[i][ii][iii + 1];
                var e1 = new Event(currentP, featureId, ringId, eventId);
                var e2 = new Event(nextP, featureId, ringId, eventId + 1);
                e1.otherEvent = e2;
                e2.otherEvent = e1;
                if (checkWhichEventIsLeft(e1, e2) > 0) {
                    e2.isLeftEndpoint = true;
                    e1.isLeftEndpoint = false;
                }
                else {
                    e1.isLeftEndpoint = true;
                    e2.isLeftEndpoint = false;
                }
                eventQueue.push(e1);
                eventQueue.push(e2);
                currentP = nextP;
                eventId = eventId + 1;
            }
        }
    }
    featureId = featureId + 1;
}
var Segment = function Segment(event) {
    _classCallCheck(this, Segment);
    this.leftSweepEvent = event;
    this.rightSweepEvent = event.otherEvent;
};
function testSegmentIntersect(seg1, seg2) {
    if (seg1 === null || seg2 === null)
        return false;
    if (seg1.leftSweepEvent.ringId === seg2.leftSweepEvent.ringId &&
        (seg1.rightSweepEvent.isSamePoint(seg2.leftSweepEvent) ||
            seg1.rightSweepEvent.isSamePoint(seg2.leftSweepEvent) ||
            seg1.rightSweepEvent.isSamePoint(seg2.rightSweepEvent) ||
            seg1.leftSweepEvent.isSamePoint(seg2.leftSweepEvent) ||
            seg1.leftSweepEvent.isSamePoint(seg2.rightSweepEvent)))
        return false;
    var x1 = seg1.leftSweepEvent.p.x;
    var y1 = seg1.leftSweepEvent.p.y;
    var x2 = seg1.rightSweepEvent.p.x;
    var y2 = seg1.rightSweepEvent.p.y;
    var x3 = seg2.leftSweepEvent.p.x;
    var y3 = seg2.leftSweepEvent.p.y;
    var x4 = seg2.rightSweepEvent.p.x;
    var y4 = seg2.rightSweepEvent.p.y;
    var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
    var numeA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
    var numeB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
    if (denom === 0) {
        if (numeA === 0 && numeB === 0)
            return false;
        return false;
    }
    var uA = numeA / denom;
    var uB = numeB / denom;
    if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
        var x = x1 + uA * (x2 - x1);
        var y = y1 + uA * (y2 - y1);
        return [x, y];
    }
    return false;
}
function runCheck(eventQueue, ignoreSelfIntersections) {
    ignoreSelfIntersections = ignoreSelfIntersections
        ? ignoreSelfIntersections
        : false;
    var intersectionPoints = [];
    var outQueue = new tinyqueue([], checkWhichSegmentHasRightEndpointFirst);
    while (eventQueue.length) {
        var event = eventQueue.pop();
        if (event.isLeftEndpoint) {
            // debugEventAndSegments(event.p, outQueue.data)
            var segment = new Segment(event);
            for (var i = 0; i < outQueue.data.length; i++) {
                var otherSeg = outQueue.data[i];
                if (ignoreSelfIntersections) {
                    if (otherSeg.leftSweepEvent.featureId === event.featureId)
                        continue;
                }
                var intersection = testSegmentIntersect(segment, otherSeg);
                if (intersection !== false)
                    intersectionPoints.push(intersection);
            }
            outQueue.push(segment);
        }
        else if (event.isLeftEndpoint === false) {
            outQueue.pop(); // const seg = outQueue.pop()
            // debugRemovingSegment(event.p, seg)
        }
    }
    return intersectionPoints;
}
function sweeplineIntersections(geojson, ignoreSelfIntersections) {
    var eventQueue = new tinyqueue([], checkWhichEventIsLeft);
    fillEventQueue(geojson, eventQueue);
    return runCheck(eventQueue, ignoreSelfIntersections);
}
exports.default = sweeplineIntersections;
