// import  'leaflet'

// 这段代码来自于 https://github.com/Leaflet/Leaflet.TileLayer.NoGap/blob/master/L.TileLayer.NoGap.js
// 如果没有这段，则显示的地图的瓦片之间有空白线
// let leaflet = require('leaflet/src/Leaflet')
// require('leaflet/src/Leaflet')
// @class TileLayer
(function () {

	L.TileLayer.mergeOptions({
		// @option keepBuffer
		// The amount of tiles outside the visible map area to be kept in the stitched
		// `TileLayer`.

		// @option dumpToCanvas: Boolean = true
		// Whether to dump loaded tiles to a `<canvas>` to prevent some rendering
		// artifacts. (Disabled by default in IE)
		dumpToCanvas: L.Browser.canvas && !L.Browser.ie,
	});

	L.TileLayer.include({
		_onUpdateLevel: function (z, zoom) {
			if (this.options.dumpToCanvas) {
				this._levels[z].canvas.style.zIndex =
					this.options.maxZoom - Math.abs(zoom - z);
			}
		},

		_onRemoveLevel: function (z) {
			if (this.options.dumpToCanvas) {
				L.DomUtil.remove(this._levels[z].canvas);
			}
		},

		_onCreateLevel: function (level) {
			if (this.options.dumpToCanvas) {
				level.canvas = L.DomUtil.create(
					"canvas",
					"leaflet-tile-container leaflet-zoom-animated",
					this._container
				);
				level.ctx = level.canvas.getContext("2d");
				this._resetCanvasSize(level);
			}
		},

		_removeTile: function (key) {
			if (this.options.dumpToCanvas) {
				var tile = this._tiles[key];
				var level = this._levels[tile.coords.z];
				var tileSize = this.getTileSize();

				if (level) {
					// Where in the canvas should this tile go?
					var offset = L.point(tile.coords.x, tile.coords.y)
						.subtract(level.canvasRange.min)
						.scaleBy(this.getTileSize());

					level.ctx.clearRect(offset.x, offset.y, tileSize.x, tileSize.y);
				}
			}

			L.GridLayer.prototype._removeTile.call(this, key);
		},

		_resetCanvasSize: function (level) {
			var buff = this.options.keepBuffer,
				pixelBounds = this._getTiledPixelBounds(this._map.getCenter()),
				tileRange = this._pxBoundsToTileRange(pixelBounds),
				tileSize = this.getTileSize();

			tileRange.min = tileRange.min.subtract([buff, buff]); // This adds the no-prune buffer
			tileRange.max = tileRange.max.add([buff + 1, buff + 1]);

			var pixelRange = L.bounds(
				tileRange.min.scaleBy(tileSize),
				tileRange.max.add([1, 1]).scaleBy(tileSize) // This prevents an off-by-one when checking if tiles are inside
			),
				mustRepositionCanvas = false,
				neededSize = pixelRange.max.subtract(pixelRange.min);

			// Resize the canvas, if needed, and only to make it bigger.
			if (
				neededSize.x > level.canvas.width ||
				neededSize.y > level.canvas.height
			) {
				// Resizing canvases erases the currently drawn content, I'm afraid.
				// To keep it, dump the pixels to another canvas, then display it on
				// top. This could be done with getImageData/putImageData, but that
				// would break for tainted canvases (in non-CORS tilesets)
				var oldSize = { x: level.canvas.width, y: level.canvas.height };
				// console.info('Resizing canvas from ', oldSize, 'to ', neededSize);

				var tmpCanvas = L.DomUtil.create("canvas");
				tmpCanvas.style.width = (tmpCanvas.width = oldSize.x) + "px";
				tmpCanvas.style.height = (tmpCanvas.height = oldSize.y) + "px";
				tmpCanvas.getContext("2d").drawImage(level.canvas, 0, 0);
				// var data = level.ctx.getImageData(0, 0, oldSize.x, oldSize.y);

				level.canvas.style.width = (level.canvas.width = neededSize.x) + "px";
				level.canvas.style.height = (level.canvas.height = neededSize.y) + "px";
				level.ctx.drawImage(tmpCanvas, 0, 0);
				// level.ctx.putImageData(data, 0, 0, 0, 0, oldSize.x, oldSize.y);
			}

			// Translate the canvas contents if it's moved around
			if (level.canvasRange) {
				var offset = level.canvasRange.min
					.subtract(tileRange.min)
					.scaleBy(this.getTileSize());

				// 			console.info('Offsetting by ', offset);

				if (!L.Browser.safari) {
					// By default, canvases copy things "on top of" existing pixels, but we want
					// this to *replace* the existing pixels when doing a drawImage() call.
					// This will also clear the sides, so no clearRect() calls are needed to make room
					// for the new tiles.
					level.ctx.globalCompositeOperation = "copy";
					level.ctx.drawImage(level.canvas, offset.x, offset.y);
					level.ctx.globalCompositeOperation = "source-over";
				} else {
					// Safari clears the canvas when copying from itself :-(
					if (!this._tmpCanvas) {
						var t = (this._tmpCanvas = L.DomUtil.create("canvas"));
						t.width = level.canvas.width;
						t.height = level.canvas.height;
						this._tmpContext = t.getContext("2d");
					}
					this._tmpContext.clearRect(
						0,
						0,
						level.canvas.width,
						level.canvas.height
					);
					this._tmpContext.drawImage(level.canvas, 0, 0);
					level.ctx.clearRect(0, 0, level.canvas.width, level.canvas.height);
					level.ctx.drawImage(this._tmpCanvas, offset.x, offset.y);
				}

				mustRepositionCanvas = true; // Wait until new props are set
			}

			level.canvasRange = tileRange;
			level.canvasPxRange = pixelRange;
			level.canvasOrigin = pixelRange.min;

			// console.log('Canvas tile range: ', level, tileRange.min, tileRange.max );
			// console.log('Canvas pixel range: ', pixelRange.min, pixelRange.max );
			// console.log('Level origin: ', level.origin );

			if (mustRepositionCanvas) {
				this._setCanvasZoomTransform(
					level,
					this._map.getCenter(),
					this._map.getZoom()
				);
			}
		},

		/// set transform/position of canvas, in addition to the transform/position of the individual tile container
		_setZoomTransform: function (level, center, zoom) {
			L.GridLayer.prototype._setZoomTransform.call(this, level, center, zoom);
			if (this.options.dumpToCanvas) {
				this._setCanvasZoomTransform(level, center, zoom);
			}
		},

		// This will get called twice:
		// * From _setZoomTransform
		// * When the canvas has shifted due to a new tile being loaded
		_setCanvasZoomTransform: function (level, center, zoom) {
			// console.log('_setCanvasZoomTransform', level, center, zoom);
			if (!level.canvasOrigin) {
				return;
			}
			var scale = this._map.getZoomScale(zoom, level.zoom),
				translate = level.canvasOrigin
					.multiplyBy(scale)
					.subtract(this._map._getNewPixelOrigin(center, zoom))
					.round();

			if (L.Browser.any3d) {
				L.DomUtil.setTransform(level.canvas, translate, scale);
			} else {
				L.DomUtil.setPosition(level.canvas, translate);
			}
		},

		_onOpaqueTile: function (tile) {
			if (!this.options.dumpToCanvas) {
				return;
			}

			// Guard against an NS_ERROR_NOT_AVAILABLE (or similar) exception
			// when a non-image-tile has been loaded (e.g. a WMS error).
			// Checking for tile.el.complete is not enough, as it has been
			// already marked as loaded and ready somehow.
			try {
				this.dumpPixels(tile.coords, tile.el);
			} catch (ex) {
				return this.fire("tileerror", {
					error: "Could not copy tile pixels: " + ex,
					tile: tile,
					coods: tile.coords,
				});
			}

			// If dumping the pixels was successful, then hide the tile.
			// Do not remove the tile itself, as it is needed to check if the whole
			// level (and its canvas) should be removed (via level.el.children.length)
			tile.el.style.display = "none";
		},

		// @section Extension methods
		// @uninheritable

		// @method dumpPixels(coords: Object, imageSource: CanvasImageSource): this
		// Dumps pixels from the given `CanvasImageSource` into the layer, into
		// the space for the tile represented by the `coords` tile coordinates (an object
		// like `{x: Number, y: Number, z: Number}`; the image source must have the
		// same size as the `tileSize` option for the layer. Has no effect if `dumpToCanvas`
		// is `false`.
		dumpPixels: function (coords, imageSource) {
			var level = this._levels[coords.z],
				tileSize = this.getTileSize();

			if (!level.canvasRange || !this.options.dumpToCanvas) {
				return;
			}

			// Check if the tile is inside the currently visible map bounds
			// There is a possible race condition when tiles are loaded after they
			// have been panned outside of the map.
			if (!level.canvasRange.contains(coords)) {
				this._resetCanvasSize(level);
			}

			// Where in the canvas should this tile go?
			var offset = L.point(coords.x, coords.y)
				.subtract(level.canvasRange.min)
				.scaleBy(this.getTileSize());

			level.ctx.drawImage(imageSource, offset.x, offset.y, tileSize.x, tileSize.y);

			// TODO: Clear the pixels of other levels' canvases where they overlap
			// this newly dumped tile.
			return this;
		},
	});

}
)()