<template>
  <div>
    <v-contextmenu ref="contextmenu">
      <v-contextmenu-item v-if="!disabled">
        <el-popover
          v-model="visible"
          trigger="click"
        >
          <el-form ref="form" :model="note_form" :rules="rules" label-width="80px">
            <el-form-item :label="$t('note.table.original_text')">
              <el-input autosize type="textarea" v-model="note_form.original_text" disabled></el-input>
            </el-form-item>
            <el-form-item :label="$t('read.form.note_title')" prop="note_title">
              <el-input v-model="note_form.note_title"
                        :placeholder="$t('input_please', { keyword: this.$t('read.form.note_title') })"></el-input>
            </el-form-item>
            <el-form-item :label="$t('read.form.note_content')" prop="note_content">
              <el-input autosize type="textarea" v-model="note_form.note_content"
                        :placeholder="$t('input_please', { keyword: this.$t('read.form.note_content') })"></el-input>
            </el-form-item>
            <el-form-item>
              <el-button @click="addNote">{{$t('button.add')}}</el-button>
              <el-button @click="visible=false">{{$t('button.cancel')}}</el-button>
            </el-form-item>
          </el-form>
          <el-button slot="reference">{{$t('read.contextmenu.add')}}</el-button>
        </el-popover>
      </v-contextmenu-item>
      <v-contextmenu-item>
        <el-button @click="updateFind(true);queryContent()" class="w-100">{{$t('read.contextmenu.search')}}</el-button>
      </v-contextmenu-item>
    </v-contextmenu>
    <el-tabs v-model="activeName" type="card" closable @tab-remove="removeTab">
      <el-tab-pane :label="key" :name="key" v-for="(item,key) in openList" :key="key">
        <el-row>
          <el-col :span="18">
            <el-form :inline="true" v-if="showSearch">
              <el-form-item :label="$t('read.form.keyword')">
                <el-input @input="queryContent" :placeholder="$t('input_please',{keyword:$t('read.form.keyword')})"
                          v-model="search_form.keyword"
                          maxlength="10"
                          show-word-limit>
                  <i slot="prefix" class="el-input__icon el-icon-search"></i>
                </el-input>
              </el-form-item>
              <template v-if="num>0">
                <el-form-item>{{search_index+1+'/'+num}}</el-form-item>
                <el-tooltip :content="$t('read.tip.search_prev')">
                  <el-image src="/prev.svg" class="img"
                            @click="search_index>0?search_index--:search_index=num-1;change_search_index()"></el-image>
                </el-tooltip>
                <el-tooltip :content="$t('read.tip.search_next')">
                  <el-image src="/next.svg" class="img"
                            @click="search_index<num-1?search_index++:search_index=0;change_search_index()"></el-image>
                </el-tooltip>
              </template>
            </el-form>
            <pre class="content" v-contextmenu:contextmenu :ref="'edit'+item.title" @mouseup="show"
                 @contextmenu="selectText" @scroll="scrollContent" v-html="item.content"
            />
          </el-col>
          <el-col :span="5" class="note-list ml3">
            <template v-if="noteList.length>0">
              <el-row v-for="(item,index) in noteList" :key="index" class="mb2">
                  <el-card :class="{'active_card':item.isActive}">
                    <div slot="header" class="clearfix">
                      <el-row type="flex" justify="space-around">
                        <span>{{item.title}}</span>
                        <el-button-group>
                          <el-button size="mini" type="primary" @click="edit(item)" icon="el-icon-edit"></el-button>
                          <el-popconfirm
                            @onConfirm="del(item,index)"
                            :title="$t('read.tip.del_confirm')"
                          >
                            <el-button size="mini" type="danger" slot="reference" icon="el-icon-delete"></el-button>
                          </el-popconfirm>
                        </el-button-group>
                      </el-row>
                    </div>
                    <div class="text item" @click="jump(item)" @mouseover="highlighting(item)"
                         @mouseout="reset(item)">
                      <transition v-if="item.isEdit" @after-leave="save(item)">
                        <el-tooltip class="item" effect="dark" :content="$t('read.tip.auto_save')"
                                    v-model="item.isEdit">
                          <el-input autosize type="textarea" v-model="item.content"></el-input>
                        </el-tooltip>
                      </transition>
                      <template v-else>
                        <el-tooltip :content="$t('read.tip.click_note_list')" :disabled="item.isEdit">
                          <pre style="background-color: white">{{item.content}}</pre>
                        </el-tooltip>
                      </template>
                    </div>
                  </el-card>
                <el-alert v-if="item.message"
                          @close="item.message=null;item.type=null"
                          :title="item.message"
                          :type="item.type">
                </el-alert>
              </el-row>
            </template>
            <h1 v-else>{{$t('read.tip.note_zero')}}</h1>
          </el-col>
        </el-row>
      </el-tab-pane>
    </el-tabs>
    <el-col :span="21">
      <el-row class="mt2">
        <el-col :span="7" v-for="(item,index) in stars" :key="index">
          <h3 class="center">{{$t('read.tip.rating_'+(index+1))}}</h3>
          <el-rate
            class="center star-icon"
            v-model="item.value"
            show-score
            score-template="{value}分"
            :disabled="item.value>0">
          </el-rate>
        </el-col>
      </el-row>
      <el-row class="mt2" type="flex" justify="center">
        <el-col :span="3">
          <el-button class="star-button" v-if="show_star_button" @click="submitRating">{{$t('button.rating')}}
          </el-button>
        </el-col>
      </el-row>
    </el-col>
  </div>
