<template>
  <div class="media-player" :class="{'playing': isPlaying, 'expanded': isExpanded}">
    <div class="controllers">
      <b-button variant="success" class="togglePlayerBtn webPlayerControl" @click="togglePlay">
          <i class="fa fa-volume-up" v-show="!isPlaying" aria-hidden="true"></i>
          <i class="fa fa-volume-off" v-show="isPlaying" aria-hidden="true"></i>
      </b-button>

      <b-button variant="success" class="expand-btn webPlayerControl" v-show="isPlaying" @click="toggleExpand">
        <i class="fa fa-bars"></i>
      </b-button>
    </div>

    <div class="players">
      <div class="player" v-for="song in songList" :key="song.index" :class="{'playing': song.isPlaying,'active':!song.mute}">
        <div class="cover" :class="song.key">
        </div>
        <div class="controllers">
          <a :href="song.src" class="control-btn" :download="song.songName" v-if="!song.isStream">
            <i class="fa fa-cloud-download"></i>
          </a>
          <div class="songName">
            <small>{{song.songName}}</small>
          </div>
          <b-progress v-if="!song.isStream" :value="song.position | progressBar" :max="song.duration | progressBar" height="3px" class="song-progress" variant="primary"></b-progress>
          <b-progress v-if="song.isStream" :value="1" :max="1" height="3px" class="song-progress" variant="primary"></b-progress>
          <div class="song-info">
            <span class="seek seek-position">{{song.position | toDuration}}</span>
            <span class="seek seek-duration" v-if="!song.isStream">{{song.duration | toDuration}}</span>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { Howl, Howler } from "howler";
import { mapState } from "vuex";
import { setInterval, clearInterval } from "timers";
import { isUndefined, isNull, debug } from "util";
require("../scripts/CodinQ.howl");

