/**
 * openlayer工具类
 * 2021-4-20
 */
import "ol/ol.css";
import { Map, View, Overlay } from "ol";
import TileGrid from 'ol/tilegrid/TileGrid';
import { boundingExtent, getCenter as olGetCenter } from 'ol/extent';
import WMTSTileGrid from 'ol/tilegrid/WMTS';
import * as olControl from 'ol/control';
import { get as getProjection, transform, fromLonLat, Projection } from 'ol/proj';
import { ImageArcGISRest, Vector as VectorSource, XYZ, ImageStatic, WMTS as WMTSSource } from 'ol/source';
import { Image as ImageLayer, Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import GeoJSON from 'ol/format/GeoJSON'
import * as olRender from 'ol/render';
import WKT from 'ol/format/WKT'
import { Style as olStyle, Stroke as olStroke, Circle as olCircle, Fill as olFill, Icon as olIcon, RegularShape as olRegularShape, Text as olText } from 'ol/style'
import Feature from "ol/Feature"
import { Point, LineString } from 'ol/geom'
import { defaults as defaultControls, OverviewMap, FullScreen, ScaleLine, ZoomSlider, MousePosition, ZoomToExtent } from 'ol/control'

import polylineJSON from '../constant/polyline.json'
import { getTurfArcFeatures, degreesToRadians, lineChunk } from './turf_util'
import arrowPNG from "../assets/img/visualizing/arrow.png";
import mapPNG from "../assets/img/visualizing/map.png";
import zwtpPNG from "../assets/img/dfzy/zwtp.png";

//#region 全局变量
// 地图投影
const PROJECTION = getProjection('EPSG:4326');
var turfFormat = new GeoJSON();
var overlay = null;
//点常量样式
var DOTSTYLE = new olStyle({
    image: new olRegularShape({
        stroke: new olStroke({
            color: 'red',
            width: 6.0
        }),
        radius: 5,
        radius2: 2,
        points: 5
    })
});
//#endregion

//#region 底图
/**
 * wmts服务()
 * @param {*} Id 
 * @param {*} options 
 * @returns 
 */
function initWMTSMap(Id, options = {}) {
    // var baseUrl = "http://192.168.168.100:8080/geoserver/gwc/service/wmts";
    const baseUrl = 'api_wmts/geoserver/gwc/service/wmts';
    var resolutions = [0.3515624987403729, 0.17578124937018644, 0.08789062468509322, 0.04394531115281611];
    //缺省参数
    // options.extent = options.extent || [-180, -90, 180, 90];
    options.level = options.level || 0;
    options.center = options.center || [120, 30];
    var baseParams = ['VERSION', 'LAYER', 'STYLE', 'TILEMATRIX', 'TILEMATRIXSET', 'SERVICE', 'FORMAT'];
    var params = {
        'VERSION': '1.0.0',
        'LAYER': 'test',
        'STYLE': '',
        'TILEMATRIX': ['EPSG:4326_test:0', 'EPSG:4326_test:1', 'EPSG:4326_test:2', 'EPSG:4326_test:3'],
        'TILEMATRIXSET': 'EPSG:4326_test',
        'SERVICE': 'WMTS',
        'FORMAT': 'image/jpeg'
    };
    var url = baseUrl + '?';
    for (var key in params) {
        if (baseParams.indexOf(key.toUpperCase()) < 0) {
            url = url + key + '=' + params[key] + '&';
        }
    }
    url = url.slice(0, -1);
    var projection1 = new Projection({
        code: 'EPSG:4326',
        units: '',
        axisOrientation: 'neu'
    });
    //源
    var source = new WMTSSource({
        url: url,
        layer: params['LAYER'],
        matrixSet: params['TILEMATRIXSET'],
        format: params['FORMAT'],
        projection: projection1,
        tileGrid: new WMTSTileGrid({
            tileSize: [256, 256],
            extent: [-400.0, -139.99999806521294, 229.99999774274818, 399.9999999999998],
            origin: [-400.0, 399.9999999999998],
            resolutions: resolutions,
            matrixIds: params['TILEMATRIX']
        }),
        style: params['STYLE'],
        wrapX: true
    });
    //图层
    var layer = new TileLayer({
        source: source
    });
    // 定义地图
    let map = new Map({
        // controls: ol.control.defaults({attribution: false, zoom: false, rotate: false}),//隐藏部件
        target: Id,
        layers: [layer],
        view: new View({
            center: options.center,
            resolutions: resolutions,
            zoom: options.level,
            projection: projection1,
            extent: [-400.0, -139.99999806521294, 229.99999774274818, 399.9999999999998]  //视图可达范围
        }),
        controls: defaultControls().extend([
            new ZoomSlider(),// 往地图增加滑块缩放控件
            new FullScreen({ tipLabel: '全屏' }),// 全屏控件
            new ScaleLine(),//比例尺
        ])
    });
    listenPostRender(layer, map);
    return map;
}

/**
 * arcgis tilelayer图层
 * @param {*} Id dom元素的id
 * @param {*} options 
 * @returns 
 */
function initTileMap(Id, options = {}) {
    //缺省参数
    options.extent = options.extent || [-180, -90, 180, 90];
    options.level = options.level || 0;
    options.center = options.center || [120, 30];
    //定义原点和分辨率，可在rest缓存服务中找到
    const origin = [-400.0, 399.9999999999998];
    const resolutions = [
        0.3515624987403729,
        0.17578124937018644,
        0.08789062468509322,
        0.04394531115281611
    ];
    // const url = "http://101.95.167.134:6080/arcgis/rest/services/NanHai_T2/MapServer/tile/{z}/{y}/{x}",
    // const url = "http://192.168.168.110:6080/arcgis/rest/services/WorldYX/MapServer/tile/{z}/{y}/{x}";
    // const url = "http://192.168.168.110:6080/arcgis/rest/services/WorldBlue/MapServer/tile/{z}/{y}/{x}";
    const url = 'api_map/arcgis/rest/services/WorldYX/MapServer/tile/{z}/{y}/{x}'
    // const url = 'api_map/arcgis/rest/services/WorldBlue/MapServer/tile/{z}/{y}/{x}'
    // 定义瓦片
    return new Map({
        // controls: ol.control.defaults({attribution: false, zoom: false, rotate: false}),//隐藏部件
        target: Id,
        layers: [
            // 瓦片图层
            new TileLayer({
                preload: 1,
                //单个底图加载切片的范围
                // extent: options.extent,
                source: new XYZ({
                    // 定义瓦片
                    tileGrid: new TileGrid({
                        tileSize: 256,
                        origin: origin,
                        // extent: fullExtent,
                        resolutions: resolutions
                    }),
                    // 坐标
                    projection: PROJECTION,
                    url: url,
                })
            })
        ],
        view: new View({
            center: options.center,
            resolutions: resolutions,
            // 注意：此处指定缩放级别不能通过zoom来指定，指定了也无效，必须通过resolution来指定
            // 官方API说明：
            // Resolutions to determine the resolution constraint.
            // If set the maxResolution, minResolution, minZoom, maxZoom, and zoomFactor options are ignored.
            resolution: resolutions[options.level],

            // zoom: 4,
            // minZoom:1,
            // maxZoom: 20,
            projection: PROJECTION,
            extent: options.extent  //视图可达范围
        }),
    });
}

/**
 * arcgis image图层
 * @param {*} Id dom元素的id
 * @param {*} options 
 */
function initImageMap(Id, options = {}) {
    //缺省参数
    options.extent = options.extent || [-180, -90, 180, 90];
    options.level = options.level || 4;
    options.center = options.center || [120, 27];

    const url = 'api_map/arcgis/rest/services/World_YX/MapServer'
    let layer = new ImageLayer({
        preload: 1,
        extent: options.extent,
        source: new ImageArcGISRest({
            ratio: 1,
            params: {},
            url: url
        })
    });

    let map = new Map({
        layers: [
            layer
        ],
        target: Id,
        view: new View({
            extent: options.extent,
            center: options.center,
            zoom: options.level,
            projection: PROJECTION,
        }),
        controls: defaultControls().extend([
            new ZoomSlider(),// 往地图增加滑块缩放控件
            new FullScreen({ tipLabel: '全屏' }),// 全屏控件
            new ScaleLine(),//比例尺
            // new ZoomToExtent(),//E标识，恢复到四至
            // new MousePosition(),// 坐标拾取控件
            // new OverviewMap({collapsed: false})// 鹰眼控件
        ])
    });
    //切换专网不使用这个
    // listenPostRender(layer, map);
    // arrow(layer, map);
    // showLineChunk(map);
    return map;
}

function initStaticImageMap(Id, options = {}) {
    //缺省参数
    options.extent = options.extent || [-180, -90, 180, 90];
    options.level = options.level || 4;
    options.center = options.center || [120, 27];
    var center = transform(options.center, 'EPSG:4326', 'EPSG:3857');
    var extent = [
        center[0] - 1920 * 1000 / 2,
        center[1] - 1080 * 1000 / 2,
        center[0] + 1920 * 1000 / 2,
        center[1] + 1080 * 1000 / 2
    ];
    let layer = new ImageLayer({
        source: new ImageStatic({
            url: mapPNG,
            imageExtent: extent,

        })
    });

    let map = new Map({
        layers: [
            layer
        ],
        target: Id,
        view: new View({
            // extent: options.extent,
            center: center,
            zoom: 6,
            // projection: projection,
        }),
        controls: defaultControls().extend([
            new ZoomSlider(),// 往地图增加滑块缩放控件
            new FullScreen({ tipLabel: '全屏' }),// 全屏控件
            new ScaleLine(),//比例尺
        ])
    });
    // listenPostRender(layer, map);
    // arrow(layer, map);
    // showLineChunk(map);
    return map;
}

/**
 * 天地图
 * @param {*} Id 
 * @param {*} options 
 * @returns 
 */
function initTDTMap(Id, options = {}) {
    //天地图影响图层
    const tian_di_tu_satellite_layer = new TileLayer({
        title: "天地图卫星影像",
        source: new XYZ({
            url: "http://t4.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=560906895a77209618ca101f4335c623"
        })
    });
    const tian_di_tu_road_layer = new TileLayer({
        title: "天地图路网",
        source: new XYZ({
            url: "http://t4.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=560906895a77209618ca101f4335c623"
        })
    });
    const tian_di_tu_annotation = new TileLayer({
        title: "天地图文字标注",
        source: new XYZ({
            url: 'http://t4.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=560906895a77209618ca101f4335c623'
        })
    });
    //缺省参数
    options.level = options.level || 0;
    options.center = options.center || [120, 27];
    let map = new Map({
        controls: olControl.defaults({ attribution: false, zoom: false, rotate: false }),//隐藏部件
        target: Id,
        layers: [
            // 瓦片图层
            tian_di_tu_satellite_layer,
            // tian_di_tu_road_layer,
            tian_di_tu_annotation,
        ],
        view: new View({
            center: options.center,
            // resolution: resolutions[options.level],
            projection: PROJECTION,
            zoom: 5,
        }),
        controls: defaultControls().extend([
            new ZoomSlider(),// 往地图增加滑块缩放控件
            new FullScreen({ tipLabel: '全屏' }),// 全屏控件
            new ScaleLine(),//比例尺
            // new ZoomToExtent(),//E标识，恢复到四至
            // new MousePosition(),// 坐标拾取控件
            // new OverviewMap({collapsed: false})// 鹰眼控件
        ])
    });
    listenPostRender(tian_di_tu_satellite_layer, map);
    return map;
}
//#endregion

//#region 浮动层
function getOverlay(titleStr, bodyStr) {
    if (!document.getElementById("popup")) {
        let dom_str = `<div id="popup" class="ol-popup">
                            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
                            <div id="popup-title" class="popup-title">${titleStr}</div>
                            <div id="popup-content" class="popup-content"></div>
                       </div>`;
        let popup_parent = document.createElement("div");
        popup_parent.innerHTML = dom_str;
        let popup = popup_parent.firstElementChild;
        let popup_close = popup.firstElementChild;
        popup_close.addEventListener("click", function () {
            overlay.setPosition(undefined);
        })
        let popup_content = popup.lastElementChild;
        popup_content.innerHTML = bodyStr;
        overlay = new Overlay({
            element: popup,
            // autoPan: true,
            // autoPanAnimation: {
            //     duration: 250   //当Popup超出地图边界时，为了Popup全部可见，地图移动的速度.
            // }
        });
    } else {
        document.getElementById("popup-title").innerHTML = titleStr;
        document.getElementById("popup").lastElementChild.innerHTML = bodyStr;
    }
    return overlay;
}
//#endregion

//#region 创建图层
function createVectorLayer(options = {}) {
    let layer = new VectorLayer({
        source: new VectorSource({
            features: []
        }),
    });
    layer.setProperties(options);
    return layer;
}
//#endregion

//#region 创建要素
function createFeature(cordination, properties, iconStyleOption) {
    let feature = new Feature({
        geometry: new Point(cordination)
    });
    feature.setProperties(properties);
    if (iconStyleOption.src) {
        feature.setStyle(createIconStyle(iconStyleOption));
    } else {
        feature.setStyle(dotStyle);
    }
    return feature;
}

function createPolygonFeature(wkt, properties) {
    let feature = new WKT().readFeature(wkt);
    feature.setProperties(properties);
    feature.setStyle(styleFunction);
    return feature;
}

function createPolylineFeature(wkt, properties, color) {
    let feature = new WKT().readFeature(wkt);
    feature.setProperties(properties);
    color && feature.setStyle((feature) => {
        var styles = [];
        styles.push(new olStyle({
            stroke: new olStroke({
                width: 7,
                color: color,
                lineDash: [1, 2, 3, 5, 6, 10]
            }),
            text: new olText({
                text: feature.get("name"),
                font: "bold 15px sans-serif",
                fill: new olFill({ color: color }),
                backgroundFill: new olFill({
                    color: "rgba(255,255,255,0)",
                }),
                textAlign: "center",
                textBaseline: "bottom",
                placement: "line"
            })
        }));
        return styles;
    });
    return feature;
}
//#endregion

//#region 样式
//图标样式
function createIconStyle(option) {
    //图标放大或缩小比例
    option.scale = option.scale || 0.1;
    //图标锚点位置
    // iconStyleOption.anchor = iconStyleOption.anchor || [0.5, 0.5];
    //方位角
    option.rotation = option.rotation || 0;
    //图标图标地址，webpack中需要import引用
    option.src = option.src || zwtpPNG;
    return new olStyle({
        image: new olIcon(option)
    });
}
//样式函数
function styleFunction(feature) {
    var styles = [];
    styles.push(new olStyle({
        stroke: new olStroke({
            width: 7,
            color: 'grey',
            lineDash: [1, 2, 3, 5, 6]
        })
    }));

    let dotStyle = createIconStyle({ src: feature.get("src"), scale: 0.2 });
    dotStyle.setGeometry(new Point(getCenter(feature.getGeometry())));
    styles.push(dotStyle);
    return styles;
}
//#endregion

//#region 工具方法
function getCenter(geometry) {
    var extent = boundingExtent(geometry.getCoordinates()[0][0]); //获取一个坐标数组的边界，格式为[minx,miny,maxx,maxy]
    return olGetCenter(extent);   //获取边界区域的中心位置
}
//#endregion

//#region 特殊效果函数
/**
 * 动态航线图
 * @param {*} layer 
 * @param {*} map 
 */
function listenPostRender(layer, map) {
    let arcStyle = new olStyle({
        stroke: new olStroke({
            color: [0, 186, 107, 0.7],
            width: 3
        })
    });
    let dotStyle = new olStyle({
        image: new olRegularShape({
            stroke: new olStroke({
                color: 'red',
                width: 6.0
            }),
            radius: 5,
            radius2: 2,
            points: 5
        })
    });

    let arcLinesFeature = [];
    let e = polylineJSON.data;
    for (let i = 0; i < e.length; i++) {
        if (e[i].wkt) {
            let tempF = getTurfArcFeatures(new WKT().readFeature(e[i]["wkt"]).getGeometry().getCoordinates(), {
                'from': e[i].name,
                'to': e[i].name,
                'resolution': multiple_x > 2 ? 80000 : null
            });
            arcLinesFeature.push(tempF);
        }
    }
    let multiple_x = window.screen.width / 1920;
    layer.on('postrender', (evt) => {
        let veContext = olRender.getVectorContext(evt);
        arcLinesFeature.forEach((item, index) => {
            //线
            veContext.drawFeature(item, arcStyle);
            let time = (evt.frameState.time - item.get('start')) / (multiple_x > 2 ? 50000 : 5000);
            let frac = time / 5 - index / arcLinesFeature.length;
            if (!item.get('start')) item.set('start', new Date().getTime());
            if (frac >= 1) {
                item.set('start', new Date().getTime());
                frac = 0;
            }
            // console.log(frac)
            // 动点
            let along = item.getGeometry().getCoordinateAt(frac);

            //设置动点的方位角
            let point1 = item.getGeometry().getCoordinateAt(frac - 0.01);
            let point2 = item.getGeometry().getCoordinateAt(frac + 0.01);
            // let pF = new Feature(new Point(along));
            // veContext.drawFeature(pF, dotStyle);
            let myImage = new Image(128, 128);
            myImage.src = arrowPNG;
            veContext.setStyle(new olStyle({
                image: new olIcon({
                    img: myImage,
                    imgSize: [128, 128],
                    scale: map.getView().getZoom() / 50,
                    rotation: degreesToRadians(point1, point2)
                })
            }));
            // console.log(map.getView().getZoom());
            veContext.drawGeometry(new Point(along));

        })
        map.render();
    });
}

/**
 * 动态箭头图
 * @param {*} layer 
 * @param {*} map 
 */
function arrow(layer, map) {
    let buttomPathStyle = new olStyle({
        stroke: new olStroke({
            color: [4, 110, 74],
            width: 28
        }),
    })
    let upperPathStyle = new olStyle({
        stroke: new olStroke({
            color: [0, 186, 107],
            width: 20
        }),
    })

    let street = new Feature({
        name: 'Null Island',
        population: 4000,
        rainfall: 500,
        geometry: new LineString(
            // [[113.136955877820221, 23.03567],[113.126955877820221, 23.13567],[112.93695587721, 23.13557] ]
            [[50.93695587721, 23.13557], [123.136955877820221, 23.03567]]
        )
    });

    let n = 0;
    //初始偏移量
    let offset = 0.01;
    layer.on('postrender', (evt) => {
        let vct = olRender.getVectorContext(evt);
        // 线边界
        vct.drawFeature(street, buttomPathStyle);
        vct.drawFeature(street, upperPathStyle);

        //最大层级下，150效果是最多2个点
        let numArr = Math.ceil((street.getGeometry().getLength() / map.getView().getResolution()) / 400);
        let points = [];
        //设置每个点的坐标
        for (let i = 0; i <= numArr; i++) {
            let fracPos = (i / numArr) + offset;
            if (fracPos > 1) fracPos -= 1;
            let pf = new Feature(new Point(street.getGeometry().getCoordinateAt(fracPos)));
            points.push(pf);
        }

        // n++;
        //确定方向并绘制
        street.getGeometry().forEachSegment((start, end) => {
            let line = new LineString([start, end]);
            points.forEach((item) => {
                let coord = item.getGeometry().getFirstCoordinate();
                let cPoint = line.getClosestPoint(coord);
                // if (Math.abs(cPoint[0] - coord[0]) < 1 && Math.abs(cPoint[1] - coord[1]) < 1) {
                if (line.intersectsCoordinate(coord)) {
                    let myImage = new Image(117, 71);
                    // myImage.src = '/static/img/arrow.png';
                    myImage.src = arrowPNG;
                    let dx = end[0] - start[0];
                    let dy = end[1] - start[1];
                    let rotation = Math.atan(dx / dy);
                    rotation = dy > 0 ? rotation : (Math.PI + rotation);
                    vct.setStyle(new olStyle({
                        image: new olIcon({
                            img: myImage,
                            imgSize: [117, 71],
                            scale: 0.15,
                            rotation: rotation
                        })
                    }))
                    vct.drawGeometry(item.getGeometry());
                }
            });
        })

        //每个点的每次移动量
        offset = offset + 0.001;
        //复位
        if (offset >= 1) {
            offset = 0.001
        }
        map.render()
    });
}

/**
 * 将指定的线段根据距离打断成多个线
 * @param {} map 
 */
function showLineChunk(map) {
    let data = [[111.93695587721, 23.13557], [113.126955877820221, 23.13567], [113.136955877820221, 22.03567]];
    var textLayer = new VectorLayer(
        {
            source: new VectorSource()
        }
    )
    map.addLayer(textLayer);

    var buttomPathStyle = new olStyle({
        stroke: new olStroke({
            color: [255, 255, 0],
            width: 20
        }),
    })
    var upperPathStyle = new olStyle({
        stroke: new olStroke({
            color: [220, 20, 60],
            width: 10
        }),
    })

    var upperPathStyle1 = new olStyle({
        stroke: new olStroke({
            color: [0, 0, 255],
            width: 10
        }),
    })

    let street = new Feature({
        geometry: new LineString(
            data
        )
    });
    street.setStyle(buttomPathStyle);

    textLayer.getSource().addFeature(street);

    let chunk = lineChunk(data);

    let features = turfFormat.readFeatures(chunk);
    for (let i in features) {
        if (i % 2 == 0) {
            features[i].setStyle(upperPathStyle);
        } else {
            features[i].setStyle(upperPathStyle1);
        }
        textLayer.getSource().addFeature(features[i]);
    }
}
//#endregion

export { initWMTSMap, initTDTMap, initTileMap, initImageMap, initStaticImageMap, createVectorLayer, getOverlay, createFeature, createPolygonFeature, createPolylineFeature, getCenter }