function PBFVectorTileProvider(options) {
    _self = this;
    //当前瓦片大小
    this._url = options.url;
    this._tileWidth = 256;
    this._tileHeight = 256;
    this._maximumLevel = 22;
    this._minimumLevel = 9;
    // this._tilingScheme = new Cesium.GeographicTilingScheme();
    this._tilingScheme = new Cesium.WebMercatorTilingScheme({
        rectangleSouthwestInMeters: new Cesium.Cartesian2(-20037508.3427892, -20037508.3427892),
        rectangleNortheastInMeters: new Cesium.Cartesian2(20037508.3427892, 20037508.3427892),
    });
    this._credit = undefined;
    this._rectangle = this._tilingScheme.rectangle;
    this._ready = true;
    this._style = null;
    if (options.style) {
        this._style = options.style;
    } else {
        this._style = {
            park: "#d8e8c8",
            landuse: "#e0e4dd",
            hospital: "#fde",
            school: "#f0e8f8",
            water: "#a0c8f0",
            aeroway: "#f2efeb",
            building: "#dfdbd7",
            service: "#cfcdca",
            street: "#e9ac77",
            path: "#cba",
            major_rail: "#bbb",
            landboundary: "#9e9cab",
            lightboundary: "#91e9f7",
            fireline: "#db7093"
        };
    }

};

function ajax(opt) {
    opt.type = opt.type || 'GET';
    opt.format = opt.format || 'JSON';
    let xhr = new XMLHttpRequest();
    xhr.open(opt.type,
        opt.url,
        true);
    if (opt.format === "ARRAY_BUFFER") {
        xhr.responseType = 'arraybuffer';
    }
    /**
     * @param {Event} event Event.
     * @private
     */
    xhr.onload = function (event) {
        // status will be 0 for file:// urls
        if (!xhr.status || xhr.status >= 200 && xhr.status < 300) {
            let type = opt.format;
            /** @type {Document|Node|Object|string|undefined} */
            let source;
            if (type === 'JSON' ||
                type === 'TEXT') {
                source = xhr.responseText;
            } else if (type === "XML") {
                source = xhr.responseXML;
                if (!source) {
                    source = ol.xml.parse(xhr.responseText);
                }
            } else if (type === "ARRAY_BUFFER") {
                source = /** @type {ArrayBuffer} */ (xhr.response);
            }
            if (source) {
                // success.call(this, format.readFeatures(source,
                //     {featureProjection: projection}),
                //     format.readProjection(source), format.getLastExtent());
                opt.success(source);
            } else {
                //failure.call(this);
            }
        } else {
            opt.failure(this);
        }
    }.bind(this);
    /**
     * @private
     */
    xhr.onerror = function () {
        failure.call(this);
    }.bind(this);
    xhr.send();
};

/**
 * 根据地图层级，行列号为索引获取三维数据的值是否存在
 * @param x 列号
 * @param y 行号
 * @param level 层级
 * @return {boolean} 存在返回true,反之为否
 */

function buildImageUrl(imageryProvider, x, y, level) {
    let url = imageryProvider._url;
    url = url
        .replace('{x}', x)
        .replace('{y}', y)
        .replace('{z}', level);
    return url;
}

Cesium.defineProperties(PBFVectorTileProvider.prototype, {
    url: {
        get: function () {
            return this._url;
        }
    },

    token: {
        get: function () {
            return this._token;
        }
    },

    proxy: {
        get: function () {
            return this._proxy;
        }
    },

    tileWidth: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('tileWidth must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._tileWidth;
        }
    },

    tileHeight: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('tileHeight must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._tileHeight;
        }
    },

    maximumLevel: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('maximumLevel must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._maximumLevel;
        }
    },

    minimumLevel: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('minimumLevel must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return 0;
        }
    },

    tilingScheme: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('tilingScheme must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._tilingScheme;
        }
    },

    rectangle: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('rectangle must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._rectangle;
        }
    },

    tileDiscardPolicy: {
        get: function () {
            //>>includeStart('debug', pragmas.debug);
            if (!this._ready) {
                throw new DeveloperError('tileDiscardPolicy must not be called before the imagery provider is ready.');
            }
            //>>includeEnd('debug');

            return this._tileDiscardPolicy;
        }
    },

    errorEvent: {
        get: function () {
            return this._errorEvent;
        }
    },

    ready: {
        get: function () {
            return this._ready;
        }
    },

    readyPromise: {
        get: function () {
            return this._readyPromise.promise;
        }
    },

    credit: {
        get: function () {
            return this._credit;
        }
    },

    usingPrecachedTiles: {
        get: function () {
            return this._useTiles;
        }
    },

    hasAlphaChannel: {
        get: function () {
            return true;
        }
    },

    layers: {
        get: function () {
            return this._layers;
        }
    },
});
PBFVectorTileProvider.prototype.getTileCredits = function (x, y, level) {
    return undefined;
};
PBFVectorTileProvider.prototype.requestImage = function (x, y, level) {
    if (!this._ready) {
        throw new DeveloperError('requestImage must not be called before the imagery provider is ready.');
    }
    if (level >= _self._minimumLevel || level <= _self._maximumLevel) {
        let url = buildImageUrl(this, x, y, level);
        return getImageByURL(url, "ARRAY_BUFFER", level, x, y);
    }
};