export default {
  data() {
    return {
      isExpanded: false,
      isPlaying: false,
      hostUrl: `http://${window.location.hostname}:${window.location.port}`,
      songList: [],
      eventNames: {
        changeSong: "mediaPlayer.changeSong",
        changePosition: "mediaPlayer.changePosition",
        changeState: "mediaPlayer.changeState",
        addNewPlayer: "mediaPlayer.addNewPlayer"
      }
    };
  },

  mounted() {
    this.init();
    window.song = this.songList;
  },

  filters: {
    progressBar(value) {
      return parseInt(value);
    }
  },

  watch: {
    connected(newValue, oldValue) {
      if (newValue === oldValue) {
        return;
      }
      if (!newValue) {
        if (this.isPlaying) {
          this.togglePlay();
          this.destory();
        }
      } else {
        this.init();
      }
    }
  },

  computed: {
    djPlayerEnableAnnounces: {
      get() {
        return this.$store.getters["djPlayer/enableAnnounces"];
      }
    },
    ...mapState(["connected"])
  },

  methods: {
    // Getter song playing status
    isPlayingSong(songKey) {
      if (!songKey) {
        console.log("isPlayingSong: songKey is not defined");
        return;
      }

      let songIndex = this.getSongIndex(songKey);
      if (songIndex === -1) {
        console.log("isPlayingSong: songIndex is not defined");
        return;
      }
      return this.songList[songIndex].isPlaying;
    },

    // Song src url getter
    getSrc(src) {
      if (!src) {
        return;
      }
      return `${this.hostUrl}/files/${src}`;
    },

    // index number getter of song
    getSongIndex(songKey) {
      if (!songKey) {
        console.log("getSongIndex: songKey is not defined");
      }

      if (!this.songList.length) {
        return -1;
      }

      let songIndex = -1;

      this.songList.forEach((song, index) => {
        if (song.key !== songKey) {
          return;
        }
        songIndex = index;
      });

      return songIndex;
    },

    // Toggle expand
    toggleExpand() {
      this.isExpanded = !this.isExpanded;
    },

    // Toggle play
    togglePlay() {
      this.isPlaying = !this.isPlaying;

      this.muteControl();

      // Toggle expanded
      if (this.isPlaying) {
        this.isExpanded = true;
      } else {
        this.isExpanded = false;
      }
    },

    // Initiliaze
    init() {
      this.$root.$on(this.eventNames.changeSong, this.changeSong);
      this.$root.$on(this.eventNames.changePosition, this.changePosition);
      this.$root.$on(this.eventNames.changeState, this.changeState);
      this.$root.$on(this.eventNames.addNewPlayer, this.addNewPlayer);

      // Getting store state keys
      let storeKeys = Object.keys(this.$store.state);

      // Filtering web player support enabled states
      let supportedWebPlayerNames = storeKeys
        .filter(storeKey => {
          return this.$store.state[storeKey].supportsWebPlayer === true;
        })
        .map(storeKey => {
          return storeKey;
        });

      supportedWebPlayerNames.forEach(playerName => {
        this.$store.dispatch(`${playerName}/getWebMediaPlayerStatus`);
      });
    },

    addNewPlayer(data) {
      if (!data) {
        console.log("addNewPlayer: data is not defined");
        return;
      }

      let songObject = {
        key: data.key,
        src: "",
        songName: data.songName,
        isPlaying: data.isPlaying,
        currentPosition: data.position,
        position: 0,
        duration: 0,
        isStream: false,
        howlIndex: -1,
        updaterInterval: null,
        mute: true
      };

      if (data.key === "streaming") {
        songObject.isStream = true;
        songObject.src = data.src;
      } else {
        songObject.src = this.getSrc(data.src);
      }

      let addedSongIndex = this.songList.push(songObject) - 1;

      if (!songObject.src || !data.isPlaying) {
        return;
      }

      this.initSong(this.songList[addedSongIndex]);
    },

    // Initiliaze song
    initSong(song) {
      if (!song) {
        console.log("initSong: song is not defined");
        return;
      }

      if (song.howl) {
        console.log("initSong: song already");
        return;
      }

      song.howl = new Howl({
        src: [song.src],
        html5: song.isStream,
        mute: song.mute
      });

      console.log(`initSong: ${song.key} song initilaized.`);

      if (song.isStream) {
        song.howl.play();
      }

      // Song will play when loaded
      song.howl.on("load", () => {
        console.log(song.key + " song is loaded event");

        if (song.isStream) {
          return;
        }

        song.howl.play();

        song.duration = song.howl.duration();
      });

      // Song will playing
      song.howl.on("play", songIndex => {
        console.log(song.key + " song is playing event");
        song.howlIndex = songIndex;

        this.muteControl();

        // Initiliaze song position updater interval
        song.updaterInterval = setInterval(() => {
          if (song.isStream) {
            song.position = song.currentPosition;
            return;
          }
          song.position = song.howl.seek();
        }, 900);

        if (song.isStream) {
          return;
        }
        // Setting position data
        song.howl.seek(song.currentPosition, song.howlIndex);
      });

      // Song will stopped
      song.howl.on("stop", () => {
        console.log(song.key + " song is stopped event");
        this.muteControl();
        song.currentPosition = 0;
        if (song.updaterInterval) {
          clearInterval(song.updaterInterval);
        }
      });
    },

    // Change song
    changeSong(data) {
      if (!data) {
        console.log("changeSong: data is not defined");
        return;
      }

      if (!data.key) {
        console.log("changeSong: data.key is not defined");
        return;
      }

      if (!data.songName) {
        console.log("changeSong: data.songName is not defined");
        return;
      }

      let songIndex = this.getSongIndex(data.key);

      if (songIndex === -1) {
        console.log("changeSong: songIndex is not defined");
        return;
      }

      let song = this.songList[songIndex];

      if (!song) {
        console.log("changeSong: song is not defined");
        return;
      }

      if (song.isStream) {
        song.src = data.src;
        song.songName = data.src;
      } else {
        song.src = this.getSrc(data.src);
        song.songName = data.songName;
      }

      song.currentPosition = 0;

      if (!song.howl) {
        this.initSong(song);
        return;
      }

      song.howl.changeSrc(song.howlIndex, song.src);

      console.log(song.key + " song changed.");
    },

    // Change position
    changePosition(data) {
      if (!data) {
        console.log(`changePosition: data is not defined ${data}`);
        return;
      }

      if (!data.key) {
        console.log(`changePosition: data.key is not defined ${data.key}`);
        return;
      }

      if (isUndefined(data.position)) {
        console.log(
          `changePosition: data.position is not defined ${data.position}`
        );
        return;
      }

      let songIndex = this.getSongIndex(data.key);

      if (songIndex === -1) {
        console.log("changePosition: songIndex is not defined");
        return;
      }

      let song = this.songList[songIndex];

      if (!song) {
        console.log("changePosition: song is not defined");
        return;
      }

      song.currentPosition = data.position;
    },

    // Change state
    changeState(data) {
      if (!data) {
        console.log("changeState: data is not defined");
        return;
      }

      if (!data.key) {
        console.log("changeState: data.key is not defined");
        return;
      }

      if (isUndefined(data.isPlaying)) {
        console.log("changeState: data.isPlaying is not defined");
        return;
      }

      let songIndex = this.getSongIndex(data.key);

      if (songIndex === -1) {
        console.log("changeState: songIndex is not defined");
        return;
      }

      let song = this.songList[songIndex];

      if (!song) {
        console.log("changeState: song is not defined");
        return;
      }

      song.isPlaying = data.isPlaying;

      if (!song.howl) {
        this.initSong(song);
      } else if (song.isPlaying) {
        this.playSong(song);
      } else {
        this.stopSong(song);
      }

      console.log("changeState: changed state: " + song.key);
    },

    // Play song
    playSong(song) {
      if (!song) {
        console.log("playSong: song is not defined");
        return;
      }

      if (!song.howl) {
        console.log("playSong: song.howl is not defined");
        return;
      }

      if (isNull(song.howlIndex)) {
        console.log("playSong: song.howlIndex is not defined");
        return;
      }

      song.isPlaying = true;
      song.howl.play();
    },

    // Stop song
    stopSong(song) {
      if (!song) {
        console.log("playSong: song is not defined");
        return;
      }

      if (!song.howl) {
        console.log("playSong: song.howl is not defined");
        return;
      }

      if (isNull(song.howlIndex)) {
        console.log("playSong: song.howlIndex is not defined");
        return;
      }

      song.isPlaying = false;
      song.duration = 0;
      song.position = 0;

      song.howl.stop();
    },

    // Mute control
    muteControl() {
      if (!this.isPlaying) {
        console.log("not playing");
        this.muteAllSong();
        return;
      }

      // Announce control
      if (this.isPlayingSong("announces")) {
        if (this.isPlayingSong("djPlayer") && !this.djPlayerEnableAnnounces) {
          return;
        }

        this.unMute(["announces"]);
        this.mute(["djPlayer", "streaming", "schedules"]);
        return;
      }

      // DjPlayer control
      if (this.isPlayingSong("djPlayer")) {
        if (this.isPlayingSong("announces")) {
          return;
        }

        this.unMute(["djPlayer"]);
        this.mute(["streaming", "schedules", "announces"]);
        return;
      }

      // Stream control
      if (this.isPlayingSong("streaming")) {
        if (this.isPlayingSong("announces")) {
          return;
        }

        this.unMute(["streaming"]);
        this.mute(["schedules"]);
        return;
      }

      // Schedules control
      if (this.isPlayingSong("schedules")) {
        if (this.isPlayingSong("announces")) {
          return;
        }

        this.unMute(["schedules"]);

        if (this.isPlayingSong("streaming")) {
          return;
        }

        this.mute(["streaming"]);

        return;
      }
    },

    // Mute
    mute(songKeys = []) {
      if (!songKeys.length) {
        console.log("mute: songKeys is not defined.");
        return;
      }

      songKeys.forEach(songKey => {
        let songIndex = this.getSongIndex(songKey);

        if (songIndex === -1) {
          console.log(`mute: songIndex is not found, ${songKey}`);
          return;
        }

        let song = this.songList[songIndex];

        if (!song.howl) {
          console.log(`mute: song.howl is not defined. ${songKey}`);
          return;
        }

        if (song.mute) {
          return;
        }

        song.mute = true;
        song.howl.mute(true);
        console.log(
          `mute: ${songKeys} is muted, current mute status: ${song.howl._muted}`
        );
      });
    },

    // Un mute
    unMute(songKeys = []) {
      if (!songKeys.length) {
        console.log("unMute: songKeys is not defined.");
        return;
      }

      songKeys.forEach(songKey => {
        let songIndex = this.getSongIndex(songKey);

        if (songIndex === -1) {
          console.log(`unMute: songIndex is not found, ${songKey}`);
          return;
        }

        let song = this.songList[songIndex];

        if (!song.howl) {
          console.log(`unMute: song.howl is not defined. ${songKey}`);
          return;
        }

        song.mute = false;
        song.howl.mute(false);
        console.log(
          `unMute: ${songKeys} is un muted, current mute status: ${
            song.howl._muted
          }`
        );
      });
    },

    // Mute all song
    muteAllSong() {
      this.songList.forEach(song => {
        if (!song.howl) {
          return;
        }

        if (song.howl._muted) {
          return;
        }

        song.mute = true;
        song.howl.mute(song.mute);
        console.log(`muteAllSong: ${song.key} is muted`);
      });
    },

    // Destroy all song howl
    destory() {
      // Close events
      this.$root.$off(this.eventNames.changeSong);
      this.$root.$off(this.eventNames.changePosition);
      this.$root.$off(this.eventNames.changeState);
      this.$root.$off(this.eventNames.addNewPlayer);

      // Destroy songs
      this.songList.forEach(song => {
        if (!song.howl) {
          return;
        }

        song.howl.unload();
        song.howl = null;

        if(song.updaterInterval){
          clearInterval(song.updaterInterval);
        }
      });

      // Clean song list array
      this.songList = [];
    }
  }
};
</script>

