/**
 * 关于deck.gl的二次封装，由于很多功能使用起来不方便，因此进行二次封装
 * gaoxf
 */
import { Deck, _SunLight as SunLight, AmbientLight } from '@deck.gl/core';
import { GeoJsonLayer, PathLayer, TextLayer, IconLayer, PolygonLayer, ScatterplotLayer } from '@deck.gl/layers';
import { ScenegraphLayer } from '@deck.gl/mesh-layers';
import { PathStyleExtension, CollisionFilterExtension } from '@deck.gl/extensions';
import * as turf from '@turf/turf'
export default class DeckNew {
    constructor(props) {
        // const ambientLight = new AmbientLight({
        //     color: [128, 128, 0],
        //     intensity: 2.0
        // });
        this.deck = new Deck({
            ...props, effects: [new SunLight({
                timestamp: 1554927200000,
                color: [255, 0, 0],
                intensity: 1
            })]
        })


        this.initProps = { initialViewState: props.initialViewState };
        this.rotate = props.initialViewState.rotate || 0;
        this.pitch = props.initialViewState.pitch || 0
        this.zoom = props.initialViewState.zoom || 17
        this.mapLayers = [];
        this.carLayers = [];
        this.markerLayers = [];
        this.textLayers = [];
        this.polygonLayers = [];
        this.pathLayers = [];
        this.layerSortArray = {
            carLayer: [],
            textLayer: [],
            markerLayer: [],
            polygonLayer: [],
            pathLayer: ['avoidancePath', 'currentPath', 'nextPath'],
            bufferLayer: ['avoidancePathBuffer', 'pathBuffer', 'obstacleBuffer', 'currentCarBuffer', 'nextPathBuffer', 'currentPathBuffer'],
            baseLayer: ['dynamicLine', 'obstacle', 'dealSingle', 'barricade', 'lane', 'lanenode', 'centerLine', 'electronicFence', 'obstacles', 'staticobjs', 'wetArea', 'dumparea', 'parkspot', 'diggingworkarea', 'stationarea', 'runablearea'],

        }
        this.createGeoJsonLayer = this.createGeoJsonLayer.bind(this);
        this.createPathLayer = this.createPathLayer.bind(this);
        this.setRotation = this.setRotation.bind(this);
        this.createTextLayer = this.createTextLayer.bind(this);
        this.creatMarker = this.creatMarker.bind(this);
        this.creatCircle = this.creatCircle.bind(this);
        this.creatPolygon = this.creatPolygon.bind(this);
        this.setLayerSortName = this.setLayerSortName.bind(this);
        this.setPitch = this.setPitch.bind(this);
        this.removeLayer = this.removeLayer.bind(this);
    }
    initLayer() {
        this.layerSort()
        this.deck.setProps({
            layers: [...this.textLayers, ...this.carLayers, ...this.markerLayers, this.polygonLayers, ...this.mapLayers, ...this.pathLayers]
        })
    }

