"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MgInnerLayerSetFactory = exports.MgLayerSetOL = exports.MgLayerSetMode = exports.mockMapGuideImageLoadFunction = exports.blankImageLoadFunction = exports.toProjUnit = void 0;
var tslib_1 = require("tslib");
var common_1 = require("./common");
var Group_1 = tslib_1.__importDefault(require("ol/layer/Group"));
var TileGrid_1 = tslib_1.__importDefault(require("ol/tilegrid/TileGrid"));
var tilegrid_1 = require("ol/tilegrid");
var TileImage_1 = tslib_1.__importDefault(require("ol/source/TileImage"));
var XYZ_1 = tslib_1.__importDefault(require("ol/source/XYZ"));
var ol_mapguide_source_factory_1 = require("./ol-mapguide-source-factory");
var ImageStatic_1 = tslib_1.__importDefault(require("ol/source/ImageStatic"));
var number_1 = require("../utils/number");
var View_1 = tslib_1.__importDefault(require("ol/View"));
var olExtent = tslib_1.__importStar(require("ol/extent"));
var Tile_1 = tslib_1.__importDefault(require("ol/layer/Tile"));
var Image_1 = tslib_1.__importDefault(require("ol/layer/Image"));
var external_layer_factory_1 = require("../components/external-layer-factory");
var string_1 = require("../utils/string");
var url_1 = require("../utils/url");
var i18n_1 = require("./i18n");
var olHas = tslib_1.__importStar(require("ol/has"));
var logger_1 = require("../utils/logger");
var UrlTile_1 = tslib_1.__importDefault(require("ol/source/UrlTile"));
var constants_1 = require("../constants");
var generic_layer_set_1 = require("./generic-layer-set");
var proj_1 = require("ol/proj");
var type_guards_1 = require("../utils/type-guards");
var error_1 = require("./error");
var units_1 = require("../utils/units");
var DEFAULT_BOUNDS_3857 = [
    -20026376.39,
    -20048966.10,
    20026376.39,
    20048966.10
];
var DEFAULT_BOUNDS_4326 = [-180, -90, 180, 90];
function getMetersPerUnit(projection) {
    var proj = (0, proj_1.get)(projection);
    return proj === null || proj === void 0 ? void 0 : proj.getMetersPerUnit();
}
function toMetersPerUnit(unit) {
    var u = toProjUnit(unit);
    // Use OL-provided mpu if available
    var mpu = proj_1.METERS_PER_UNIT[u];
    if (mpu) {
        return mpu;
    }
    else {
        // Otherwise, compute ourselves
        switch (unit) {
            case common_1.UnitOfMeasure.Centimeters:
                return 0.01;
            case common_1.UnitOfMeasure.DMS:
            case common_1.UnitOfMeasure.DecimalDegrees:
            case common_1.UnitOfMeasure.Degrees:
                return (2 * Math.PI * 6370997) / 360;
            case common_1.UnitOfMeasure.Feet:
                return 0.3048;
            case common_1.UnitOfMeasure.Inches:
                return 0.0254;
            case common_1.UnitOfMeasure.Kilometers:
                return 1000;
            case common_1.UnitOfMeasure.Meters:
                return 1;
            case common_1.UnitOfMeasure.Miles:
                return 1609.344;
            case common_1.UnitOfMeasure.Millimeters:
                return 0.001;
            case common_1.UnitOfMeasure.NauticalMiles:
                return 1852;
            case common_1.UnitOfMeasure.Pixels:
                return 1;
            case common_1.UnitOfMeasure.Unknown:
                return 1;
            case common_1.UnitOfMeasure.Yards:
                return 0.9144;
        }
    }
}
function toProjUnit(unit) {
    switch (unit) {
        case common_1.UnitOfMeasure.Meters:
            return "m";
        case common_1.UnitOfMeasure.Feet:
            return "ft";
        case common_1.UnitOfMeasure.Inches:
            return "in";
        case common_1.UnitOfMeasure.Centimeters:
            return "cm";
        case common_1.UnitOfMeasure.Kilometers:
            return "km";
        case common_1.UnitOfMeasure.Yards:
            return "yd";
        case common_1.UnitOfMeasure.Millimeters:
            return "mm";
        case common_1.UnitOfMeasure.Miles:
            return "mi";
        case common_1.UnitOfMeasure.NauticalMiles:
            return "nm";
        case common_1.UnitOfMeasure.Pixels:
            return "px";
        default:
            throw new error_1.MgError("Unsupported unit");
    }
}
exports.toProjUnit = toProjUnit;
function blankImageLoadFunction(image) {
    image.getImage().src = constants_1.BLANK_GIF_DATA_URI;
}
exports.blankImageLoadFunction = blankImageLoadFunction;
function mockMapGuideImageLoadFunction(image, src) {
    var el = document.getElementById("mg-debug-text-canvas");
    if (!el) {
        el = document.createElement("canvas");
        el.style.visibility = "hidden";
        el.id = "mg-debug-text-canvas";
        document.body.append(el);
    }
    var tCtx = el.getContext("2d");
    if (tCtx) {
        tCtx.clearRect(0, 0, tCtx.canvas.width, tCtx.canvas.height);
        var strings = [];
        var parsed = (0, url_1.parseUrl)(src);
        strings.push("[Mock MapGuide Map Image Request]");
        strings.push("Agent: ".concat(parsed.url));
        var xoff = 10;
        var yoff = 30;
        var fontSize = 14;
        var mm = tCtx.measureText(strings[0]);
        var maxSize = mm.width + xoff;
        var ch = yoff + fontSize + 2;
        maxSize = Math.max(tCtx.measureText(strings[1]).width + xoff, maxSize);
        ch += (fontSize + 2);
        var keys = Object.keys(parsed.query);
        for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
            var k = keys_1[_i];
            if (k == "MAPNAME" || k == "SETDISPLAYWIDTH" || k == "SETDISPLAYHEIGHT" || k == "SETVIEWCENTERX" || k == "SETVIEWCENTERY" || k == "SETVIEWSCALE") {
                if (!(0, string_1.strIsNullOrEmpty)(parsed.query[k])) {
                    var s = "".concat(k, ": ").concat(parsed.query[k]);
                    strings.push(s);
                    maxSize = Math.max(tCtx.measureText(s).width + xoff, maxSize);
                    ch += (fontSize + 2);
                }
            }
        }
        tCtx.canvas.width = maxSize;
        tCtx.canvas.height = ch;
        tCtx.fillStyle = "rgba(255, 0, 0, 0.5)";
        tCtx.fillRect(0, 0, maxSize, ch);
        tCtx.fillStyle = "rgba(255, 255, 0, 1.0)";
        //console.log(`Canvas size: [${tCtx.canvas.width}, ${tCtx.canvas.height}]`);
        tCtx.font = "".concat(fontSize, "px sans-serif");
        var y = yoff;
        for (var _a = 0, strings_1 = strings; _a < strings_1.length; _a++) {
            var str = strings_1[_a];
            //console.log(`Draw (${str}) at [10, ${y}]`);
            tCtx.fillText(str, 10, y);
            y += (fontSize + 1);
        }
        image.getImage().src = tCtx.canvas.toDataURL();
    }
}
exports.mockMapGuideImageLoadFunction = mockMapGuideImageLoadFunction;
var MgLayerSetMode;
(function (MgLayerSetMode) {
    MgLayerSetMode[MgLayerSetMode["Stateless"] = 0] = "Stateless";
    MgLayerSetMode[MgLayerSetMode["Stateful"] = 1] = "Stateful";
    MgLayerSetMode[MgLayerSetMode["OverviewMap"] = 2] = "OverviewMap";
})(MgLayerSetMode = exports.MgLayerSetMode || (exports.MgLayerSetMode = {}));
/**
 * @hidden
 */