<style lang="scss" scoped>
@import "../styles/sass/variables";
@keyframes marquee {
  from {
    transform: translateX(30%);
  }

  to {
    transform: translateX(-50%);
  }
}

.media-player {
  & > .controllers {
    position: fixed;
    top: 85px;
    right: 30px;
    transition: all 0.5s ease-in-out;
    display: flex;
    flex-direction: column;

    .btn {
      border-radius: 50%;
      margin-bottom: 20px;
      border-color: $smg;
      background-color: $white;
      color: $smg;
    }
  }

  &.playing {
    & > .controllers {
      right: 40px;
    }
    .players {
      box-shadow: 0px 0px 7px 1px #777777;
      right: -290px;
    }
  }

  &.expanded {
    & > .controllers {
      right: 300px;

      .btn {
        border-top-right-radius: 0px;
        border-bottom-right-radius: 0px;
        border-right: unset;
      }
    }

    & .players {
      right: 0px;
    }
  }

  .players {
    width: 300px;
    height: 100vh;
    background-color: $white;
    position: fixed;
    top: 0px;
    right: -300px;
    padding: 10px;
    transition: all 0.5s ease-in-out;
    z-index: 10002;

    .player {
      width: 100%;
      display: flex;
      box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.5);
      margin-bottom: 10px;
      padding: 3px;
      transition: all 0.3s ease-in-out;
      opacity: 1;
      background-color: $white;
      align-items: center;
      filter: grayscale(100%);

      &.playing {
        filter: none;
      }

      &.active {
        box-shadow: 0px 0px 2px 0px #f05123;
      }

      &:after {
        content: " ";
        clear: both;
        height: 0px;
      }

      .cover {
        font-size: 28px;
        text-align: center;
        width: 50px;
        height: 50px;
        color: $smg;
        margin-right: 3px;
        font: normal normal normal 22px FontAwesome;
        display: flex;
        justify-content: center;
        align-items: center;
        &.schedules {
          &:after {
            content: "\F001";
          }
        }

        &.djPlayer {
          &:after {
            content: "\F025";
          }
        }

        &.announces {
          &:after {
            content: "\F0A1";
          }
        }

        &.streaming {
          &:after {
            content: "\F1EE";
          }
        }
      }

      .controllers {
        width: 200px;
        padding: 3px;
        display: flex;
        flex-direction: column;
        position: relative;
        overflow: hidden;

        .songName {
          position: relative;
          height: 20px;
          small {
            display: inline-block;
            width: 200%;
            font-size: 12px;
            position: absolute;
            animation-duration: 8s;
            animation-name: marquee;
            animation-iteration-count: infinite;
            animation-direction: alternate;
            animation-timing-function: linear;
            white-space: nowrap;
            overflow: hidden;
            box-sizing: border-box;
          }
        }

        .control-btn {
          font-size: 24px;
          align-self: flex-end;
        }

        .song-info {
          display: flex;
          justify-content: flex-end;

          .seek {
            display: block;
            font-size: 11px;
            float: left;
            margin-left: 5px;
          }
        }
      }

      .song-progress {
        margin-top: 4px;
        margin-bottom: 4px;
      }
    }
  }
}
</style>