function getImageByURL(url, format, level, x, y) {
    return new Promise(function (resolve, reject) {
        var l = level, col = x, row = y;
        ajax({
            type: 'get',
            url: url,
            data: "",
            format: format,
            success: function (data) {
                let layers = null;
                let pbf = new Pbf(data);
                let pbfLayers = pbf.readFields(pbf.layers, {});
                // let features = [];
                let pbfLayer;
                let canvas = document.createElement('canvas');
                canvas.width = 1024;
                canvas.height = 1024;
                let context = canvas.getContext('2d');
                for (let name in pbfLayers) {
                    if (layers && layers.indexOf(name) === -1) {
                        continue;
                    }
                    pbfLayer = pbfLayers[name];
                    let rawFeature;
                    for (let i = 0, ii = pbfLayer.length; i < ii; ++i) {
                        rawFeature = pbf.readRawFeature(pbf, pbfLayer, i);
                        let feature = pbf.createFeature(pbf, rawFeature);
                        if (feature.type === "LineString" || feature.type === "MultiLineString" || feature.type === "Polygon") {
                            if (feature.properties.undefined !== "road_label" && feature.properties.undefined !== "marine_label" &&
                                feature.properties.undefined !== "waterway_label") {
                                if (feature.properties.undefined === "marine_label") {
                                    console.log(feature.properties);
                                }
                                let style = setStyleByGeomety(feature.type, feature.properties);
                                let flatCoordinate = feature.flatCoordinates, ends = feature.ends;
                                for (let i = 0; i < ends.length; i++) {
                                    let n = i > 0 ? ends[i - 1] : 0;
                                    context.beginPath();
                                    context.moveTo(parseInt(flatCoordinate[n] / 4), parseInt(flatCoordinate[++n] / 4));
                                    while (n < (ends[i] - 1)) {
                                        context.lineTo(parseInt(flatCoordinate[++n] / 4), parseInt(flatCoordinate[++n] / 4));
                                    }
                                    context.setLineDash(style.lineDash);
                                    context.strokeStyle = style.strokeStyle;
                                    context.fillStyle = style.fillStyle;
                                    context.lineWidth = style.linewidth;
                                    context.stroke();
                                    if (feature.type === "Polygon") {
                                        context.fill();
                                    }
                                }
                            }
                        }

                    }
                }
                // console.log(l, col, row);
                resolve(canvas);
                // let image = new Image();
                // image.src = canvas.toDataURL();
                // image.onload = function () {
                //     resolve(image);
                // };
                // image.onerror = function (e) {
                //     reject(e);
                // };
            }
            ,
            failure: function () {
                let image = new Image();
                resolve(image);
            }
        })
    });
};

