import { getAbsoluteUrl } from '../utils';
export class Map {
    constructor() {
        this.drawing = false;
        this.zoom = 10;
        this.minzoom = 0;
        this.maxzoom = 22;
    }
    componentWillLoad() {
        this._style = this.loadStyle();
        this.map = new mapboxgl.Map({
            container: this.el,
            center: [this.longitude, this.latitude],
            zoom: this.zoom,
            minZoom: this.minzoom,
            maxZoom: this.maxzoom,
            style: this._style
        });
        window.addEventListener('resize', this.resizeMap.bind(this));
        this.map.on('draw.create', (e) => this.glDrawCreate.emit({
            mapId: this.id,
            features: e.features
        }));
        this.map.on('draw.delete', (e) => this.glDrawDelete.emit({
            mapId: this.id,
            features: e.features
        }));
    }
    componentDidUpdate() {
        this.resizeMap();
    }
    async updateStyle() {
        if (this._updateStyleTimeout)
            return;
        this._updateStyleTimeout = window.setTimeout(async () => {
            this._updateStyleTimeout = null;
            this._style = await this.loadStyle();
            this.map.setStyle(this._style);
            this.glStyleUpdated.emit(this._style);
        }, 66);
    }
    async handleStyleAdded() {
        this.updateStyle();
    }
    async handleStyleModified() {
        this.updateStyle();
    }
    async handleStyleRemoved() {
        this.updateStyle();
    }
    async updateDrawing() {
        if (this.drawing) {
            this.draw = new MapboxDraw(this.drawOptions);
            this.map.addControl(this.draw);
            this.glDrawEnter.emit({
                mapId: this.id
            });
        }
        else {
            this.map.removeControl(this.draw);
            this.draw = null;
            this.glDrawExit.emit({
                mapId: this.id
            });
        }
    }
    resizeMap() {
        if (this._resizeMapTimeout)
            return;
        this._resizeMapTimeout = window.setTimeout(async () => {
            this._resizeMapTimeout = null;
            if (this.map)
                this.map.resize();
        }, 66);
    }
    getStyleLayers(styleId, json) {
        if (!json.layers)
            return [];
        let results = [];
        for (let layer of json.layers) {
            let result = Object.assign({}, layer, { id: this.prefix(styleId, layer.id) });
            if (layer.source)
                result.source = this.prefix(styleId, layer.source);
            results.push(result);
        }
        return results;
    }
    getStyleSources(styleId, json) {
        if (!json.sources)
            return [];
        let sources = {};
        for (let sourceName in json.sources)
            sources[this.prefix(styleId, sourceName)] = json.sources[sourceName];
        return sources;
    }
    loadStyle() {
        let style = {
            version: 8,
            metadata: {},
            sources: {},
            layers: []
        };
        if (this.glyphs)
            style.glyphs = this.glyphs;
        if (this.sprite)
            style.sprite = this.sprite;
        Array.from(this.el.querySelectorAll('gl-style')).forEach((styleEl) => {
            if (!styleEl.enabled)
                return;
            let id = styleEl.id;
            let json = styleEl.json;
            if (!json)
                return;
            style.layers = this.getStyleLayers(id, json).concat(style.layers);
            style.sources = Object.assign({}, style.sources, this.getStyleSources(id, json));
            if (json.glyphs && !style.glyphs)
                style.glyphs = json.glyphs;
            if (json.sprite && !style.sprite)
                style.sprite = json.sprite;
        });
        if (style.glyphs)
            style.glyphs = getAbsoluteUrl(style.glyphs)
                .replace('%7Bfontstack%7D', '{fontstack}')
                .replace('%7Brange%7D', '{range}');
        if (style.sprite)
            style.sprite = getAbsoluteUrl(style.sprite);
        return style;
    }
    prefix(styleId, value) {
        return `${styleId}:${value}`;
    }
    static get is() { return "gl-map"; }
    static get properties() { return {
        "draw": {
            "type": "Any",
            "attr": "draw",
            "mutable": true
        },
        "drawing": {
            "type": Boolean,
            "attr": "drawing",
            "watchCallbacks": ["updateDrawing"]
        },
        "drawOptions": {
            "type": "Any",
            "attr": "draw-options"
        },
        "el": {
            "elementRef": true
        },
        "glyphs": {
            "type": String,
            "attr": "glyphs"
        },
        "id": {
            "type": String,
            "attr": "id"
        },
        "latitude": {
            "type": Number,
            "attr": "latitude"
        },
        "longitude": {
            "type": Number,
            "attr": "longitude"
        },
        "map": {
            "type": "Any",
            "attr": "map",
            "mutable": true
        },
        "maxzoom": {
            "type": Number,
            "attr": "maxzoom"
        },
        "minzoom": {
            "type": Number,
            "attr": "minzoom"
        },
        "resizeMap": {
            "method": true
        },
        "sprite": {
            "type": String,
            "attr": "sprite"
        },
        "zoom": {
            "type": Number,
            "attr": "zoom"
        }
    }; }
    static get events() { return [{
            "name": "glDrawCreate",
            "method": "glDrawCreate",
            "bubbles": true,
            "cancelable": true,
            "composed": true
        }, {
            "name": "glDrawDelete",
            "method": "glDrawDelete",
            "bubbles": true,
            "cancelable": true,
            "composed": true
        }, {
            "name": "glDrawEnter",
            "method": "glDrawEnter",
            "bubbles": true,
            "cancelable": true,
            "composed": true
        }, {
            "name": "glDrawExit",
            "method": "glDrawExit",
            "bubbles": true,
            "cancelable": true,
            "composed": true
        }, {
            "name": "glStyleUpdated",
            "method": "glStyleUpdated",
            "bubbles": true,
            "cancelable": true,
            "composed": true
        }]; }
    static get listeners() { return [{
            "name": "glStyleElementAdded",
            "method": "handleStyleAdded"
        }, {
            "name": "glStyleElementModified",
            "method": "handleStyleModified"
        }, {
            "name": "glStyleElementRemoved",
            "method": "handleStyleRemoved"
        }]; }
    static get style() { return "/**style-placeholder:gl-map:**/"; }
}
