/**
 * Use this class to ensure Google Maps API javascript is loaded before running any google map specific code.
 */
export class GoogleMapsApi {

	/**
	 * Constructor set up config.
	 */
	constructor(apiKey) {
		// api key for google maps
		this.apiKey = apiKey;
	}

	/**
	 * Load the Google Maps API javascript
	 */
	load() {
		const promise = new Promise((resolve) => {
			this.resolve = resolve;

			// set a globally scoped callback if it doesn't already exist
			if (typeof (window.humanForward) === 'undefined') {
				window.humanForward = {};
			}
			if (!window.humanForward.GoogleMapsApi) {
				this.callbackName = 'humanForward.GoogleMapsApi.mapReady';
				window.humanForward.GoogleMapsApi = this;
				window.humanForward.GoogleMapsApi.mapReady = this.mapReady.bind(this);
			}

			if ((typeof window.google === 'undefined'
				|| typeof window.google.maps === 'undefined')
				&& typeof this.callbackName !== 'undefined') {
				this.loaded = true;
				const script = document.createElement('script');
				script.src = `//maps.googleapis.com/maps/api/js?key=${this.apiKey}&callback=${this.callbackName}`;
				script.async = true;
				document.body.appendChild(script);
			} else {
				this.resolve();
			}
		});
		return promise;
	}

	/**
	 * Globally scoped callback for the map loaded
	 */
	mapReady() {
		this.extendApi();
		// resolves promise in load
		this.resolve();
	}

	extendApi() {
		google.maps.Map.prototype.panToWithOffset = function (latlng, offsetX, offsetY) {
			const map = this;
			const overlayView = new google.maps.OverlayView();
			overlayView.onAdd = function () {
				const proj = this.getProjection();
				const aPoint = proj.fromLatLngToContainerPixel(latlng);
				aPoint.x = aPoint.x + offsetX;
				aPoint.y = aPoint.y + offsetY;
				map.panTo(proj.fromContainerPixelToLatLng(aPoint));
			};
			overlayView.draw = function () { };
			overlayView.setMap(this);
		};
	}
}