function setStyleByGeomety(geom, property) {
    let layer = property.undefined, cls = property.class, type = property.type;
    let adminLevel = property.admin_level, maritime = property.maritime, disputed = property.disputed;
    let fill = "yellow", stroke = "yellow", linewidth = 7, lineDash = [0, 0], style = null;//#343332
    if (geom === "LineString" || geom === "MultiLineString" || geom === "Polygon") {
        if (layer === 'landuse' && (cls === 'cemetery' || cls === 'parking'
            || cls === 'pitch' || cls === 'rock' || cls === 'land' || cls === 'sand' || cls === 'scrub')) {
            stroke = _self._style.landuse;
            fill = stroke;
        } else if (layer === 'landuse' && cls === 'hospital') {
            stroke = _self._style.hospital;
            fill = stroke;
        } else if (layer === 'landuse' && cls === 'school') {
            stroke = _self._style.school;
            fill = stroke;
        } else if (layer === 'landuse' && (cls === 'wood' || cls === 'wetland' || cls === 'park'
            || cls === 'agriculture' || cls === 'industrial' || cls === 'grass' || cls === 'wetland_noveg')) {
            stroke = _self._style.park;
            fill = stroke;
        } else if (layer === 'landuse_overlay' && (cls === 'wetland_noveg' || cls === 'wetland')) {
            stroke = _self._style.park;
            fill = stroke;
        } else if (layer === 'waterway' &&
            (cls === 'river' || cls === 'stream' || cls === 'canal' || cls === 'river' || cls === "drain" || cls === "ditch")) {
            stroke = _self._style.park.water;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'waterway' && (cls === 'stream' ||
            cls === 'canal')) {
            stroke = _self._style.water;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'water') {
            stroke = _self._style.water;
            fill = stroke;
        } else if (layer === 'aeroway') {
            stroke = _self._style.aeroway;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'building') {
            stroke = _self._style.building;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'motorway_link') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'minor_rail') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'service') {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' &&
            (cls === 'street' || cls === 'street_limited')) {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'main') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'motorway') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'path') {
            stroke = _self._style.path;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'tunnel' && cls === 'major_rail') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'road' && cls === 'motorway_link') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && cls === 'service') {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && (cls === 'street' ||
            cls === 'street_limited')) {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && cls === 'main') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && cls === 'motorway') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && cls === 'path') {
            stroke = _self._style.path;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'road' && cls === 'major_rail') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'road' && cls === 'minor_rail') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'road' && cls === 'driveway') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'road' && cls === 'driveway') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'barrier_line') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'motorway_link') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'minor_rail') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'driveway') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'motorway') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'service') {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'aerialway') {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' &&
            (cls === 'street' || cls === 'street_limited')) {
            stroke = _self._style.service;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'main') {
            stroke = _self._style.street;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'path') {
            stroke = _self._style.path;
            linewidth = 7;
            fill = stroke;
        } else if (layer === 'bridge' && cls === 'major_rail') {
            stroke = _self._style.major_rail;
            linewidth = 8;
            fill = stroke;
        }
        // else if (layer === 'admin' && adminLevel >= 3 && maritime === 0) {
        //     console.log(property);
        //     stroke = _self._style.landboundary;
        //     linewidth = 10;
        //     fill = stroke;
        // } else if (layer === 'admin' && adminLevel === 2 &&
        //     disputed === 0 && maritime === 0) {
        //     console.log(property);
        //     stroke = _self._style.landboundary;
        //     linewidth = 8;
        //     fill = stroke;
        // } else if (layer === 'admin' && adminLevel === 2 &&
        //     disputed === 1 && maritime === 0) {
        //     stroke = _self._style.fireline;
        //     linewidth = 7;
        //     fill = stroke;
        //     lineDash = [12, 10];
        // } else if (layer === 'admin' && adminLevel >= 3 && maritime === 1) {
        //     console.log(property);
        //     stroke = _self._style.water;
        //     linewidth = 7;
        //     fill = stroke;
        //     lineDash = [12, 24]
        // } else if (layer === 'admin' && adminLevel === 2 && maritime === 1) {
        //     console.log(property);
        //     stroke = _self._style.water;
        //     linewidth = 7;
        //     fill = stroke;
        //     lineDash = [12, 12]
        // }
        else if (layer === 'admin') {
            if (property.iso_3166_1.indexOf("CN") >= 0) {
                if (disputed === 1) {
                    stroke = _self._style.fireline;
                    linewidth = 7;
                    fill = stroke;
                    lineDash = [12, 10];
                } else if (maritime === 1) {
                    stroke = _self._style.water;
                    linewidth = 7;
                    fill = stroke;
                    lineDash = [12, 12]
                } else if (adminLevel === 2) {
                    stroke = _self._style.lightboundary;
                    linewidth = 8;
                    fill = stroke;
                } else {
                    stroke = _self._style.lightboundary;
                    linewidth = 7;
                    fill = stroke;
                }
            } else {
                if (disputed === 1) {
                    stroke = _self._style.landboundary;
                    linewidth = 7;
                    fill = stroke;
                    lineDash = [12, 10];
                } else if (maritime === 1) {
                    stroke = _self._style.water;
                    linewidth = 7;
                    fill = stroke;
                    lineDash = [12, 12]
                } else if (adminLevel === 2) {
                    stroke = _self._style.landboundary;
                    linewidth = 7;
                    fill = stroke;
                } else if (adminLevel >= 3) {
                    stroke = _self._style.landboundary;
                    linewidth = 6;
                    fill = stroke;
                }
            }

        }
    }

    style = {
        linewidth: linewidth,
        strokeStyle: stroke,
        fillStyle: fill,
        lineDash: lineDash
    };
    return style;
}


