<template>
  <div :style="{opacity: opacity}">
    <slot />
  </div>
</template>
<script>
  import * as VueGoogleMaps from "gmap-vue";
  export default {
    mixins: [VueGoogleMaps.MapElementMixin],
    props: {
      marker: {
        type: Object,
        default: undefined
      },
      offsetX: {
        type: Number,
        default: 0
      },
      offsetY: {
        type: Number,
        default: 0
      },
      alignment: {
        type: String,
        default: "top"
      },
      zIndex: {
        type: Number,
        default: 50
      },
      cssPosition: {
        type: Boolean,
        default: false
      },
      nuxtMode: {
        type: Boolean,
        default: false,
      },
    },
    inject: {
      $clusterPromise: {
        default: null
      }
    },
    beforeCreate (options) {
      if (this.$clusterPromise) {
        options.map = null;
      }

      return this.$clusterPromise;
    },
    methods: {
      afterCreate (inst) {
        if (this.$clusterPromise && !this.isMarkerAdded) {
          this.$clusterPromise.then(co => {
            co.addMarker(inst);
            this.$clusterObject = co;
            this.isMarkerAdded = true;
          });
        }
      }
    },
    data () {
      return {
        opacity: 0.01
      };
    },
    watch: {
      marker (val) {
        this.$mapPromise.then(map => this.$overlay.setPosition());
      },
      zIndex (val) {
        if (this.$overlay) {
          this.$overlay.repaint()
        }
      }
    },
    provide () {
      const self = this;
      return this.$mapPromise.then(map => {
        class Overlay extends google.maps.OverlayView {
          constructor(map) {
            super();
            this.setMap(map);
            this.draw = () => this.repaint();
            this.setPosition = () => this.repaint();
          }
          repaint () {
            const div = self.$el;
            if (self.nuxtMode && !div.offsetWidth && !div.offsetHeight) {
              return;
            }
            const projection = this.getProjection();
            if (projection && div) {
              const posPixel = projection.fromLatLngToDivPixel(self.latLng);
              let x, y;
              switch (self.alignment) {
                case "top":
                  x = posPixel.x - div.offsetWidth / 2;
                  y = posPixel.y - div.offsetHeight;
                  break;
                case "bottom":
                  x = posPixel.x - div.offsetWidth / 2;
                  y = posPixel.y;
                  break;
                case "left":
                  x = posPixel.x - div.offsetWidth;
                  y = posPixel.y - div.offsetHeight / 2;
                  break;
                case "right":
                  x = posPixel.x;
                  y = posPixel.y - div.offsetHeight / 2;
                  break;
                case "center":
                  x = posPixel.x - div.offsetWidth / 2;
                  y = posPixel.y - div.offsetHeight / 2;
                  break;
                case "topleft":
                case "lefttop":
                  x = posPixel.x - div.offsetWidth;
                  y = posPixel.y - div.offsetHeight;
                  break;
                case "topright":
                case "righttop":
                  x = posPixel.x;
                  y = posPixel.y - div.offsetHeight;
                  break;
                case "bottomleft":
                case "leftop":
                  x = posPixel.x - div.offsetWidth;
                  y = posPixel.y;
                  break;
                case "bottomright":
                case "rightbottom":
                  x = posPixel.x;
                  y = posPixel.y;
                  break;
                default:
                  throw new Error("Invalid alignment type of custom marker!");
                  break;
              }
              if (self.cssPosition) {
                div.style.transform = `translate(${x + self.offsetX}px, ${y + self.offsetY}px)`;
              } else {
                div.style.left = x + self.offsetX + "px";
                div.style.top = y + self.offsetY + "px";
              }
              div.style["z-index"] = self.zIndex;
            }
          }
          onAdd () {
            const div = self.$el;
            const panes = this.getPanes();
            div.style.position = "absolute";
            div.style.display = "inline-block";
            div.style.zIndex = self.zIndex;
            panes.overlayLayer.appendChild(div);
            panes.overlayMouseTarget.appendChild(div);
            this.getDraggable = () => false;
            this.getPosition = () => {
              return new google.maps.LatLng(self.lat, self.lng);
            };
            self.afterCreate(this);
          }
          onRemove () {
            if (self.$el) {
              const ua = window.navigator.userAgent
              const msie = ua.indexOf("MSIE ")
              if (msie > 0 || !!ua.match(/Trident.*rv\:11\./)) {
                self.$el.parentNode.removeChild(self.$el)
              } else {
                self.$el.remove();
              }
            }
          }
        }
        this.$overlay = new Overlay(map);
        setTimeout(() => {
          if (this.$overlay) {
            this.$overlay.repaint();
            this.opacity = 1;
          }
        }, 100);
      });
    },
    computed: {
      lat () {
        return parseFloat(
          isNaN(this.marker.lat) ? this.marker.latitude : this.marker.lat
        );
      },
      lng () {
        return parseFloat(
          isNaN(this.marker.lng) ? this.marker.longitude : this.marker.lng
        );
      },
      latLng () {
        if (this.marker instanceof google.maps.LatLng) {
          return this.marker;
        }
        return new google.maps.LatLng(this.lat, this.lng);
      }
    },
    destroyed () {
      if (this.$clusterObject) {
        this.$clusterObject.removeMarker(this.$overlay, true);
      } else {
	if (this.$overlay) {
          this.$overlay.setMap(null);
          this.$overlay = undefined;
	}
      }
    }
  };
</script>