<script>
import { inject, watch } from 'vue'
import { Options, Vue } from "vue-class-component";

@Options({
  props: {
    tagName: String,
    src: String,
    style: { type:Object, default: {}},
  },
})
class MediaFrame extends Vue {
  constructor(props) {
    super(props);

    this.mediaRef = null;

    this.mediaCtrl = inject('mediaCtrl');
    this.mediaTime = inject('mediaTime');
    this.mediaStatus = inject('mediaStatus');

    watch(() => this.mediaCtrl.seek, this.seekMediaStep.bind(this));
    watch(() => this.mediaCtrl.volume, this.volumeMediaStep.bind(this));
    watch(() => this.mediaCtrl.playTrigger, this.setPlayPause.bind(this));
    watch(() => this.mediaCtrl.loadTrigger, this.reload.bind(this));
  }

  mounted() {
    this.mediaRef = this.$refs.mediaRef;
    this.mediaStatus.volume = this.mediaRef.volume;
  }

  seekMediaStep(timeStep) {
    if(!this.mediaRef) {
      return;
    }

    let playEnd = false;
    let seekTime = this.mediaRef.currentTime + Math.ceil(timeStep);
    if(seekTime < 0) {
      seekTime = 0;
    } else if(seekTime > this.mediaTime.duration) {
      seekTime = this.mediaTime.duration;
      if(this.mediaRef.currentTime != this.mediaTime.duration) { // 触发一次播放，收到ended事件
        playEnd = true;
      }
    }
    this.mediaRef.currentTime = seekTime;
    if(playEnd) {
      this.setPlayPause(true);
    }
  }

  setPlayPause() {
    if(!this.mediaStatus.playing) {
      this.mediaRef.play();
    } else {
      this.mediaRef.pause();
    }
  }

  reload() {
    this.mediaRef.load();
  }

  volumeMediaStep(volumeStep) {
    if(!this.mediaRef) {
      return;
    }

    let volume = this.mediaRef.volume + volumeStep;
    if(volume < 0) {
      volume += 1;
    }else if(volume > 1) {
      volume -= 1;
    }
    volume = Math.round(volume * 10) / 10; // 保留一位小数
    this.mediaRef.volume = volume;
    this.mediaStatus.volume = volume;
  }

  onErrorEvent(event) {
    const state = event.type + ": code=" + this.mediaRef.error.code + ", message=" + this.mediaRef.error.message;
    console.log("MediaFrame.onErrorEvent()", event, state);
    this.mediaStatus.playState = state;
  }

  onTimeUpdate(event) {
    if(!this.mediaRef) { // unmounted
      return;
    }
    // console.log("MediaFrame.onTimeUpdate()", event, this.mediaRef.currentTime);
    this.mediaTime.currentTime = this.mediaRef.currentTime;
  }

  onDurationChange(event) {
    console.log("MediaFrame.onDurationChange()", event.type);
    this.mediaTime.duration = this.mediaRef.duration;
  }

  onOtherEvent(event) {
    console.log("MediaFrame.onOtherEvent()", event.type);
    this.mediaStatus.playState = event.type;
    if(event.type == 'playing') {
      this.mediaStatus.playing = true;
    } else if(event.type == 'loadstart'
    || event.type == 'pause'
    || event.type == 'error') {
      this.mediaStatus.playing = false;
    }
  }
}

export default MediaFrame;
</script>

<template>
<div>
  <!-- <component :is="tagName"> 可以直接换成<video>/<audio>, -->
  <!-- 这里是为了统一onEvent处理才这样写                         -->
  <component :is="tagName"
    ref="mediaRef"

    :style="style"

    :autoplay="mediaCtrl.autoplay" 
    :loop="mediaCtrl.loop"
    :muted="mediaCtrl.mute"
    :playbackRate="mediaCtrl.playbackRate"
    :src="src"

    :onabort="onOtherEvent"
    :oncanplay="onOtherEvent"
    :oncanplaythrough="onOtherEvent"
    :ondurationchange="onDurationChange"
    :onended="onOtherEvent"
    :onerror="onErrorEvent"
    :onload="onOtherEvent"
    :onloadedmetadata="onOtherEvent"
    :onloadstart="onOtherEvent"
    :onpause="onOtherEvent"
    :onplay="onOtherEvent"
    :onplaying="onOtherEvent"
    :onseeking="onOtherEvent"
    :onseeked="onOtherEvent"
    :onstalled="onOtherEvent"
    :ontimeupdate="onTimeUpdate"
  />
</div>
</template>

<style scoped>
</style>
