<template>
  <div class="h-100" v-if="meeting.passwordRequired ? meeting.passwordProvided : true">
    <div v-if="accessDialogShown">Please allow access to camera and microphone</div>
      <div class="h-100" ref="videos">
          <transition-group tag="div" class="video-wrapper" name="tiles">
              <grid-layout
                  :layout="videoGrid"
                  :key="uniqueId"
                  :col-num="maxCols"
                  :max-rows="maxRows"
                  :row-height="rowHeight"
                  :is-draggable="true"
                  :is-resizable="true"
                  :verticalCompact="true"
                  :margin="[gridPadding, gridPadding]"
                  :use-css-transforms="true"
              >
                  <grid-item v-for="(video, index) in videoGrid" :key="video.id" :id="video.id" :x="video.x" :y="video.y" :w="video.w" :h="video.h" :i="video.i">
                      <v-btn :color="'#282e38'" fab large dark class="v-btn--kick" @click="kickParcitipant(video)" v-show="!video.video.self && user.type == 'associate'">
                          <v-icon>mdi-account-remove</v-icon>
                      </v-btn>
                  </grid-item>
              </grid-layout>
          </transition-group>
          <!-- <div v-for="(video, index) in videos" :id="video.id" :key="video.id" @click="switchToFullSize(video, index)" :class="{'selected-high': video.id == bigMembersCountSelectedId, 'selected-low': lowMembersCountSelectedId == video.id}" class="video-container">
          </div>-->
      </div>
      <button class="unscale" @click="bigMembersCountSelectedId = null" v-show="bigMembersCountSelectedId !== null">
          <i class="mdi mdi-close"></i>
      </button>
      <div style="display:none" ref="otContainer">
          <!-- Container to catch OpenTok Elements before reattaching -->
      </div>
      <!-- <modal-questions ref="initialModal" @questionsAnswered="getToken" @ready="ready"></modal-questions> -->
  </div>
</template>

<script>
import { mapState } from "vuex";

import VueGridLayout from "vue-grid-layout";

