<template>
  <teleport to="#content">
    <div id="navmap">
      <nav>
        <a class="top" href="#top">
          <i class="fa fa-fw fa-square" />
          <span>{{ $t("nav.top") }}</span>
        </a>
        <item v-for="item of items" :key="item.key" :item="item" :step="step" />
      </nav>
    </div>
  </teleport>
</template>

<script>
import Item from "./StickyNav/Item.vue";

export default {
  name: "StickyNav",
  components: {
    Item,
  },
  data() {
    return {
      header: document.querySelector("header nav.navbar"),
      bannerName: document.querySelector("#header-accompanying_course-name"),
      bannerDetails: document.querySelector(
        "#header-accompanying_course-details",
      ),
      container: null,
      heightSum: null,
      stickyNav: null,
      limit: 25,
      anchors: null,
      items: [],
    };
  },
  computed: {
    accompanyingCourse() {
      return this.$store.state.accompanyingCourse;
    },
    step() {
      return this.accompanyingCourse.step;
    },
    top() {
      return parseInt(
        window
          .getComputedStyle(this.stickyNav)
          .getPropertyValue("top")
          .slice(0, -2),
      );
    },
  },
  mounted() {
    this.ready();
    window.addEventListener("scroll", this.handleScroll);
  },
  unmounted() {
    window.removeEventListener("scroll", this.handleScroll);
  },
  methods: {
    ready() {
      // load datas DOM when mounted ready
      this.container = document.querySelector("#content");
      this.stickyNav = document.querySelector("#navmap");
      this.anchors = document.querySelectorAll("h2 a[id^='section']");
      this.initItemsMap();

      // TODO resizeObserver not supports IE !
      // Listen when elements change size, then recalculate heightSum and initItemsMap
      const resizeObserver = new ResizeObserver(() => {
        this.refreshPos();
      });

      resizeObserver.observe(this.header);
      resizeObserver.observe(this.bannerName);
      resizeObserver.observe(this.bannerDetails);
      resizeObserver.observe(this.container);
    },
    initItemsMap() {
      this.anchors.forEach((anchor) => {
        this.items.push({
          pos: null,
          active: false,
          key: parseInt(anchor.id.slice(8).slice(0, -1)),
          id: "#" + anchor.id,
        });
      });
    },
    refreshPos() {
      //console.log('refreshPos');
      this.heightSum =
        this.header.offsetHeight +
        this.bannerName.offsetHeight +
        this.bannerDetails.offsetHeight;

      this.anchors.forEach((anchor, i) => {
        this.items[i].pos = this.findPos(anchor)["y"];
      });
    },
    findPos(element) {
      let posX = 0,
        posY = 0;
      do {
        posX += element.offsetLeft;
        posY += element.offsetTop;
        element = element.offsetParent;
      } while (element != null);

      let pos = [];
      pos["x"] = posX;
      pos["y"] = posY;

      return pos;
    },
    handleScroll() {
      let pos = this.findPos(this.stickyNav);
      let top = this.heightSum + this.top - window.scrollY;
      //console.log(window.scrollY);

      if (top > this.limit) {
        this.stickyNav.style.position = "absolute";
        this.stickyNav.style.left = "10px";
      } else {
        this.stickyNav.style.position = "fixed";
        this.stickyNav.style.left = pos["x"] + "px";
      }

      this.switchActive();
    },
    switchActive() {
      this.items.forEach((item, i) => {
        let next = this.items[i + 1] ? this.items[i + 1].pos : "100000";
        item.active =
          (window.scrollY >= item.pos) & (window.scrollY < next) ? true : false;
      }, this);

      // last item never switch active because scroll reach bottom of page
      if (document.body.scrollHeight == window.scrollY + window.innerHeight) {
        this.items[this.items.length - 1].active = true;
        this.items[this.items.length - 2].active = false;
      } else {
        this.items[this.items.length - 1].active = false;
      }
    },
  },
};
</script>

<style lang="scss">
div#content {
  position: relative;

  div#navmap {
    position: absolute;
    top: 30px;
    left: 10px; //-10%;
    nav {
      font-size: small;
      a {
        display: block;
        box-sizing: border-box;
        margin-bottom: -3px;
        color: #71859669;
        text-decoration: none;
        &.top {
          color: #718596;
        }
        span {
          display: none;
        }
        &:hover,
        &.active {
          span {
            display: inline;
            padding-left: 8px;
          }
        }
        &:hover {
          color: #718596b5;
        }
        &.active {
          color: #e2793d; //orange
          //color: #eec84a; //jaune
        }
      }
    }
  }
}
@media only screen and (max-width: 768px) {
  div#navmap {
    display: none;
  }
}
</style>