    setPitch(number) {
        this.pitch = number;
        let zoom = this.getZoom() || this.zoom
        this.deck.setProps({ initialViewState: {} })
        this.deck.setProps({
            initialViewState: {
                latitude: document.location.mapCenter[0],
                longitude: document.location.mapCenter[1],
                zoom: zoom,
                pitch: this.pitch,
                bearing: -this.rotate,
                // pickingRadius:5,
                controller: true
            }
        })
    }
    getZoom() {
        if (this.deck.viewState.hasOwnProperty('default-view')) {
            return this.deck.viewState['default-view'].zoom
        }
        return this.deck.viewState.zoom
    }
    getPitch() {
        if (this.deck.viewState.hasOwnProperty('default-view')) {
            return this.deck.viewState['default-view'].pitch
        }
        return this.deck.viewState.pitch
    }
    clearLayer(key) {

        switch (key) {
            case 'marker':
                this.markerLayers = []
                break;
            case 'car':
                this.carLayers = [];
                break;
            case 'map':
                this.mapLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.mapLayers.splice(index, 1)
                    }
                })
                break;
            case 'text':
                this.textLayers = []
                break;
            case 'polygon':
                this.polygonLayers = []
                break;
            case 'path':
                this.pathLayers = []
        }
    }
    setLayerSortName(key, name, sort) {
        if (this.layerSortArray.hasOwnProperty(key)) {
            if (this.layerSortArray[key].includes(name)) {
                this.layerSortArray[key].forEach((m, i) => {
                    if (m === name) {
                        if (sort) {
                            this.layerSortArray[key].splice(i, 1)
                            this.layerSortArray[key].splice(sort >= 1 ? sort - 1 : 0, 0, name)
                        }
                    }
                })
            } else {
                if (sort) {
                    this.layerSortArray[key].splice(sort >= 1 ? sort - 1 : 0, 0, name)
                } else {
                    this.layerSortArray[key].push(name)
                }
            }
        }
    }
    createGeoJsonLayer(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data: this.convert(data),
            stroked: true,
            filled: true,
            extruded: false,
            wireframe: true,
            getElevation: 0,
            pickable: true,
        }
        let layer = new GeoJsonLayer(Object.assign(defalutOprion, option));
        this.removeLayer('map', layerName)
        this.mapLayers.push(layer)
        this.initLayer()
    }
    creatCircle(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data,
            pickable: true,
            radiusUnits: 'meters',
            getPosition: d => d.coordinates,
        }
        let layer = new ScatterplotLayer(Object.assign(defalutOprion, option));
        this.removeLayer('map', layerName)
        this.mapLayers.push(layer)
        this.initLayer()
        // let cicleList = []
        // data.forEach(item => {
        //     var radius = option.radius;
        //     var options = { steps: 20, units: 'meters', properties: { foo: 'bar' } };
        //     var circle = turf.circle(item.coordinates, radius, options);
        //     cicleList.push(circle)
        // })
        // const obj = {
        //     type: "FeatureCollection",
        //     features: [...cicleList]
        // }
        // this.createGeoJsonLayer(obj, option, layerName)
    }
    creatPolygon(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data: [data],
            pickable: true,
            stroked: true,
            filled: true,
            wireframe: true,
            lineWidthMinPixels: 1,
            getPolygon: d => d.coordinates,
        }
        let layer = new PolygonLayer(Object.assign(defalutOprion, option));
        this.setLayerSortName('polygonLayer', layerName)
        this.removeLayer('map', layerName)
        this.mapLayers.push(layer)
        this.initLayer()
    }
    createPathLayer(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data,
            pickable: true,
            // widthScale: 20,
            // widthMinPixels: 2,
            getDashArray: [3, 3],
            getOffset: 0,
            dashJustified: false,
            // dashGapPickable: true,
            highPrecisionDash: true,
            extensions: [new PathStyleExtension({ dash: true, offset: true })],
            // getPath: d => d.path,
            getColor: d => d.color,
        }
        const layer = new PathLayer(Object.assign(defalutOprion, option));
        this.setLayerSortName('pathLayer', layerName)
        this.removeLayer('path', layerName)
        this.pathLayers.push(layer)
        this.initLayer()
    }
    createCarModel(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data,
            pickable: true,
            getPosition: d => d.coordinates,
            sizeScale: 1,
            _lighting: 'pbr',
            getTranslation: [0, 0, 0],
            _dataDiff: (newData, oldData) => [{ startRow: 0, endRow: data.length + 1 }],
            getOrientation: f => {
                return [0, f.rotate * 180 / Math.PI + 90, 90]
            },
        }
        const layer = new ScenegraphLayer(Object.assign(defalutOprion, option));
        // this.setLayerSortName('carLayer', layerName)
        this.removeLayer('car', layerName)
        this.carLayers.push(layer)
        this.initLayer()
    }
    createTextLayer(data, option, layerName) {
        let defalutOprion = {
            id: layerName,
            data,
            pickable: true,
            getPosition: d => d.coordinates,
            getText: d => d.name,
            characterSet: 'auto',//这样设置支持中文
            getAngle: 0,
            getTextAnchor: 'middle',
            getAlignmentBaseline: 'bottom',
            fontSettings: {
                buffer: 1,
                sdf: true,
                smoothing: 0.2
            },
            fontWeight: 100,
            billboard: true,
            collisionEnabled: true,
            collisionTestProps: {
                sizeScale: 6 * 2,
                sizeMaxPixels: 40 * 2,
                sizeMinPixels: 1 * 2
            },
            getPixelOffset: [0, -5],
            extensions: [new CollisionFilterExtension()],
        }
        const layer = new TextLayer(Object.assign(defalutOprion, option));
        // this.setLayerSortName('textLayer', layerName)
        this.removeLayer('text', layerName)
        this.textLayers.push(layer)
        this.initLayer()
    }
    creatMarker(data, option, layerName) {
        const layer = new IconLayer({
            id: layerName,
            data,
            pickable: true,
            // iconAtlas and iconMapping are required
            // getIcon: return a string
            getPosition: d => d.coordinates,
            ...option
        });
        this.setLayerSortName('markerLayer', layerName)
        this.removeLayer('marker', layerName)
        this.markerLayers.push(layer)
        this.initLayer()
    }
    setRoll(coor) {
        let zoom = this.getZoom() || 15
        let pitch = this.getPitch() || 40
        this.deck.setProps({ initialViewState: {} })
        this.deck.setProps({
            initialViewState: {
                latitude: coor[0],
                longitude: coor[1],
                zoom: zoom,
                pitch: pitch,
                bearing: -this.rotate,
                // pickingRadius:5,
                controller: true
                // * 180 / Math.PI + 60 + 180
            }
        })
    }
    setRotation(rotate) {
        this.rotate = rotate
        let zoom = this.getZoom() || 15
        let pitch = this.getPitch() || 40
        this.deck.setProps({ initialViewState: {} })
        this.deck.setProps({
            initialViewState: {
                latitude: document.location.mapCenter[0],
                longitude: document.location.mapCenter[1],
                zoom: zoom,
                pitch: pitch,
                bearing: -rotate,
                // pickingRadius:5,
                controller: true
                // * 180 / Math.PI + 60 + 180
            }
        })
    }
    flyTo(coor, zoom) {
        let pitch = this.getPitch() || 40
        this.deck.setProps({ initialViewState: {} })
        this.deck.setProps({
            initialViewState: {
                latitude: coor[0],
                longitude: coor[1],
                zoom: zoom,
                pitch: pitch,
                bearing: -this.rotate,
                // pickingRadius:5,
                controller: true
            }
        })
    }
    //根据页面中图层的顺序排序
    layerSort() {
        //图层的顺序
        let obj = []
        Object.values(this.layerSortArray).forEach(item => {
            obj.push(...item)
        })
        let newArray = []
        obj.forEach(item => {
            this.mapLayers.forEach(m => {
                if (item == m.id) {
                    newArray.push(m)
                }
            })
        })
        this.mapLayers = newArray.reverse();
    }
    //根据图层名字从图层数组中移除对应图层
    removeLayer(type, layerName) {
        switch (type) {
            case 'marker':
                this.markerLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.markerLayers.splice(index, 1)
                    }
                })
                break;
            case 'car':
                this.carLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.carLayers.splice(index, 1)
                    }
                })
                break;
            case 'map':
                this.mapLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.mapLayers.splice(index, 1)
                    }
                })
                break;
            case 'text':
                this.textLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.textLayers.splice(index, 1)
                    }
                })
                break;
            case 'polygon':
                this.polygonLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.polygonLayers.splice(index, 1)
                    }
                })
                break;
            case 'path':
                this.pathLayers.forEach((item, index) => {
                    if (item.id == layerName) {
                        this.pathLayers.splice(index, 1)
                    }
                })
        }
        this.initLayer();
    }
    /**
     * 移除所有图层
     **/
    remove() {
        this.deck.setProps({
            layers: []
        })
    }
    /**
     * 坐标去掉高程
     **/
    convert(obj) {
        let { features } = obj;
        for (let i = 0; i < features.length; i++) {
            let { geometry } = features[i];
            let { coordinates, type } = geometry;
            for (let j = 0; j < coordinates.length; j++) {
                if (type == "Polygon") {
                    for (let k = 0; k < coordinates[j].length; k++) {
                        if (coordinates[j][k].length > 2) {
                            coordinates[j][k] = coordinates[j][k].slice(0, 2)
                        }
                    }
                } else {
                    if (coordinates[j].length > 2) {
                        coordinates[j] = coordinates[j].slice(0, 2)
                    }
                }
            }

        }
        return obj
    }
    /**
     * 经纬度互换
     **/
    coorReverse(data) {
        return data.map(item => {
            let list = [];
            list = [item[1], item[0]]
            return list
        })
    }
    /**
     * 颜色16进制转成rgba
     **/
    convertColor(color, opacity) {
        if (!color) return;
        if (color.indexOf('rgba') > -1) {
            let colors = color.replace('rgba', '').replace('(', '').replace(')', '').split(',').map(m => parseInt(m))
            return [...colors.slice(0, 3), opacity ? opacity * 225 : 225]
        } else {
            let result = []
            if (color.length === 4) {
                result = /^#?([a-f\d])([a-f\d])([a-f\d])$/i.exec(color);
                // 将分解出的分量转换为十进制数，并将它们扩展为 6 位十六进制字符串
                let r = parseInt(result[1] + result[1], 16);
                let g = parseInt(result[2] + result[2], 16);
                let b = parseInt(result[3] + result[3], 16);
                return [r, g, b, opacity ? opacity * 225 : 225]
            } else {
                result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
                // 将分解出的分量转换为十进制数
                let r = parseInt(result[1], 16);
                let g = parseInt(result[2], 16);
                let b = parseInt(result[3], 16);
                return [r, g, b, opacity ? opacity * 225 : 225]
            }
        }
    }

    mergeOption(oldOption, newOption) {
        Object.keys(newOption).forEach(key => {
            if (typeof newOption[key] == "object") {
                if (oldOption.hasOwnProperty(key)) {
                    this.mergeOption(oldOption[key], newOption[key])
                } else {
                    oldOption[key] = newOption[key]
                }
            } else {
                oldOption[key] = newOption[key]
            }

        })
    }
}