export default {
  components: {
    GridLayout: VueGridLayout.GridLayout,
    GridItem: VueGridLayout.GridItem
  },
  data() {
    return {
        readyForUse: false,
        uniqueId: Math.floor(Math.random() * Math.floor(10000)),
        counter: 1,
        openTokSession: null,
        publisher: null,
        screenPublisher: null,
        subscribers: [],
        publisherReady: false,
        accessDialogShown: false,
        videos: [],
        videoGrid: [],
        bigMembersCountSelectedId: null,
        lowMembersCountSelectedId: null,
        maxCols: 12,
        maxRows: 4,
        rowHeight: 240,
        gridPadding: 8,
        loadingInProgress: false
    };
  },
  computed: {
    ...mapState(["meeting", "user", "session"])
  },
  methods: {
    disconnect() {
        if (!this.openTokSession) return;
        this.openTokSession.disconnect();
        this.openTokSession.off();
        this.videos = [];
        this.publisher.destroy();
        this.publisher = null;
        this.subscribers = [];
        this.publisherReady = false;
        this.$store.commit("setSessionConnectivityState", false);
        this.openTokSession = null;
        if (this.screenPublisher) {
            this.screenPublisher.destroy();
            this.screenPublisher = null;
            this.$store.commit("setScreenShareState", null);
        }
    },
    getToken(data, isAssociate) {
        if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date() && (this.user.type === "guest" || !confirm("Meeting not started. Start it now?")))
            return;
        data.meetingId = this.meeting.id;
        data.userUid = this.user.UID;
        $.ajax({
            url: isAssociate ? "/associate/token" : "/token",
            method: "POST",
            headers: {
                "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
            },
            data,
            success: data => {
                this.$refs.initialModal.hide();
                if (!isAssociate) {
                    const user = Object.assign({}, this.user);
                    user.id = data.participantId;
                    user.name = data.participantName;
                    user.pin = data.participantPin;
                    this.$store.commit("setUser", user);
                }
                this.initializeOpenTok(data.apiKey, data.sessionId, data.token);
            },
            error: jXhr => {
                if (jXhr.responseJSON && jXhr.responseJSON.errorCode) {
                    switch (jXhr.responseJSON.errorCode) {
                        case "LM-1":
                            alert("Meeting not started yet.");
                            break;
                        case "LM-2":
                            alert("You was kicked from this meeting.");
                            window.location = "/";
                            break;
                        case "LM-3":
                            alert("Wrong password");
                            this.$refs.initialModal.disableWaiting();
                            break;
                    }
                } else {
                    this.$refs.initialModal.disableWaiting();
                    alert(getSingleError(jXhr));
                }
            }
        });
    },
    createVideoContainer() {
        let videoCont = {};
        videoCont.id = `${this.uniqueId}_video_${this.counter++}`;
        if (this.videos.length == 1 && !this.lowMembersCountSelectedId) {
            this.lowMembersCountSelectedId = videoCont.id;
        }

        this.videos.push(videoCont);
        this.adjustVideoContainers();

        return videoCont;
    },
    adjustVideoContainers() {
        this.videoGrid = [];

        let windowHeight = window.innerHeight;
        this.rowHeight = (windowHeight - this.gridPadding * (this.maxRows + 1)) / this.maxRows;

        let cols = Math.ceil(Math.sqrt(this.videos.length));
        let rows = Math.ceil(this.videos.length / cols);

        let elementsLastRow = this.videos.length % cols;
        let lastNormalIndex = this.videos.length - elementsLastRow;

        if (elementsLastRow) {
            this.maxCols = cols * elementsLastRow;
        } else {
            this.maxCols = cols;
        }

        let colsPerElement = this.maxCols / cols;
        let rowsPerElement = this.maxRows / rows;

        let colsLastRow = Math.ceil(this.maxCols / elementsLastRow);

        let cntX = 0;
        let cntY = 0;

        for (let [index, video] of this.videos.entries()) {
            video.i = index;
            video.x = cntX;
            video.y = cntY;
            video.h = rowsPerElement;
            video.w = colsPerElement;
            cntX += colsPerElement;

            if (cntX >= this.maxCols) {
                cntX = 0;
                cntY += rowsPerElement;
            }

            let videoTemp = Object.assign({}, video);
            videoTemp.video = video;
            this.videoGrid.push(videoTemp);
        }

        /* OLD IMPLEMENTATION */

        /* for (let [index, video] of this.videos.entries()) {
            video.i = index;
            if (index < lastNormalIndex) {
                video.x = cntX;
                video.y = cntY;
                video.h = rowsPerElement;
                video.w = colsPerElement;
                cntX += colsPerElement;

                if (cntX >= this.maxCols) {
                    cntX = 0;
                    cntY += rowsPerElement;
                }
            } else {
                video.x = cntX;
                video.y = cntY;
                video.h = rowsPerElement;
                video.w = colsLastRow;
                cntX += colsLastRow;
            }

            let videoTemp = Object.assign({}, video);
            this.videoGrid.push(videoTemp);
        } */

        /* let gridColumn, gridRows = ''

        if(rows && cols){
            gridColumn = `grid-template-columns: repeat(${cols}, minmax(320px, 1fr));`
            gridRows = `grid-template-rows: repeat(${rows}, minmax(240px, 1fr));`
        } */
    },
    initializeOpenTok(apiKey, sessionId, token) {
      this.openTokSession = OT.initSession(apiKey, sessionId);

      this.openTokSession.on({
          sessionDisconnected: event => {
              if (event.reason === "forceDisconnected") {
                  alert("You were kicked.");
                  if (this.user.type === "associate") {
                      this.disconnect();
                      this.$store.dispatch("leaveMeeting");
                  } else {
                      window.location = "/";
                  }
              }
          }
      });

      // Create a publisher
      this.publisher = OT.initPublisher(
          this.$refs.otContainer,
          {
            insertMode: "append",
            width: "100%",
            height: "100%",
            resolution: "1280x720",
            frameRate: 30,
            name: this.user.name,
            style: {
                nameDisplayMode: "on",
                archiveStatusDisplayMode: "off"
            }
          },
          error => {
            if (error) {
                alert(error.message);
            } else {
                this.publisherReady = true;
                const cont = this.createVideoContainer();
                this.$nextTick(() => {
                    cont.el = $(`#${cont.id}`)[0];
                    cont.el.appendChild(this.publisher.element);
                    cont.obj = this.publisher;
                    this.$set(cont, "self", true);
                    //cont.self = true;
                });
            }
          }
      );

      this.publisher.on({
          accessDialogOpened: e => {
            this.accessDialogShown = true;
          },
          accessDialogClosed: e => {
            this.accessDialogShown = false;
          }
      });

      this.openTokSession.on("streamCreated", event => {
        //console.log("stream Created event");
        let container;
        if (event.stream.videoType === "screen") {
          //TODO: This is
        }
        const subscriber = this.openTokSession.subscribe(
          event.stream,
          this.$refs.otContainer,
          {
            insertMode: "append",
            width: "100%",
            height: "100%",
            style: { nameDisplayMode: "on" }
          },
          error => {
              if (error) {
                alert(error.message);
              } else {
                  const cont = this.createVideoContainer();
                  this.$nextTick(() => {
                    cont.el = $(`#${cont.id}`)[0];
                    cont.el.appendChild(subscriber.element);
                    cont.obj = subscriber;
                    container = cont;
                  });
              }
          }
        );
        subscriber.on({
          destroyed: e => {
            container.el.remove();
            const index = this.videos.findIndex(v => v.id == container.id);
            if (index >= 0) this.videos.splice(index, 1);
            this.adjustVideoContainers();
          }
        });
        this.subscribers.push(subscriber);
      });

    this.openTokSession.connect(token, error => {
        // If the connection is successful, publish to the session
        if (error) {
            alert(error.message);
        } else {
            this.$store.commit("setSessionConnectivityState", true);
        }
      });
      this.loadingInProgress = false;
    },
    publishToSession() {
        this.openTokSession.publish(this.publisher, error => {
          if (error) {
            alert(error.message);
          }
        });
    },
    switchToFullSize(video, index) {
        if (this.videos.length < 4) {
          if (this.lowMembersCountSelectedId !== video.id && index !== 0) {
            this.lowMembersCountSelectedId = video.id;
          }
        } else {
          this.bigMembersCountSelectedId = video.id;
        }
    },
    ready() {
        this.$nextTick(function() {
          this.readyForUse = true;
          if (this.user.type === "associate") {
            if (!this.meeting.id || this.active_menu_item.template !== "room") return;
            this.getToken({}, true);
            return;
          }

          if (this.meeting.scheduledDate && !this.meeting.startedAt && this.meeting.scheduledDate > new Date()) {
            alert("Meeting not started.");
            return;
          }
          let participantId = this.user.id;
          if (!participantId) {
            this.$refs.initialModal.show(this.meeting.passwordRequired);
            return;
          }
          this.getToken({
            participantId
          });
        });
    },
    shareScreen() {
        if (this.screenPublisher) return;
        this.screenPublisher = OT.initPublisher(
            this.$refs.otContainer,
            {
              insertMode: "append",
              width: "100%",
              height: "100%",
              resolution: "1280x720",
              frameRate: 30,
              videoSource: "screen",
              name: this.user.name,
              style: {
                nameDisplayMode: "on",
                archiveStatusDisplayMode: "off"
              }
            },
            error => {
                if (error) {
                  console.error(error);
                  if (error.code !== 1500) alert(error.message);
                  this.screenPublisher = null;
                } else {
                  const cont = this.createVideoContainer();
                  this.$nextTick(() => {
                    cont.el = $(`#${cont.id}`)[0];
                    cont.el.appendChild(this.screenPublisher.element);
                    cont.obj = this.screenPublisher;
                    // cont.self = true;

                    this.$set(cont, "self", true);
                  });
                  this.screenPublisher.on("streamDestroyed", event => {
                    cont.el.remove();
                    const index = this.videos.findIndex(v => v.id == cont.id);
                    if (index >= 0) this.videos.splice(index, 1);
                    this.adjustVideoContainers();
                    this.screenPublisher = null;
                    this.$store.commit("setScreenShareState", false);
                  });
                  this.openTokSession.publish(this.screenPublisher, error => {
                    if (error) {
                      alert(error.message);
                    }
                  });
                  this.$store.commit("setScreenShareState", true);
                }
            }
        );
    },
    kickParcitipantContinue(participant) {
        const connection = participant.video.obj.stream.connection;
        const [type, id] = connection.data.split(":");
        this.openTokSession.forceDisconnect(connection, error => {
          if (error) {
            console.error(error);
          } else {
            $.ajax({
              url: `/associate/meeting/${this.meeting.id}/kick`,
              method: "POST",
              headers: {
                "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
              },
              data: {
                type,
                id
              },
              error: jXhr => {
                console.error(getSingleError(jXhr));
              }
            });
          }
        });
    },
    kickParcitipant(participant) {
      if (confirm("Are you sure want to kick this person out of meeting?")) this.kickParcitipantContinue(participant);
    }
},
watch: {
    publisherReady(val) {
      if (val && this.session.sessionConnected) this.publishToSession();
    },
    "session.sessionConnected"(val) {
      if (val && this.publisherReady) this.publishToSession();
    },
    "user.is_active_and_visible"(val) {
      if (!this.publisher || !this.publisher.publishVideo) return;
      this.publisher.publishVideo(val);
      this.publisher.publishAudio(val);
    },
    "meeting.id"(val) {
      if (this.loadingInProgress) return;
      this.loadingInProgress = true;
      this.disconnect();

      if (val) {
          this.getToken({}, true);
      } else {
          this.loadingInProgress = false;
      }
    },
    "active_menu_item.template"(val) {
      if (this.loadingInProgress || val !== "room" || !this.meeting.id || this.openTokSession) return;
      this.loadingInProgress = true;
      this.getToken({}, true);
    }
  },
  created() {
    OT.checkScreenSharingCapability(response => {
      this.$store.commit("setScreesharingAvailability", response.supported);
    });
  },
  mounted() {
    let self = this;

    this.$eventBus.$on("screenShare", this.shareScreen);
    this.$eventBus.$on("meetingRejoin", () => {
      this.loadingInProgress = true;
      this.disconnect();
      this.getToken({}, true);
    });

    let width = $(window).width();
    let height = $(window).height();

    window.addEventListener("resize", function() {
      let new_width = $(window).width();
      let new_height = $(window).height();

      if (width !== new_width || height !== new_height) {
        self.adjustVideoContainers();
      }
    });

    this.$eventBus.$on("leaveMeeting", () => {
      $.ajax({
        url: "/associate/meeting/leave",
        method: "POST",
        headers: {
          "X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
        },
        error: jXhr => {
          console.error(getSingleError(jXhr));
        }
      });
      this.$store.dispatch("leaveMeeting");
      this.disconnect();
    });
  }
}
</script>