<template>
  <div id="mapbox">
    <!-- 地图 -->
    <div id="mapview" class="map">
    </div>

    <!-- popup -->
    <div>
      <!-- PC端popup -->
      <div id="pcPopup" class="ol-popup" v-if="this.$store.state.isMobile === false">
        <div id="popup-content">
          <b-table-simple>
            <b-thead head-variant="light">
              <tr>
                <b-th colspan="2">
                  {{popupData.type}}
                  <span class="float-right" id="popup-closer" @click="closePopup($event.srcElement)"><i class="fa fa-times fa-lg" aria-hidden="true"></i></span>
                </b-th>
              </tr>
            </b-thead>
            <b-tbody>
              <tr>
                <!-- <b-th style="width:60px"></b-th> -->
                <b-td><strong>名称:</strong> <code>{{popupData.info.title}}</code></b-td>
              </tr>
              <tr v-show="popupData.type !== '文化设施'">
                <!-- <b-th>时间:</b-th> -->
                <!-- <b-td><strong>时间:</strong> {{popupData.info.time}}</b-td> -->
              </tr>
              <tr>
                <!-- <b-th>概要:</b-th> -->
                <b-td><strong>概要:</strong> <code>{{popupData.info.time}}</code>,{{popupData.info.content|ellipsis}}</b-td>
                <b-link v-if="popupData.info.url" :href="popupData.info.url" target='_blank'>
                  <<< 发布者：{{this.store.}}>>>
                  <i class="fa fa-arrow-right" aria-hidden="true"></i>
                </b-link>
              </tr>
            </b-tbody>
          </b-table-simple>
          <!-- <b-button v-if="popupData.info.url" class="float-right" variant="info" size="sm" :href="popupData.info.url" target='_blank'>详情
            <i class="fa fa-arrow-right" aria-hidden="true"></i>
          </b-button> -->
        </div>
      </div>

      <!-- Mobile端popup -->
      <div id="mobilePopup" v-else v-show="isShow">
         <div class="mobilePop-header">
              <strong>{{popupData.type}}</strong>
               <span class="float-right" id="popup-closer" @click="closePopup($event.srcElement)"><i class="fa fa-times fa-lg" aria-hidden="true" id="popup-closer"></i></span>
          </div>
        <!-- <b-table-simple>
           <b-thead head-variant="light">
              <tr>
                <b-th colspan="2">
                  {{popupData.type}}
                  <span class="float-right" id="popup-closer" @click="closePopup($event.srcElement)"><i class="fa fa-times fa-lg" aria-hidden="true" id="popup-closer"></i></span>
                </b-th>
              </tr>
            </b-thead>
        </b-table-simple> -->
        <div class="mobilePop-body">
          <b-table-simple>
            <!-- <b-thead head-variant="light">
              <tr>
                <b-th colspan="2">
                  {{popupData.type}}
                  <span class="float-right" id="popup-closer" @click="closePopup($event.srcElement)"><i class="fa fa-times fa-lg" aria-hidden="true" id="popup-closer"></i></span>
                </b-th>
              </tr>
            </b-thead> -->
             <b-tbody>
              <tr>
                <!-- <b-th style="width:60px"></b-th> -->
                <b-td><strong>名称:</strong> <code>{{popupData.info.title}}</code></b-td>
              </tr>
              <tr v-show="popupData.type !== '文化设施'">
                <!-- <b-th>时间:</b-th> -->
                <b-td><strong>时间:</strong> {{popupData.info.time}}</b-td>
              </tr>
              <tr>
                <!-- <b-th>概要:</b-th> -->
                <b-td><strong>概要:</strong> {{popupData.info.content}}</b-td>
              </tr>
            </b-tbody>
          </b-table-simple>
        </div>
        <div class="mobilePop-footer">
          <b-button  v-if="popupData.info.url" class="mr-4  mb-4" variant="info" size="sm" :href="popupData.info.url" target='_blank'>详情
            <i class="fa fa-arrow-right" aria-hidden="true"></i>
          </b-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// jquery
// import $ from 'jquery'

// openlayer
import 'ol/ol.css'
import {Map, View} from 'ol'
import * as Extent from 'ol/extent'
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer'
import * as olProj from 'ol/proj'
import {Point, LineString} from 'ol/geom'
import {defaults as defaultInteractions} from 'ol/interaction'
import Feature from 'ol/Feature'
// import GeoJSON from 'ol/format/GeoJSON'
import * as control from 'ol/control'
import {Style, Icon, Stroke} from 'ol/style'
import {Vector as VectorSource} from 'ol/source'
// import TileSource from 'ol/source/TileWMS'
import XYZ from 'ol/source/XYZ'
import Overlay from 'ol/Overlay'

// import OSM from 'ol/source/OSM'