</template>

<script lang="ts">

  import Vue from 'vue'

  export default Vue.extend({
    name: 'read',
    layout: 'my-pre',
    data() {
      return {
        //显示搜索框
        showSearch: false,
        //显示笔记表单
        visible: false,
        //正文搜索
        search_form: {
          keyword: ''
        },
        //搜索结果记录数
        num: 0,
        //搜索结果索引
        search_index: -1,
        //笔记表单
        note_form: {
          note_id: '',
          note_title: '',
          note_content: '',
          original_text: ''
        },
        //表单校验规则
        rules: {
          note_title: [{
            required: true,
            message: this.$t('input_please', { keyword: this.$t('read.form.note_title') }),
            trigger: 'blur'
          }],
          note_content: [{
            required: true,
            message: this.$t('input_please', { keyword: this.$t('read.form.note_content') }),
            trigger: 'blur'
          }]
        },
        //活动的论文标签
        activeName: '',
        //笔记列表
        noteList: [],
        //禁用右键菜单标志位
        disabled: true,
        //替换目标
        replace: {},
        stars: [],
        show_star_button: false
      }
    },
    computed: {
      //打开的论文标签
      openList() {
        return this.$store.state.read.read
      },
      //当前激活的正文元素
      pre() {
        return this.$refs['edit' + this.activeName][0]
      },
      //当前激活的论文实体
      activeContent() {
        return this.$store.state.read.read[this.activeName]
      }
    },
    watch: {
      //激活的论文标签
      activeName(newVal) {
        this.$store.commit('read/choose', newVal)
        this.doScroll()
        if (this.activeContent.find && this.activeContent.find.showSearch) {
          this.showSearch = this.activeContent.find.showSearch
          this.search_form.keyword = this.activeContent.find.keyword
          let search_index = this.activeContent.find.search_index
          this.queryContent()
          this.search_index = search_index
          this.change_search_index()
        } else {
          this.showSearch = false
          this.search_form = {
            keyword: ''
          }
          this.num = 0
          this.search_index = -1
        }

      },
      showSearch(newVal) {
        if (!newVal) {
          let pre: HTMLElement = this.pre
          this.search_form.keyword = ''
          this.resetQuery(pre)
        }
      }
    },

    methods: {
      //查找评价记录
      queryRating(){
        let that=this
        this.GLOBAL.fetchGet('/v1/api/paper/findRating', { paperId:this.activeContent.id },function(res) {
          if(res.code==='200'){
            if(res.data===null){
              that.stars=[{ value: 0 }, { value: 0 }, { value: 0 }]
            }else{
              that.stars=[{ value: res.data.score1 }, { value: res.data.score2 }, { value: res.data.score3 }]
            }
            that.show_star_button=res.data===null
          }else{
            that.$message.error(that.$t('error_500').toString())
          }
        })
      },
      //滚动正文
      scrollContent(e) {
        this.$store.commit('read/scroll', e.target.scrollTop)
      },
      doScroll() {
        this.$nextTick(() => {
          if (this.activeContent.scrollTop) {
            this.pre.scrollTo({
              top: this.activeContent.scrollTop
            })
          }
        })
      },
      //激活选中的搜索结果
      change_search_index() {
        let ele = this.pre.querySelectorAll('span[class^=search-light]')[this.search_index]
        ele.classList.add('choose-search-text')
        ele.scrollIntoView({
          block: 'center'
        })
        for (let index = 0; index < this.num; index++) {
          if (index !== this.search_index) {
            this.pre.querySelectorAll('span[class^=search-light]')[index].classList.remove('choose-search-text')
          }
        }

        this.updateFind(this.showSearch)
      },
      updateFind(showSearch = false) {
        this.showSearch = showSearch
        this.$store.commit('read/find', {
          showSearch: showSearch,
          keyword: this.search_form.keyword,
          search_index: this.search_index
        })
      },
      //重置搜索
      resetQuery(pre: HTMLElement) {
        for (let span of pre.querySelectorAll('span[class^=search-light]')) {
          let text = document.createTextNode(span.innerText)
          span.replaceWith(text)
        }
        pre.normalize()
        this.num = 0
        this.search_index = -1
      },
      //正文搜索
      queryContent() {
        let pre: HTMLElement = this.pre
        this.resetQuery(pre)
        if (this.search_form.keyword.length === 0) {
          let selection = getSelection()
          if (selection && selection.toString().length > 0) {
            this.search_form.keyword = selection.toString()
          } else {
            return
          }
        }
        let replaceObj = []
        for (let node of pre.childNodes) {
          let content = node.nodeType === 3 ? node.data : node.innerText
          let matchAll = content.matchAll(new RegExp(this.search_form.keyword, 'g'))
          let replaceNodes = []
          if (node.nodeType === 1 && node.innerText.length === this.search_form.keyword.length) {
            node.classList.add('search-light')
          } else {
            let length = 0
            let prev
            for (let match of matchAll) {
              this.num += 1
              let start = document.createTextNode(content.substr(prev ? prev : 0, match.index - length))
              let span = document.createElement('span')
              span.classList.add('search-light')
              span.innerText = this.search_form.keyword
              prev = match.index + this.search_form.keyword.length
              replaceNodes.push(start, span)
              length += start.data.length + this.search_form.keyword.length
            }
            if (length > 0) {
              replaceNodes.push(document.createTextNode(content.substr(prev)))
              replaceObj.push({
                source: node,
                target: replaceNodes
              })
            }
          }
        }

        for (let item of replaceObj) {
          let node = item.source
          let replaceNodes = item.target
          if (replaceNodes.length > 0) {
            if (node.nodeType === 3) {
              node.replaceWith(replaceNodes[0])
              for (let index = 1; index < replaceNodes.length; index++) {
                replaceNodes[index - 1].after(replaceNodes[index])
              }
            } else {
              node.innerHTML = ''
              for (let child of replaceNodes) {
                node.appendChild(child)
              }
            }
          }
        }
        if (this.num > 0) {
          this.search_index = 0
          this.change_search_index()
        } else {
          this.$message.warning({
            message: this.$t('read.tip.search_zero', { keyword: this.search_form.keyword }).toString(),
            showClose: true,
            duration: 2000
          })
        }
      },
      //编辑笔记
      edit(item: any) {
        if ('isEdit' in item) {
          item.isEdit = !item.isEdit
        } else {
          this.$set(item, 'isEdit', true)
        }
      },
      //保存笔记
      save(item: any) {
        let that=this
        this.GLOBAL.fetchJSON('/v1/api/notes/update','PUT',{
          noteId:item.id,
          noteContent:item.content
        },function(res) {
            if(res.code==='200'){
              that.$set(item, 'type', 'success')
              that.$set(item, 'message', that.$t('read.tip.update_note_ok'))
            }else {
              that.$set(item, 'type', 'error')
              that.$set(item, 'message', that.$t('read.tip.update_note_fail'))
            }
        })
      },
      //删除笔记
      del(item: any, index: number) {
        let that=this
        let span=document.getElementById(item.id)
        if(span) {
          let text = document.createTextNode(span.innerText)
          span.replaceWith(text)
          that.pre.normalize()
          this.GLOBAL.fetchJSON('/v1/api/notes/remove', 'DELETE', {
            noteId: item.id,
            paperId: that.activeContent.id,
            content: that.pre.innerHTML
          }, function(res) {
            if (res.code === '200') {
              that.noteList.splice(index, 1)
              that.$store.commit('read/updateContent',that.pre.innerHTML)
            } else {
              that.$message.error(that.$t('error_500').toString())
            }
          })
        }else{
          that.$message.error(that.$t('error_500').toString())
        }

      },
      //提交评分
      submitRating() {
        console.info(this.stars)
        let that=this
        this.GLOBAL.fetchJSON('/v1/api/paper/rating','POST',{
          paperId:this.activeContent.id,
          score1:this.stars[0].value,
          score2:this.stars[1].value,
          score3:this.stars[2].value,
        },function(res) {
          if(res.code==='200'){
            that.queryRating()
            that.$message.info(that.$t('read.tip.rating_ok').toString())
          }else{
            that.$message.error(that.$t('error_500').toString())
          }
        })
      },
      //高亮笔记
      highlighting(item: any) {
        let ele = document.getElementById(item.id)
        if (ele && this.GLOBAL.visible_in_container(this.$refs['edit' + this.activeName][0], ele)) {
          ele.classList.add('heightlight')
        }
      },
      reset(item: any) {
        let ele = document.getElementById(item.id)
        if (ele) {
          ele.classList.remove('heightlight')
        }
      },
      //跳转到笔记位置
      jump(item: any) {
        this.noteList.forEach(i=>{
          if(i.id!==item.id){
            this.$set(i,'isActive',false)
          }
        })
        this.$set(item,'isActive',true)
        let ele = document.getElementById(item.id)
        if (ele) {
          ele.scrollIntoView({
            block: 'center'
          })
        }

        this.highlighting(item)
      },
      //是否显示右键菜单
      show() {
        let s = getSelection()
        if (s) {
          this.disabled = s.isCollapsed
        } else {
          this.disabled = true
        }
      },
      //关闭标签
      removeTab(name: string) {
        this.$store.commit('read/close', name)
        if (Object.keys(this.openList).length === 0) {
          this.$router.push(this.localePath('/document'))
          this.$store.commit('menus/none')
        }
        this.activeName = this.$store.state.read.activeName
      },
      resetNote() {
        this.replace = {}
        this.note_form.note_id = ''
        this.note_form.note_title = ''
        this.note_form.note_content = ''
        this.note_form.original_text = ''
      },
      //添加笔记
      addNote() {
        let that = this
        this.$refs.form.validate((valid: boolean) => {
          if (valid && Object.keys(that.replace.replaceVal).length > 0) {
            let id = new Date().getTime()
            let c = document.createElement('span')
            c.setAttribute('id', id.toString())
            that.replace.val.replaceWith(that.replace.replaceVal[0])
            for (let index = 1; index < that.replace.replaceVal.length; index++) {
              that.replace.replaceVal[index - 1].after(that.replace.replaceVal[index])
            }

            that.GLOBAL.fetchJSON('/v1/api/notes/add','POST',{
              noteId: this.note_form.note_id,
              noteTitle: this.note_form.note_title,
              noteContent: this.note_form.note_content,
              paperId: that.activeContent.id,
              fileId: that.activeContent.fileId,
              originalText:that.note_form.original_text,
              content: that.pre.innerHTML
            },function(res) {
                if(res.code==='200'){
                  that.$message.info({
                    message: that.$t('read.tip.add_tip_ok').toString(),
                    showClose: true,
                    duration: 1000,
                    onClose:function() {
                      that.$store.commit('read/updateContent',that.pre.innerHTML)
                      that.noteList.unshift({
                        id: that.note_form.note_id,
                        title: that.note_form.note_title,
                        content: that.note_form.note_content
                      })
                      that.resetNote()
                    }
                  })
                }else{
                  that.$message.error(that.$t('error_500').toString())
                }
            })
          } else {
            that.$message.error(that.$t('read.tip.add_tip_fail').toString())
            return false
          }
          this.visible = false
        })

      },
      //获取选中文本
      selectText() {
        let selection = getSelection()
        console.info(selection)
        if (selection && !this.disabled) {
          let range = selection.getRangeAt(0)
          console.info(range)
          if (range.startContainer === range.endContainer) {
            let tip = '不跨节点'
            let anchorNode = range.startContainer
            let bold = document.createElement('span')
            bold.classList.add('bold')
            this.note_form.note_id = this.$uuid.v1()
            bold.setAttribute('id', this.note_form.note_id)
            if (range.endOffset - range.startOffset === anchorNode.length) {
              console.info(tip + '全选')
              bold.innerText = anchorNode.wholeText
              this.replace = {
                val: anchorNode,
                replaceVal: [bold]
              }
            } else {
              console.info(tip + '选中一部分')
              let start = document.createTextNode(anchorNode.substringData(0, range.startOffset))
              let end = document.createTextNode(anchorNode.substringData(range.endOffset, anchorNode.length))
              bold.innerText = anchorNode.substringData(range.startOffset, range.endOffset - range.startOffset)
              this.replace = {
                val: anchorNode,
                replaceVal: [start, bold, end]
              }
            }
            this.note_form.original_text = bold.innerText
          } else {
            let tip = '跨节点'
            let startNode = range.startContainer
            let endNode = range.endContainer
          }
        } else {
          console.error('无法获取选中文本')
        }
      },
      //查找笔记
      findNote(){
        let that=this
        this.GLOBAL.fetchGet(`/v1/api/notes/list/${this.activeContent.id}`,{},function(res) {
            if(res.code==='200'){
              that.noteList=[]

              res.data.data.forEach(item=>{
                let obj={
                  id: item.noteId,
                  title: item.noteTitle,
                  content: item.noteContent,
                  isActive:item.noteId===that.$route.query.noteId
                }
                that.noteList.push(obj)
                if(item.noteId===that.$route.query.noteId){
                  that.jump(obj)
                  that.$nextTick(() => {
                    let ele = document.querySelector('div[class$=active_card]')
                    if (ele) {
                      ele.scrollIntoView({
                        block: 'center'
                      })
                    }
                  })
                }
              })
            }else{
              that.$message.error(that.$t('error_500').toString())
            }
        })
      }
    },
    mounted() {
      let that = this
      this.$nextTick(() => {
        if(this.activeContent) {
          that.queryRating()
          that.findNote()
        }

      })

      this.activeName = this.$store.state.read.activeName


      addEventListener('keyup', function(event) {
        //监听查找操作
        if (event.shiftKey && 'F' === event.key.toUpperCase()) {
          event.preventDefault()
          that.showSearch = !that.showSearch
        } else if ('ESCAPE' === event.key.toUpperCase()) {
          that.showSearch = false
        }
        if(that.activeContent) {
          that.updateFind(that.showSearch)
        }
      }, true)
    }

  })