var MgLayerSetOL = /** @class */ (function () {
    function MgLayerSetOL(mgTiledLayers, externalBaseLayersGroup, overlay, projection, dpi, extent, inPerUnit, view) {
        this.mgTiledLayers = mgTiledLayers;
        this.externalBaseLayersGroup = externalBaseLayersGroup;
        this.overlay = overlay;
        this.projection = projection;
        this.dpi = dpi;
        this.extent = extent;
        this.inPerUnit = inPerUnit;
        this.view = view;
    }
    MgLayerSetOL.prototype.getMetersPerUnit = function () {
        return this.inPerUnit / 39.37;
    };
    MgLayerSetOL.prototype.scaleToResolution = function (scale) {
        return (scale / this.inPerUnit / this.dpi) * olHas.DEVICE_PIXEL_RATIO;
    };
    MgLayerSetOL.prototype.resolutionToScale = function (resolution) {
        return (resolution * this.dpi * this.inPerUnit) / olHas.DEVICE_PIXEL_RATIO;
    };
    MgLayerSetOL.prototype.getSourcesForProgressTracking = function () {
        var sources = [];
        if (this.externalBaseLayersGroup) {
            var bls = this.externalBaseLayersGroup.getLayersArray();
            for (var _i = 0, bls_1 = bls; _i < bls_1.length; _i++) {
                var bl = bls_1[_i];
                if (bl instanceof Image_1.default || bl instanceof Tile_1.default) {
                    sources.push(bl.getSource());
                }
            }
        }
        for (var i = this.mgTiledLayers.length - 1; i >= 0; i--) {
            var s = this.mgTiledLayers[i].getSource();
            if (s) {
                sources.push();
            }
        }
        var ovs = this.overlay.getSource();
        if (ovs) {
            sources.push(ovs);
        }
        if (this.selectionOverlay) {
            var sovs = this.selectionOverlay.getSource();
            if (sovs) {
                sources.push(sovs);
            }
        }
        if (this.activeSelectedFeatureOverlay) {
            var asovs = this.activeSelectedFeatureOverlay.getSource();
            if (asovs) {
                sources.push(asovs);
            }
        }
        return sources;
    };
    MgLayerSetOL.prototype.getLayers = function () {
        var layers = [];
        if (this.externalBaseLayersGroup) {
            layers.push(this.externalBaseLayersGroup);
        }
        for (var i = this.mgTiledLayers.length - 1; i >= 0; i--) {
            layers.push(this.mgTiledLayers[i]);
        }
        layers.push(this.overlay);
        if (this.selectionOverlay) {
            layers.push(this.selectionOverlay);
        }
        if (this.activeSelectedFeatureOverlay) {
            layers.push(this.activeSelectedFeatureOverlay);
        }
        return layers;
    };
    MgLayerSetOL.prototype.update = function (showGroups, showLayers, hideGroups, hideLayers) {
        //Send the request
        var imgSource = this.overlay.getSource(); //olMapGuideSource;
        //NOTE: Even if these group ids being shown/hidden are MG base layer groups, it still has to be
        //done as the server-side snapshot of the runtime map needs to be aware as well. This will be
        //apparent if you were to plot a runtime-map server-side that has base layer groups.
        imgSource.updateParams({
            showlayers: showLayers,
            showgroups: showGroups,
            hidelayers: hideLayers,
            hidegroups: hideGroups
        });
        //As MG base layer groups are separate ol layer instances, we have to toggle them on the client-side as well
        if (showGroups && showGroups.length > 0) {
            var _loop_1 = function (groupId) {
                var match = this_1.mgTiledLayers.filter(function (l) { return l.get(common_1.LayerProperty.LAYER_NAME) === groupId; });
                if (match.length == 1) {
                    match[0].setVisible(true);
                }
            };
            var this_1 = this;
            for (var _i = 0, showGroups_1 = showGroups; _i < showGroups_1.length; _i++) {
                var groupId = showGroups_1[_i];
                _loop_1(groupId);
            }
        }
        if (hideGroups && hideGroups.length > 0) {
            var _loop_2 = function (groupId) {
                var match = this_2.mgTiledLayers.filter(function (l) { return l.get(common_1.LayerProperty.LAYER_NAME) === groupId; });
                if (match.length == 1) {
                    match[0].setVisible(false);
                }
            };
            var this_2 = this;
            for (var _a = 0, hideGroups_1 = hideGroups; _a < hideGroups_1.length; _a++) {
                var groupId = hideGroups_1[_a];
                _loop_2(groupId);
            }
        }
    };
    MgLayerSetOL.prototype.updateSelectionColor = function (color) {
        if (this.selectionOverlay) {
            var source = this.selectionOverlay.getSource(); // olMapGuideSource;
            source.updateParams({
                SELECTIONCOLOR: color
            });
        }
    };
    MgLayerSetOL.prototype.updateExternalBaseLayers = function (externalBaseLayers) {
        if (this.externalBaseLayersGroup) {
            var layers = this.externalBaseLayersGroup.getLayers();
            layers.forEach(function (l) {
                var match = (externalBaseLayers || []).filter(function (el) { return el.name === l.get("title"); });
                if (match.length == 1) {
                    l.setVisible(!!match[0].visible);
                }
                else {
                    l.setVisible(false);
                }
            });
        }
    };
    MgLayerSetOL.prototype.updateTransparency = function (trans) {
        //If no external layers defined, this won't be set
        if (this.externalBaseLayersGroup) {
            if (constants_1.LAYER_ID_BASE in trans) {
                this.externalBaseLayersGroup.setOpacity((0, number_1.restrictToRange)(trans[constants_1.LAYER_ID_BASE], 0, 1.0));
            }
            else {
                this.externalBaseLayersGroup.setOpacity(1.0);
            }
        }
        if (constants_1.LAYER_ID_MG_DYNAMIC_OVERLAY in trans) {
            var opacity = (0, number_1.restrictToRange)(trans[constants_1.LAYER_ID_MG_DYNAMIC_OVERLAY], 0, 1.0);
            this.overlay.setOpacity(opacity);
        }
        else {
            this.overlay.setOpacity(1.0);
        }
        if (constants_1.LAYER_ID_MG_BASE in trans) {
            var opacity = (0, number_1.restrictToRange)(trans[constants_1.LAYER_ID_MG_BASE], 0, 1.0);
            for (var _i = 0, _a = this.mgTiledLayers; _i < _a.length; _i++) {
                var group = _a[_i];
                group.setOpacity(opacity);
            }
        }
        else {
            for (var _b = 0, _c = this.mgTiledLayers; _b < _c.length; _b++) {
                var group = _c[_b];
                group.setOpacity(1.0);
            }
        }
        if (this.selectionOverlay) {
            if (constants_1.LAYER_ID_MG_SEL_OVERLAY in trans) {
                this.selectionOverlay.setOpacity((0, number_1.restrictToRange)(trans[constants_1.LAYER_ID_MG_SEL_OVERLAY], 0, 1.0));
            }
            else {
                this.selectionOverlay.setOpacity(1.0);
            }
        }
    };
    MgLayerSetOL.prototype.refreshMap = function (mode) {
        if (mode === void 0) { mode = common_1.RefreshMode.LayersOnly | common_1.RefreshMode.SelectionOnly; }
        if ((mode & common_1.RefreshMode.LayersOnly) == common_1.RefreshMode.LayersOnly) {
            var imgSource = this.overlay.getSource(); // olMapGuideSource;
            imgSource.updateParams({
                seq: (new Date()).getTime()
            });
        }
        if (this.selectionOverlay) {
            if ((mode & common_1.RefreshMode.SelectionOnly) == common_1.RefreshMode.SelectionOnly) {
                var imgSource = this.selectionOverlay.getSource(); // olMapGuideSource;
                imgSource.updateParams({
                    seq: (new Date()).getTime()
                });
            }
        }
    };
    MgLayerSetOL.prototype.makeActiveSelectedFeatureSource = function (mapExtent, size, url) {
        if (url === void 0) { url = constants_1.BLANK_GIF_DATA_URI; }
        return new ImageStatic_1.default({
            imageExtent: mapExtent,
            imageSize: [size.w, size.h],
            url: url
        });
    };
    MgLayerSetOL.prototype.showActiveSelectedFeature = function (mapExtent, size, uri) {
        if (this.activeSelectedFeatureOverlay) {
            this.activeSelectedFeatureOverlay.setSource(this.makeActiveSelectedFeatureSource(mapExtent, size, uri));
            this.activeSelectedFeatureOverlay.setVisible(true);
        }
    };
    return MgLayerSetOL;
}());
exports.MgLayerSetOL = MgLayerSetOL;
var MgInnerLayerSetFactory = /** @class */ (function () {
    function MgInnerLayerSetFactory(callback, map, agentUri, imageFormat, selectionImageFormat, selectionColor) {
        this.callback = callback;
        this.map = map;
        this.agentUri = agentUri;
        if ((0, type_guards_1.isRuntimeMap)(map)) {
            this.dynamicOverlayParams = {
                MAPNAME: map.Name,
                FORMAT: imageFormat,
                SESSION: map.SessionId,
                BEHAVIOR: 2
            };
            this.staticOverlayParams = {
                MAPDEFINITION: map.MapDefinition,
                FORMAT: imageFormat,
                CLIENTAGENT: "ol.source.ImageMapGuide for OverviewMap",
                USERNAME: "Anonymous",
                VERSION: "3.0.0"
            };
            this.selectionOverlayParams = {
                MAPNAME: map.Name,
                FORMAT: selectionImageFormat || "PNG8",
                SESSION: map.SessionId,
                SELECTIONCOLOR: selectionColor,
                BEHAVIOR: 1 | 4 //selected features + include outside current scale
            };
        }
    }
    MgInnerLayerSetFactory.prototype.getTileUrlFunctionForGroup = function (resourceId, groupName, zOrigin) {
        var urlTemplate = this.callback.getClient().getTileTemplateUrl(resourceId, groupName, '{x}', '{y}', '{z}', false);
        return function (tileCoord) {
            var z = tileCoord[0];
            var x = tileCoord[1];
            var y = tileCoord[2]; //NOTE: tileCoord format changed in OL 6.0, no longer need to negate and subtract by 1
            return urlTemplate
                .replace('{z}', (zOrigin - z).toString())
                .replace('{x}', x.toString())
                .replace('{y}', (y).toString());
        };
    };
    MgInnerLayerSetFactory.prototype.create = function (locale, externalBaseLayers, mode, appSettings) {
        var _this = this;
        var _a;
        var _b = this, map = _b.map, agentUri = _b.agentUri;
        if ((0, type_guards_1.isRuntimeMap)(map)) {
            if ((0, string_1.strIsNullOrEmpty)(agentUri)) {
                throw new error_1.MgError("Expected agentUri to be set");
            }
            //If a tile set definition is defined it takes precedence over the map definition, this enables
            //this example to work with older releases of MapGuide where no such resource type exists.
            var resourceId = map.TileSetDefinition || map.MapDefinition;
            //On MGOS 2.6 or older, tile width/height is never returned, so default to 300x300
            var tileWidth = map.TileWidth || 300;
            var tileHeight = map.TileHeight || 300;
            var metersPerUnit = map.CoordinateSystem.MetersPerUnit;
            var finiteScales = [];
            if (map.FiniteDisplayScale) {
                for (var i = map.FiniteDisplayScale.length - 1; i >= 0; i--) {
                    finiteScales.push(map.FiniteDisplayScale[i]);
                }
            }
            var extent = [
                map.Extents.LowerLeftCoordinate.X,
                map.Extents.LowerLeftCoordinate.Y,
                map.Extents.UpperRightCoordinate.X,
                map.Extents.UpperRightCoordinate.Y
            ];
            var dpi = map.DisplayDpi;
            var inPerUnit = 39.37 * map.CoordinateSystem.MetersPerUnit;
            var resolutions = new Array(finiteScales.length);
            var projection = void 0;
            for (var i = 0; i < finiteScales.length; ++i) {
                resolutions[i] = finiteScales[i] / inPerUnit / dpi;
            }
            var parsedArb = (0, units_1.tryParseArbitraryCs)(map.CoordinateSystem.MentorCode);
            if (parsedArb) {
                projection = new proj_1.Projection({
                    code: parsedArb.code,
                    units: toProjUnit(parsedArb.units),
                    metersPerUnit: toMetersPerUnit(parsedArb.units)
                });
            }
            else {
                if (map.CoordinateSystem.EpsgCode.length > 0) {
                    projection = "EPSG:".concat(map.CoordinateSystem.EpsgCode);
                }
            }
            var zOrigin = finiteScales.length - 1;
            var mgTiledLayers = [];
            //const groupLayers = [] as TileLayer[];
            if (map.Group) {
                for (var i = 0; i < map.Group.length; i++) {
                    var group = map.Group[i];
                    if (group.Type != 2 && group.Type != 3) { //BaseMap or LinkedTileSet
                        continue;
                    }
                    var tileLayer = void 0;
                    if (group.Type === 3 && map.TileSetProvider === "XYZ") {
                        var retinaScale = 1;
                        if (typeof (map.TilePixelRatio) != 'undefined') {
                            retinaScale = map.TilePixelRatio;
                        }
                        var tileSource = new XYZ_1.default({
                            tileSize: [256 * retinaScale, 256 * retinaScale],
                            tileGrid: (0, tilegrid_1.createXYZ)({ tileSize: [256, 256] }),
                            projection: projection,
                            // TODO: Should use tileUrlFunction for consistency with MG tiled layers below and to also faciliate 
                            // something like client-side tile caching in the future
                            url: this.callback.getClient().getTileTemplateUrl(resourceId, group.Name, '{x}', '{y}', '{z}', true),
                            wrapX: false
                        });
                        tileLayer = new Tile_1.default({
                            //name: group.Name,
                            source: tileSource
                        });
                    }
                    else {
                        var tileGrid = new TileGrid_1.default({
                            origin: olExtent.getTopLeft(extent),
                            resolutions: resolutions,
                            tileSize: [tileWidth, tileHeight]
                        });
                        var tileSource = new TileImage_1.default({
                            tileGrid: tileGrid,
                            projection: projection,
                            tileUrlFunction: this.getTileUrlFunctionForGroup(resourceId, group.Name, zOrigin),
                            wrapX: false
                        });
                        tileLayer = new Tile_1.default({
                            //name: group.Name,
                            source: tileSource
                        });
                    }
                    tileLayer.set(common_1.LayerProperty.LAYER_NAME, group.ObjectId);
                    tileLayer.set(common_1.LayerProperty.LAYER_DISPLAY_NAME, group.ObjectId);
                    tileLayer.set(common_1.LayerProperty.LAYER_TYPE, common_1.MgLayerType.Tiled);
                    tileLayer.set(common_1.LayerProperty.IS_EXTERNAL, false);
                    tileLayer.set(common_1.LayerProperty.IS_GROUP, false);
                    tileLayer.setVisible(group.Visible);
                    //groupLayers.push(tileLayer);
                    mgTiledLayers.push(tileLayer);
                }
            }
            /*
            if (groupLayers.length > 0) {
                groupLayers.push(
                    new ol.layer.Tile({
                        source: new ol.source.TileDebug({
                            tileGrid: tileGrid,
                            projection: projection,
                            tileUrlFunction: function(tileCoord) {
                                const z = tileCoord[0];
                                const x = tileCoord[1];
                                const y = tileCoord[2]; //NOTE: tileCoord format changed in OL 6.0, no longer need to negate and subtract by 1
                                return urlTemplate
                                    .replace('{z}', (zOrigin - z).toString())
                                    .replace('{x}', x.toString())
                                    .replace('{y}', (y).toString());
                            },
                            wrapX: false
                        })
                    })
                );
            }
            */
            var overlay = this.createMgOverlayLayer(common_1.MgBuiltInLayers.Overlay, agentUri, locale, metersPerUnit, projection, mode == MgLayerSetMode.Stateful, mode == MgLayerSetMode.Stateful ? this.dynamicOverlayParams : this.staticOverlayParams);
            var selectionOverlay = void 0;
            var activeSelectedFeatureOverlay = void 0;
            if (mode == MgLayerSetMode.Stateful) {
                selectionOverlay = this.createMgOverlayLayer(common_1.MgBuiltInLayers.SelectionOverlay, agentUri, locale, metersPerUnit, projection, true, this.selectionOverlayParams);
            }
            if (mode == MgLayerSetMode.Stateful) {
                //NOTE: Not tracking this source atm
                activeSelectedFeatureOverlay = new Image_1.default({
                    //OL6: need to specify a source up-front otherwise it will error blindly
                    //trying to get a source out of this URL, so set up a source with an empty
                    //image data URI, it will be updated if we receive a request to show an
                    //active selected feature image
                    source: new ImageStatic_1.default({
                        imageExtent: extent,
                        imageSize: [common_1.BLANK_SIZE.w, common_1.BLANK_SIZE.h],
                        url: constants_1.BLANK_GIF_DATA_URI
                    })
                });
                activeSelectedFeatureOverlay.set(common_1.LayerProperty.LAYER_NAME, common_1.MgBuiltInLayers.ActiveFeatureSelectionOverlay);
                activeSelectedFeatureOverlay.set(common_1.LayerProperty.LAYER_DISPLAY_NAME, common_1.MgBuiltInLayers.ActiveFeatureSelectionOverlay);
                activeSelectedFeatureOverlay.set(common_1.LayerProperty.LAYER_TYPE, common_1.MG_LAYER_TYPE_NAME);
                activeSelectedFeatureOverlay.set(common_1.LayerProperty.IS_EXTERNAL, false);
                activeSelectedFeatureOverlay.set(common_1.LayerProperty.IS_GROUP, false);
            }
            var externalBaseLayersGroup = void 0;
            //NOTE: Don't bother adding external base layers for overview map as the main map in the
            //overview is rendered with GETMAPIMAGE and not GETDYNAMICMAPOVERLAYIMAGE meaning the background
            //is opaque and you won't be able to see the base layers underneath anyways.
            if (mode != MgLayerSetMode.OverviewMap && externalBaseLayers != null) {
                var groupOpts = {
                    title: (0, i18n_1.tr)("EXTERNAL_BASE_LAYERS", locale),
                    layers: externalBaseLayers.map(function (ext) {
                        var tl = _this.createExternalBaseLayer(ext);
                        return tl;
                    })
                };
                externalBaseLayersGroup = new Group_1.default(groupOpts);
                externalBaseLayersGroup.set(common_1.LayerProperty.LAYER_NAME, common_1.MG_BASE_LAYER_GROUP_NAME);
                externalBaseLayersGroup.set(common_1.LayerProperty.LAYER_DISPLAY_NAME, common_1.MG_BASE_LAYER_GROUP_NAME);
                externalBaseLayersGroup.set(common_1.LayerProperty.IS_EXTERNAL, false);
                externalBaseLayersGroup.set(common_1.LayerProperty.IS_GROUP, true);
            }
            (0, logger_1.debug)("Creating OL view with projection ".concat(projection, " and ").concat(resolutions.length, " resolutions"));
            var view = void 0;
            if (resolutions.length == 0) {
                view = new View_1.default({
                    projection: projection
                });
            }
            else {
                view = new View_1.default({
                    projection: projection,
                    resolutions: resolutions
                });
            }
            var layerSet = new MgLayerSetOL(mgTiledLayers, externalBaseLayersGroup, overlay, projection, dpi, extent, inPerUnit, view);
            layerSet.selectionOverlay = selectionOverlay;
            layerSet.activeSelectedFeatureOverlay = activeSelectedFeatureOverlay;
            return layerSet;
        }
        else {
            var projection = (_a = map === null || map === void 0 ? void 0 : map.meta) === null || _a === void 0 ? void 0 : _a.projection;
            var bounds = void 0;
            var externalBaseLayersGroup = void 0;
            if (externalBaseLayers != null) {
                var groupOpts = {
                    title: (0, i18n_1.tr)("EXTERNAL_BASE_LAYERS", locale),
                    layers: externalBaseLayers.map(function (ext) {
                        var tl = _this.createExternalBaseLayer(ext);
                        return tl;
                    })
                };
                externalBaseLayersGroup = new Group_1.default(groupOpts);
                externalBaseLayersGroup.set(common_1.LayerProperty.LAYER_NAME, common_1.MG_BASE_LAYER_GROUP_NAME);
                externalBaseLayersGroup.set(common_1.LayerProperty.IS_EXTERNAL, false);
                externalBaseLayersGroup.set(common_1.LayerProperty.IS_GROUP, true);
                //projection = "EPSG:3857";
                //bounds = DEFAULT_BOUNDS_3857;
            }
            var subjectLayer = void 0;
            if (map) {
                subjectLayer = (0, external_layer_factory_1.createOLLayerFromSubjectDefn)(map, projection, false, appSettings);
                if (map.meta) {
                    projection = map.meta.projection;
                    bounds = map.meta.extents;
                }
            }
            if (!projection && !bounds) {
                projection = "EPSG:4326";
                bounds = DEFAULT_BOUNDS_4326;
            }
            var parsedArb = (0, units_1.tryParseArbitraryCs)(projection);
            var metersPerUnit = 1;
            if (parsedArb) {
                projection = new proj_1.Projection({
                    code: parsedArb.code,
                    units: toProjUnit(parsedArb.units),
                    metersPerUnit: toMetersPerUnit(parsedArb.units),
                    extent: bounds
                });
            }
            else {
                metersPerUnit = getMetersPerUnit(projection);
            }
            var view = new View_1.default({
                projection: projection
            });
            return new generic_layer_set_1.GenericLayerSetOL(view, subjectLayer, bounds, externalBaseLayersGroup, projection, metersPerUnit);
        }
    };
    MgInnerLayerSetFactory.prototype.createExternalBaseLayer = function (ext) {
        var extSource = (0, external_layer_factory_1.createExternalSource)(ext);
        if (extSource instanceof UrlTile_1.default) {
            var loaders = this.callback.getBaseTileLoaders();
            if (loaders[ext.name])
                extSource.setTileLoadFunction(loaders[ext.name]);
        }
        var options = {
            title: ext.name,
            type: "base",
            visible: ext.visible === true,
            source: extSource
        };
        var tl = new Tile_1.default(options);
        tl.set(common_1.LayerProperty.LAYER_TYPE, ext.kind);
        tl.set(common_1.LayerProperty.LAYER_NAME, ext.name);
        tl.set(common_1.LayerProperty.LAYER_DISPLAY_NAME, ext.name);
        tl.set(common_1.LayerProperty.IS_EXTERNAL, false);
        tl.set(common_1.LayerProperty.IS_GROUP, false);
        return tl;
    };
    MgInnerLayerSetFactory.prototype.createMgOverlayLayer = function (layerName, agentUri, locale, metersPerUnit, projection, useImageOverlayOp, params) {
        var overlaySource = (0, ol_mapguide_source_factory_1.createMapGuideSource)({
            projection: projection,
            url: agentUri,
            useOverlay: useImageOverlayOp,
            metersPerUnit: metersPerUnit,
            params: params,
            ratio: 1,
            // For mobile devices with retina/hidpi displays, the default 96 DPI produces
            // really low quality map images. For such devices, the DPI should be some
            // function of the device pixel ratio reported. As this value can be fractional
            // round it down to the nearest integer
            //
            // UPDATE 18/07/2023: But cap it to a minimum of 1, otherwise a sub-1 ratio floors to 0, making the
            // final DPI 0, which breaks everything
            displayDpi: Math.max(Math.floor(olHas.DEVICE_PIXEL_RATIO), 1) * 96
        });
        overlaySource.setAttributions((0, i18n_1.tr)("PBMG", locale !== null && locale !== void 0 ? locale : i18n_1.DEFAULT_LOCALE));
        var layer = new Image_1.default({
            //name: "MapGuide Dynamic Overlay",
            source: overlaySource
        });
        layer.set(common_1.LayerProperty.LAYER_NAME, layerName);
        layer.set(common_1.LayerProperty.LAYER_DISPLAY_NAME, layerName);
        layer.set(common_1.LayerProperty.LAYER_TYPE, common_1.MG_LAYER_TYPE_NAME);
        layer.set(common_1.LayerProperty.IS_EXTERNAL, false);
        layer.set(common_1.LayerProperty.IS_GROUP, false);
        return layer;
    };
    return MgInnerLayerSetFactory;
}());
exports.MgInnerLayerSetFactory = MgInnerLayerSetFactory;
//# sourceMappingURL=layer-set.js.map