// eventBus公共实例
import bus from '../../static/js/eventBus'

// icon
import culture from '../assets/icon/culture.png'
import info from '../assets/icon/info.png'
import report from '../assets/icon/report.png'

// 地图对象
// eslint-disable-next-line
var map = null

export default {
  name: 'Map',
  data () {
    return {
      noticeStyles: { //  通知标注 样式
        Point: new Style({
          image: new Icon({
            crossOrigin: 'anonymous',
            src: info,
            scale: 0.2
          })
        }),
        LineString: new Style({
          stroke: new Stroke({
            color: '#d81e06',
            width: 6
          })
        })
      },

      reportStyles: { //  报道标注 样式
        Point: new Style({
          image: new Icon({
            crossOrigin: 'anonymous',
            src: report,
            scale: 0.2
          })
        }),
        LineString: new Style({
          stroke: new Stroke({
            color: '#d4237a',
            width: 6
          })
        })
      },

      cultureStyles: { //  文化标注 样式
        Point: new Style({
          image: new Icon({
            crossOrigin: 'anonymous',
            src: culture,
            scale: 0.2
          })
        }),
        LineString: new Style({
          stroke: new Stroke({
            color: '#c1296db',
            width: 6
          })
        })
      },
      // popup的overlay对象
      popup: null,
      popupData: { //  PC端 地图弹出框信息
        type: '',
        info: ''
      },
      // mobile端popup控制
      isShow: false
    }
  },
  methods: {
    /**
     * @description:构建地图
     * @returns {void}
     */
    initMap: function () {
      // 根据设备的不同设置地图范围
      const MOBILE = [11591641.84, 3587409, 11594985.96, 3594153.87]
      const PC = [11589871, 3589520, 11599383, 3592463]
      let extent = this.$store.state.isMobile ? MOBILE : PC

      map = new Map({
        target: 'mapview',
        layers: [
          //  天地图底图图层
          new TileLayer({
            source: new XYZ({
              url: 'http://t4.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=a7baca459fe5be059d34849072e84fd0'
            })
          }),
          //  天地图标注图层
          new TileLayer({
            source: new XYZ({
              url: 'http://t4.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=a7baca459fe5be059d34849072e84fd0'
            })
          })
          // new TileLayer({
          //   source: new TileSource({
          //     url: 'http://cn-gz-ali-1.sakurafrp.com:10265/geoserver/CDUT/wms',
          //     crossOrigin: 'anonymous',
          //     params: {
          //       LAYERS: 'cdut',
          //       TILED: true
          //     },
          //     servertype: 'geoserver',
          //     transition: 0
          //   })
          // })
        ],
        interactions: defaultInteractions({
          pinchRotate: false // 移动端禁止地图旋转
        }),
        view: new View({
          center: olProj.fromLonLat([104.1429, 30.6778]),
          zoom: 15,
          extent: extent
        }),
        controls: control.defaults().extend([
          // new control.MousePosition() // 实例化坐标拾取控件，并加入地图
        ])
      })
      map.updateSize()
    },

    /**
     * @description:构建popup覆盖层
     * @returns {void}
     */
    initOverLay: function () {
      var container = document.getElementById('pcPopup')

      this.popup = new Overlay({
        element: container,
        autoPan: true,
        autoPanAnimation: {
          duration: 250
        }
      })
      map.addOverlay(this.popup)
    },

    /**
     * @description:绘制要素
     * @param {String} title:图层名称
     * @param {Object of {GeoJSON,String,String}} msg:要素信息(含有geometry,id,type)
     * @param {String} type:所属类别, 文化类：'culture' / 消息类: 'notice'
     * @param {Boolean} isRefresh:是否刷新图层
     * @param {Boolean} isLoacate:是否缩放到要素
     * @returns {void}
     */
    printFeature: function (title, msg, type, isRefresh = false, isLocate = false) {
      // 初始化图层
      var layer = this.getLayerByTitle(title)
      if (layer !== null) {
        // 非首次调用，清除图层中的要素
        if (isRefresh) {
          layer.getSource().clear()
        }
      } else {
        // 首次调用，创建图层
        layer = new VectorLayer({
          title: title,
          source: new VectorSource({
          })
        })
        map.addLayer(layer)
      }

      // GeoJSON格式转换为ol.feature格式，样式装载
      var geometry = msg.geometry
      var style
      switch (type) {
        case 'notice':
          style = this.noticeStyles
          break
        case 'report':
          style = this.reportStyles
          break
        case 'culture':
          style = this.cultureStyles
          break
      }
      var feature = this.GeoJSON_to_Feature(geometry, style)

      // 要素属性装载
      feature.set('id', msg.id)
      feature.set('type', type)

      // 要素装载入图层
      layer.getSource().addFeature(feature)

      // 缩放至要素
      if (isLocate) {
        this.locateAtFeature(feature)
      }
    },

    /**
     * @description:根据 GeoJSON 格式数据绘制要素
     * tips:目前支持类型：Point,LineString；后续可能增加类型：MutiPoint,MutiLineString,Polygn,MutiPolygn
     * @param {GeoJSON} geometry:GeoJSON格式数据
     * @param {Array of ol.Style} styles:样式
     * @returns {ol.feature} 返回由GeoJSON转换成的配制好样式的ol.feature
     */
    GeoJSON_to_Feature: function (geometry, styles) {
      if (!geometry.type) {
        console.log('printFromGeoJSON 所输入的GeoJSON不符合规范')
        return
      }

      var feature = null
      // 按geometry.type类型创建要素并赋予样式
      switch (geometry.type) {
        case 'Point':
          feature = new Feature({
            geometry: new Point(olProj.fromLonLat(geometry.coordinates, 'EPSG:3857')),
            id: 1
          })
          feature.setStyle(styles.Point)
          break
        case 'LineString':
          for (let i = 0; i < geometry.coordinates.length; i++) {
            geometry.coordinates[i] = olProj.fromLonLat(geometry.coordinates[i])
          }
          feature = new Feature({
            geometry: new LineString(geometry.coordinates)
          })
          feature.setStyle(styles.LineString)
          break
        default:
          console.log('printFromGeoJSON不支持该"' + geometry.type + '"类型')
          return
      }

      return feature
    },

    /**
     * @description:缩放至要素
     * @param {ol.Feature} feature:要素
     * @param {int} zoom: 缩放级别
     * @return {void}
     */
    locateAtFeature: function (feature, zoom = 18) {
      let view = map.getView()
      view.setZoom(zoom)
      view.setCenter(Extent.getCenter(feature.getGeometry().getExtent()))
    },

    /**
     * @description:获取并渲染最近若干天的报道
     * @param {int} day: 天数
     * @returns {void}
     */
    loadRecentReports: function (day) {
      var that = this
      this.$axios
        .post('/report/recent', {
          day: day
        })
        .then(res => {
          res.data.forEach(item => {
            that.printFeature('reportLayer', item, 'report')
          })
        })
    },

    /**
     * @description:获取并渲染最近若干天的通知
     * @param {int} day: 天数
     * @returns {void}
     */
    loadRecentNotices: function (day) {
      var that = this
      this.$axios
        .post('/notice/recent', {
          day: day
        })
        .then(res => {
          res.data.forEach(item => {
            that.printFeature('noticeLayer', item, 'notice')
          })
        })
    },

    /**
     * @description:获取并渲染所有文化设施
     * @returns {void}
     */
    loadCulture: function () {
      var that = this
      this.$axios
        .post('/culture/all')
        .then(res => {
          res.data.forEach(e => {
            that.printFeature('cultureLayer', e, 'culture')
          })
        })
    },

    /**
     * @description: 地图要素点击事件
     * @return {void}
     */
    mapClick: function () {
      var that = this

      // 根据设备类型设置点击事件
      var clickFun = this.$store.state.isMobile ? mobileClickFun : pcClickFun
      map.on('singleclick', clickFun)

      function mobileClickFun (e) {
        var feature = map.forEachFeatureAtPixel(e.pixel, function (feature) {
          return feature
        })
        if (feature) {
          var id = feature.get('id')
          switch (feature.get('type')) {
            case 'notice':
              that.loadNoticeByID(id)
              break
            case 'report':
              that.loadReportByID(id)
              break
            case 'culture':
              that.loadCultureByID(id)
              break
          }
          that.locateAtFeature(feature)
          that.isShow = true
        } else {
          that.closePopup()
        }
      }

      async function pcClickFun (e) {
        var coordinate = e.coordinate
        var feature = map.forEachFeatureAtPixel(e.pixel, feature => {
          return feature
        })
        if (feature) {
          that.setPopupPosition(coordinate)
          //  根据id获取要素信息
          var id = feature.get('id')
          switch (feature.get('type')) {
            case 'notice':
              await that.loadNoticeByID(id)
              break
            case 'report':
              await that.loadReportByID(id)
              break
            case 'culture':
              await that.loadCultureByID(id)
              break
          }
        } else {
          that.closePopup()
        }
      }
    },

    /**
     * @description: ol封装：通过title属性获取图层
     * @param {title} 图层title值
     * @return {layer / null}
    */
    getLayerByTitle: function (title) {
      var layers = map.getLayers().array_
      for (let i = 0; i < layers.length; i++) {
        if (layers[i].get('title') === title) {
          return layers[i]
        } else {
          continue
        }
      }
      return null
    },

    /**
     * @description:通过id查询载入通知信息
     */
    loadReportByID: async function (id) {
      var that = this
      var res

      await this.$axios
        .post('/report/detail', {
          id: id
        })
        .then(response => {
          that.popupData.info = response.data
          that.popupData.type = '新闻报道'

          res = response.data
        })

      return res
    },

    /**
     * @description:通过id查询载入通知信息
     */
    loadNoticeByID: async function (id) {
      var that = this
      var res
      await this.$axios
        .post('/notice/detail', {
          id: id
        })
        .then(response => {
          that.popupData.info = response.data
          that.popupData.type = '活动通知'

          res = response.data
        })

      return res
    },

    /**
     * @description:通过id 查询载入文化信息
     */
    loadCultureByID: async function (id) {
      var that = this
      var res

      await this.$axios
        .post('/culture/detail', {
          id: id
        })
        .then(response => {
          response.data.content = response.data.content.join('')
          that.popupData.info = response.data
          that.popupData.type = '文化设施'

          res = response.data
        })

      return res
    },

    /**
     * @description:设置并聚焦到popup的显示位置
     * @param {ol.coordinate}坐标
     * @param {ol.zoom}缩放级别
     */
    setPopupPosition: function (coordinate, zoom = 18) {
      this.popup.setPosition(coordinate)
      var view = map.getView()
      view.setCenter(coordinate)
      view.setZoom(zoom)
    },

    /**
     * @description:根据pc端与mobile端不同的popup关闭事件
     * @param {DOM} dom:点击按钮dom
     */
    closePopup: function (dom) {
      if (this.$store.state.isMobile) {
        this.isShow = false
      } else {
        this.popup.setPosition(undefined)

        // 消除按钮聚焦
        if (dom) {
          dom.blur()
        }
      }
      return false
    },

    /**
     * @description: eventBus的bus.$on 触发事件汇总
     */
    busOnAction: function () {
      var that = this

      // mobile端：绘制报道标识与底部弹窗
      bus.$on('showReportDetail', async id => {
        that.loadReportByID(id)
          .then(res => {
            that.printFeature('markLayer', res, 'report', true, true)
            that.isShow = true
          })
      })

      // PC端：根据各个类型的id 绘制地图标识与popup弹窗
      bus.$on('printMapMark', async msg => {
        let data
        let id = msg.id
        switch (msg.type) {
          case 'notice':
            await that.loadNoticeByID(id)
              .then(res => {
                data = res
              })
            break
          case 'report':
            await that.loadReportByID(id)
              .then(res => {
                data = res
              })
            break
          case 'culture':
            await that.loadCultureByID(id)
              .then(res => {
                data = res
              })
            break
        }
        that.printFeature('markLayer', data, msg.type, true, false)

        //  显示popup
        var feature = that.getLayerByTitle('markLayer').getSource().getFeatures()[0]
        var coord = feature.getGeometry().getCoordinates()
        that.setPopupPosition(coord)
      })

      // 刷新地图标识
      bus.$on('refreshMap', () => {
        map.removeLayer(that.getLayerByTitle('noticeLayer'))
        map.removeLayer(that.getLayerByTitle('reportLayer'))
        map.removeLayer(that.getLayerByTitle('markLayer'))
        that.loadRecentNotices(7)
        that.loadRecentReports(7)
        that.closePopup()
      })
    }
  },
  mounted () {
    this.initMap()
    this.initOverLay()
    this.busOnAction()
    this.loadRecentReports(7)
    this.loadRecentNotices(7)
    this.loadCulture()
    this.mapClick()
  },
  filters: {
    // 超过100位显示省略号
    ellipsis: function (value) {
      if (!value) return ''
      if (value.length > 70) {
        return value.slice(0, 70) + '...'
      }
      return value
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#mapview{
  width: 100%;
  height: 100%;
  position: absolute;
}
#mobilePopup {
  position: absolute;
  height: 45%;
  width:100%;
  background: white;
  bottom: 0px;
  border-radius: 15px;
  z-index: 3;
}
.mobilePop-header{
  padding: 12px;
  background:rgba(222,226,230,0.5)
}
.mobilePop-body {
  height: calc(100%);
  overflow: auto;

}
.mobilePop-footer {
  position: absolute;
  bottom: 0px;
  right: 0px;
  /* height: 31px; */
  /* background: yellowgreen; */
  /* background:(255,255,255,0.5); */
}
.ol-popup {
  position: absolute;
  background-color: white;
  box-shadow: 0 1px 4px rgba(0,0,0,0.2);
  padding: 15px;
  border-radius: 10px;
  border: 1px solid #cccccc;
  bottom: 12px;
  left: -50px;
  min-width: 280px;
  font-size:13px
}
.ol-popup:after, .ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}
.ol-popup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}
.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}
</style>