</script>
<style>
  .heightlight {
    color: #74f2ff;
    font-size: larger;
  }

  .active_card{
    border: 1px solid black;
  }

  .search-light {
    color: blue;
  }

  .choose-search-text {
    animation: changeshadow 1s ease-in infinite;
  }

  @keyframes changeshadow {
    0% {
      text-shadow: 0 0 4px blue
    }
    50% {
      text-shadow: 0 0 40px blue
    }
    100% {
      text-shadow: 0 0 4px blue
    }
  }

  .choose-note {
    cursor: pointer;
  }

  pre {
    overflow-x: hidden;
  }

  .content {
    height: 600px;
    overflow-y: auto;
  }

  .note-list {
    height: 600px;
    overflow-y: auto;
  }

  .text {
    font-size: 14px;
  }

  .item {
    margin-bottom: 18px;
  }

  .clearfix::before,
  .clearfix::after {
    display: table;
    content: "";
  }

  .clearfix::after {
    clear: both
  }

  .star-button {
    width: 100%;
  }

  .star-icon i {
    font-size: 30px;
  }

  .w-100 {
    width: 100%;
  }

  .el-input.el-input--prefix > input[type='text'] {
    height: 40px;
  }

  .img {
    height: 30px;
    width: 30px;
    vertical-align: text-top;
  }


</style>
