import { inject, onUnmounted, watch, provide, ref } from 'vue';
import mitt from 'mitt';
import { isString, isArray, isFunction, getObjClassName, removeEmpty, isEmptyObj, kebabCase } from '../utils/util';
import { mergeDescriptors } from '../utils/merge-descriptors';
import { getInstanceListener, getVcParentInstance } from '../utils/private/vm';
import * as cesiumProps from '../utils/cesium-props';
import { vcKey } from '../utils/config';
import { t } from '../locale';
import * as coordtransform from '../utils/coordtransform';
import cloneDeep from 'lodash/cloneDeep';
import differenceWith from 'lodash/differenceWith';
import isEqual from 'lodash/isEqual';

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

function useLog (vcInstance) {
    const makeLog = (prefix = '') => {
        return function (...args) {
            if (process.env.NODE_ENV !== 'production') {
                if (prefix) {
                    if (isString(args[0])) {
                        args[0] = prefix.trim() + ' ' + args[0];
                    }
                    else {
                        args = [prefix.trim(), ...args];
                    }
                }
                console.log(...args);
            }
        };
    };
    const makeWarn = (prefix = '') => {
        return function (...args) {
            if (prefix) {
                if (isString(args[0])) {
                    args[0] = prefix.trim() + ' ' + args[0];
                }
                else {
                    args = [prefix.trim(), ...args];
                }
            }
            console.warn(...args);
        };
    };
    const makeError = (prefix = '') => {
        return function (...args) {
            if (prefix) {
                if (isString(args[0])) {
                    args[0] = prefix.trim() + ' ' + args[0];
                }
                else {
                    args = [prefix.trim(), ...args];
                }
            }
            console.error(...args);
        };
    };
    return {
        log: makeLog(`[VueCesium] ${vcInstance.proxy.$options.name}`),
        warn: makeWarn(`[VueCesium] WARN ${vcInstance.proxy.$options.name}`),
        error: makeError(`[VueCesium] ERR ${vcInstance.proxy.$options.name}`)
    };
}

function useEvents (props, vcInstance, logger) {
    const $vc = vcInstance.appContext.config.globalProperties.$VueCesium;
    const bindEvents = (cesiumObject, cesiumEvents, register = true) => {
        const ev = cesiumEvents || vcInstance.cesiumEvents || [];
        ev &&
            ev.forEach(eventName => {
                if (cesiumObject[eventName]) {
                    const listener = getInstanceListener(vcInstance, eventName);
                    const methodName = register ? 'addEventListener' : 'removeEventListener';
                    listener && cesiumObject[eventName][methodName](listener);
                }
                else if (process.env.VUECESIUM_DEBUG) {
                    logger.warn('Add event linstener of ' + eventName + ' failed, try to upgrade Cesium to latest version.');
                }
            });
    };
    const registerEvents = register => {
        var _a;
        const { viewer, cesiumObject } = vcInstance;
        const { ScreenSpaceEventHandler, ScreenSpaceEventType } = Cesium;
        if (!$vc.pickScreenSpaceEventHandler || !$vc.viewerScreenSpaceEventHandler) {
            $vc.pickScreenSpaceEventHandler = new ScreenSpaceEventHandler(viewer.canvas);
            $vc.viewerScreenSpaceEventHandler = new ScreenSpaceEventHandler(viewer.canvas);
            viewerScreenSpaceEvents.forEach(type => {
                const listener = getInstanceListener(vcInstance, type);
                listener && $vc.viewerScreenSpaceEventHandler.setInputAction(listener, ScreenSpaceEventType[type]);
                $vc.pickScreenSpaceEventHandler.setInputAction(pickedAction.bind({ eventName: type, viewer }), ScreenSpaceEventType[type]);
            });
        }
        bindEvents(cesiumObject, vcInstance.cesiumEvents || [], register);
        (_a = vcInstance.cesiumMembersEvents) === null || _a === void 0 ? void 0 : _a.forEach(eventName => {
            const cesiumIntanceMember = isArray(eventName.name) && eventName.name.length > 0
                ? cesiumObject[eventName.name[0]][eventName.name[1]]
                : cesiumObject[eventName.name];
            cesiumIntanceMember && bindEvents(cesiumIntanceMember, eventName.events, register);
        });
        if (props.enableMouseEvent) {
            pickEvents.forEach(eventName => {
                const listener = getInstanceListener(vcInstance, eventName);
                if (register) {
                    listener && (cesiumObject[eventName] = listener);
                }
                else {
                    listener && delete cesiumObject[eventName];
                }
            });
        }
    };
    function pickedAction(movement) {
        if (!props.enableMouseEvent) {
            return;
        }
        const { viewer, eventName } = this;
        const position = movement.position || movement.endPosition;
        if (!position) {
            return;
        }
        const pickedFeatureAndCallbackNames = [];
        let callbackName;
        if (eventName.indexOf('LEFT_DOUBLE_CLICK') !== -1) {
            callbackName = 'dblclick';
        }
        else if (eventName.indexOf('CLICK') !== -1) {
            callbackName = 'click';
        }
        else if (eventName.indexOf('DOWN') !== -1) {
            callbackName = 'mousedown';
        }
        else if (eventName.indexOf('UP') !== -1) {
            callbackName = 'mouseup';
        }
        else if (eventName.indexOf('MOUSE_MOVE') !== -1) {
            callbackName = 'mousemove';
        }
        let callbackNameOut;
        if (callbackName === 'mousemove') {
            callbackNameOut = 'mouseout';
        }
        else if (callbackName === 'click') {
            callbackNameOut = 'clickout';
        }
        const pickedFeature = viewer.scene.pick(position);
        if (!Cesium.defined(pickedFeature)) {
            if (this.pickedFeature) {
                pickedFeatureAndCallbackNames.push({
                    callbackName: callbackNameOut,
                    pickedFeature: this.pickedFeature,
                });
            }
            this.pickedFeature = undefined;
        }
        else {
            if (this.pickedFeature && this.pickedFeature !== pickedFeature) {
                pickedFeatureAndCallbackNames.push({
                    callbackName: callbackNameOut,
                    pickedFeature: this.pickedFeature,
                });
            }
            if (callbackName === 'mousemove' && (!this.pickedFeature || this.pickedFeature !== pickedFeature)) {
                pickedFeatureAndCallbackNames.push({
                    callbackName: 'mouseover',
                    pickedFeature,
                });
            }
            pickedFeatureAndCallbackNames.push({
                callbackName,
                pickedFeature,
            });
        }
        if (pickedFeatureAndCallbackNames.length === 0) {
            return;
        }
        let intersection;
        const scene = viewer.scene;
        if (scene.mode === Cesium.SceneMode.SCENE3D) {
            const ray = scene.camera.getPickRay(position);
            intersection = scene.globe.pick(ray, scene);
        }
        else {
            intersection = scene.camera.pickEllipsoid(position, Cesium.Ellipsoid.WGS84);
        }
        let button = -1;
        if (eventName.indexOf('LEFT') !== -1) {
            button = 0;
        }
        else if (eventName.indexOf('MIDDLE') !== -1) {
            button = 1;
        }
        else if (eventName.indexOf('RIGHT') !== -1) {
            button = 2;
        }
        const eventSourceList = [];
        pickedFeatureAndCallbackNames.forEach(item => {
            const callbackName = item.callbackName;
            const pickedFeature = item.pickedFeature;
            if (pickedFeature.id) {
                if (isArray(pickedFeature.id) && pickedFeature.id[0] instanceof Cesium.Entity) {
                    eventSourceList.push({
                        callbackName,
                        cesiumObject: pickedFeature.id[0].entityCollection.owner,
                        pickedFeature,
                    });
                }
                else if (pickedFeature.id instanceof Cesium.Entity) {
                    eventSourceList.push({
                        callbackName,
                        cesiumObject: pickedFeature.id,
                        pickedFeature,
                    });
                    eventSourceList.push({
                        callbackName,
                        cesiumObject: pickedFeature.id.entityCollection.owner,
                        pickedFeature,
                    });
                }
            }
            if (pickedFeature.primitive) {
                eventSourceList.push({
                    callbackName,
                    cesiumObject: pickedFeature.primitive,
                    pickedFeature,
                });
            }
            const getParentCollection = e => {
                eventSourceList.push({
                    callbackName,
                    cesiumObject: e,
                    pickedFeature,
                });
                if (e._vcParent) {
                    getParentCollection(e._vcParent);
                }
            };
            if (pickedFeature.collection) {
                eventSourceList.push({
                    callbackName,
                    cesiumObject: pickedFeature.collection,
                    pickedFeature,
                });
                if (pickedFeature.collection._vcParent) {
                    getParentCollection(pickedFeature.collection._vcParent);
                }
            }
        });
        eventSourceList.forEach(event => {
            event.cesiumObject[event.callbackName] &&
                event.cesiumObject[event.callbackName]({
                    type: `on${event.callbackName}`,
                    windowPosition: position,
                    surfacePosition: intersection,
                    pickedFeature: event.pickedFeature,
                    button,
                    cesiumObject: event.cesiumObject,
                });
        });
        this.pickedFeature = pickedFeature;
    }
    return {
        bindEvents,
        registerEvents,
    };
}
const viewerScreenSpaceEvents = [
    'LEFT_CLICK',
    'LEFT_DOUBLE_CLICK',
    'LEFT_DOWN',
    'LEFT_UP',
    'MIDDLE_CLICK',
    'MIDDLE_DOWN',
    'MIDDLE_UP',
    'MOUSE_MOVE',
    'PINCH_END',
    'PINCH_MOVE',
    'PINCH_START',
    'RIGHT_CLICK',
    'RIGHT_DOWN',
    'RIGHT_UP',
    'WHEEL',
];
const pickEvents = ['mousedown', 'mouseup', 'click', 'clickout', 'dblclick', 'mousemove', 'mouseover', 'mouseout'];

function useCommon (props, { emit }, vcInstance) {
    const logger = useLog(vcInstance);
    vcInstance.alreadyListening = [];
    let unwatchFns = [];
    vcInstance.mounted = false;
    const vcMitt = mitt();
    vcInstance.vcMitt = vcMitt;
    const $services = inject(vcKey);
    if ($services === void 0) {
        console.error(`${vcInstance.cesiumClass} ${t('vc.loadError')}`);
        return;
    }
    const parentVcInstance = getVcParentInstance(vcInstance);
    const eventsState = useEvents(props, vcInstance, logger);
    vcInstance.children = [];
    const entityGraphics = [
        'billboard',
        'box',
        'corridor',
        'cylinder',
        'ellipse',
        'ellipsoid',
        'label',
        'model',
        'tileset',
        'path',
        'plane',
        'point',
        'polygon',
        'polyline',
        'polylineVolume',
        'rectangle',
        'wall'
    ];
    const beforeLoad = () => __awaiter(this, void 0, void 0, function* () {
        emit('beforeLoad', vcInstance);
        if (parentVcInstance.nowaiting) {
            return true;
        }
        else {
            yield parentVcInstance.proxy.createPromise;
        }
    });
    const load = () => __awaiter(this, void 0, void 0, function* () {
        var _a;
        if (vcInstance.mounted) {
            return false;
        }
        logger.log(`${vcInstance.cesiumClass}---load`);
        yield beforeLoad();
        const { Cesium, viewer } = $services;
        vcInstance.viewer = viewer;
        vcInstance.Cesium = Cesium;
        if (!parentVcInstance.cesiumObject) {
            return yield ((_a = parentVcInstance.proxy) === null || _a === void 0 ? void 0 : _a.load());
        }
        setPropsWatcher(true);
        return createCesiumObject().then((cesiumObject) => __awaiter(this, void 0, void 0, function* () {
            vcInstance.cesiumObject = cesiumObject;
            return mount().then(() => {
                vcInstance.mounted = true;
                parentVcInstance.children.push(vcInstance);
                const readyObj = { Cesium, viewer, cesiumObject, vm: vcInstance.proxy };
                emit('ready', readyObj);
                vcMitt.emit('ready', readyObj);
                logger.log(`${vcInstance.cesiumClass}---loaded`);
                return readyObj;
            });
        }));
    });
    const beforeUnload = () => __awaiter(this, void 0, void 0, function* () {
        yield vcInstance.unloadingPromise;
    });
    const unload = () => __awaiter(this, void 0, void 0, function* () {
        yield beforeUnload();
        for (let i = 0; i < vcInstance.children.length; i++) {
            const vcChildCmp = vcInstance.children[i].proxy;
            yield vcChildCmp.unload();
        }
        return vcInstance.mounted ? unmount().then(() => __awaiter(this, void 0, void 0, function* () {
            setPropsWatcher(false);
            vcInstance.cesiumObject = undefined;
            vcInstance.mounted = false;
            emit('destroyed', vcInstance);
            logger.log(`${vcInstance.cesiumClass}---unmounted`);
            return vcInstance.renderByParent && !vcInstance.unloadingPromise ? parentVcInstance.proxy.unload() : true;
        })) : false;
    });
    const reload = () => __awaiter(this, void 0, void 0, function* () {
        return unload().then(() => {
            return load();
        });
    });
    const mount = () => __awaiter(this, void 0, void 0, function* () {
        var _b;
        eventsState.registerEvents(true);
        return ((_b = vcInstance.mount) === null || _b === void 0 ? void 0 : _b.call(vcInstance)) || true;
    });
    const unmount = () => __awaiter(this, void 0, void 0, function* () {
        var _c;
        eventsState.registerEvents(false);
        return ((_c = vcInstance.unmount) === null || _c === void 0 ? void 0 : _c.call(vcInstance)) || true;
    });
    const createCesiumObject = () => __awaiter(this, void 0, void 0, function* () {
        logger.log('do createCesiumObject');
        if (isFunction(vcInstance.createCesiumObject)) {
            return vcInstance.createCesiumObject();
        }
        else {
            const options = transformProps(props);
            return new Cesium[vcInstance.cesiumClass](options);
        }
    });
    const setPropsWatcher = register => {
        if (register) {
            if (!vcInstance.cesiumClass || !Cesium[vcInstance.cesiumClass]) {
                return;
            }
            props &&
                Object.keys(props).forEach(vueProp => {
                    var _a, _b;
                    let cesiumProp = vueProp;
                    if (vueProp === 'labelStyle' || vueProp === 'wmtsStyle') {
                        cesiumProp = 'style';
                    }
                    else if (vueProp === 'bmKey') {
                        cesiumProp = 'key';
                    }
                    if (((_a = vcInstance.proxy.$options.watch) === null || _a === void 0 ? void 0 : _a[vueProp]) || vcInstance.alreadyListening.indexOf(vueProp) !== -1) {
                        return;
                    }
                    const watcherOptions = (_b = vcInstance.proxy.$options.props[vueProp]) === null || _b === void 0 ? void 0 : _b.watcherOptions;
                    const unwatch = vcInstance.proxy.$watch(vueProp, (val) => __awaiter(this, void 0, void 0, function* () {
                        yield vcInstance.proxy.createPromise;
                        const { cesiumObject } = vcInstance;
                        const pd = cesiumObject && Object.getOwnPropertyDescriptor(cesiumObject, cesiumProp);
                        const pdProto = cesiumObject && Object.getOwnPropertyDescriptor(Object.getPrototypeOf(cesiumObject), cesiumProp);
                        const hasSetter = (pd && (pd.writable || pd.set)) || (pdProto && (pdProto.writable || pdProto.set));
                        if (hasSetter) {
                            if (watcherOptions && watcherOptions.cesiumObjectBuilder) {
                                const newVal = watcherOptions.cesiumObjectBuilder.call(vcInstance, val);
                                if (!(Cesium.defined(cesiumObject[cesiumProp]) && Cesium.defined(cesiumObject[cesiumProp]._callback))) {
                                    cesiumObject[cesiumProp] = newVal;
                                }
                            }
                            else {
                                cesiumObject[cesiumProp] = transformProp(cesiumProp, val);
                            }
                            return true;
                        }
                        else {
                            return vcInstance.proxy.reload();
                        }
                    }), {
                        deep: watcherOptions === null || watcherOptions === void 0 ? void 0 : watcherOptions.deep
                    });
                    unwatchFns.push(unwatch);
                });
        }
        else {
            unwatchFns.forEach(item => item());
            unwatchFns = [];
        }
    };
    const transformProps = props => {
        let options = {};
        props &&
            Object.keys(props).forEach(vueProp => {
                let cesiumProp = vueProp;
                if (vueProp === 'labelStyle' || vueProp === 'wmtsStyle') {
                    cesiumProp = 'style';
                }
                else if (vueProp === 'bmKey') {
                    cesiumProp = 'key';
                }
                const className = getObjClassName(props[vueProp]);
                if (className &&
                    className.indexOf('Graphics') === -1 &&
                    entityGraphics.indexOf(cesiumProp) !== -1 &&
                    (vcInstance.cesiumClass === 'Entity' || vcInstance.cesiumClass.indexOf('DataSource') > 0)) {
                    options[cesiumProp] = transformProps(props[vueProp]);
                }
                else {
                    options[cesiumProp] = transformProp(vueProp, props[vueProp]);
                }
            });
        options = removeEmpty(options);
        return options;
    };
    const transformProp = (prop, value) => {
        const className = getObjClassName(value);
        if (className &&
            className.indexOf('Graphics') === -1 &&
            entityGraphics.indexOf(prop) !== -1 &&
            (vcInstance.cesiumClass === 'Entity' || vcInstance.cesiumClass.indexOf('DataSource') > 0)) {
            return transformProps(value);
        }
        else {
            const cmpName = vcInstance.proxy.$options.name;
            const propOption = vcInstance.proxy.$options.props[prop] || (cesiumProps[prop] && cesiumProps[prop][prop]);
            return (propOption === null || propOption === void 0 ? void 0 : propOption.watcherOptions) && !isEmptyObj(value)
                ? propOption.watcherOptions.cesiumObjectBuilder.call(vcInstance, value)
                : isFunction(value) && cmpName && (cmpName.indexOf('Graphics') !== -1 || cmpName === 'vc-entity')
                    ? new Cesium.CallbackProperty(value, false)
                    : value;
        }
    };
    const getServices = () => {
        return mergeDescriptors({}, $services || {});
    };
    const createPromise = new Promise((resolve, reject) => {
        try {
            let isLoad = false;
            if ($services.viewer) {
                isLoad = true;
                load().then(e => {
                    resolve(e);
                    isLoad = false;
                });
            }
            parentVcInstance.vcMitt.on('ready', () => {
                if (!isLoad) {
                    resolve(load());
                }
            });
        }
        catch (e) {
            reject(e);
        }
    });
    logger.log(`${vcInstance.cesiumClass}---onCreated`);
    onUnmounted(() => {
        logger.log(`${vcInstance.cesiumClass}---onUnmounted`);
        vcInstance.unloadingPromise = new Promise((reslove, reject) => {
            unload().then(() => {
                logger.log(`${vcInstance.cesiumClass}---unloaded`);
                reslove(true);
                vcInstance.unloadingPromise = undefined;
                vcMitt.all.clear();
            });
        });
        vcInstance.alreadyListening = [];
    });
    return {
        $services,
        load,
        unload,
        reload,
        createPromise,
        transformProp,
        transformProps,
        unwatchFns,
        setPropsWatcher,
        logger,
        getServices
    };
}

function index (props, ctx, vcInstance) {
    vcInstance.cesiumEvents = ['definitionChanged'];
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const { cesiumObject } = vcInstance;
        const cmpNameArr = kebabCase(vcInstance.proxy.$options.name).split('-');
        const emitType = (cmpNameArr.length === 3 ? `update:${cmpNameArr[2]}` : 'update:polylineVolume');
        const parentVM = getVcParentInstance(vcInstance).proxy;
        return parentVM && parentVM.__updateGraphics(cesiumObject, emitType);
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        const cmpNameArr = kebabCase(vcInstance.proxy.$options.name).split('-');
        const emitType = (cmpNameArr.length === 3 ? `update:${cmpNameArr[2]}` : 'update:polylineVolume');
        const parentVM = getVcParentInstance(vcInstance).proxy;
        return (parentVM && parentVM.__updateGraphics(undefined, emitType));
    });
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
}

function index$1 (props, ctx, vcInstance) {
    vcInstance.cesiumEvents = ['errorEvent'];
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const { viewer } = commonState.$services;
        if (vcInstance.cesiumClass.indexOf('ImageryProvider') !== -1) {
            vcInstance.renderByParent = true;
            const imageryProvider = vcInstance.cesiumObject;
            imageryProvider.readyPromise.then(() => {
                const listener = getInstanceListener(vcInstance, 'readyPromise');
                listener && ctx.emit('readyPromise', imageryProvider, viewer, vcInstance.proxy);
            });
            if (props.projectionTransforms && props.projectionTransforms.from !== props.projectionTransforms.to) {
                const ignoreTransforms = vcInstance.proxy.$options.name === 'VcProviderImageryBaidumap' ||
                    (vcInstance.proxy.$options.name === 'vc-provider-imagery-tianditu' && imageryProvider._epsgCode === '4490');
                if (!ignoreTransforms) {
                    const { WebMercatorTilingScheme, Cartographic, Math: CesiumMath } = Cesium;
                    const tilingScheme = new WebMercatorTilingScheme();
                    const projection = tilingScheme.projection;
                    const nativeProject = projection.project;
                    const nativeUnProject = projection.unproject;
                    let projectMethods;
                    let unprojectMethods;
                    if (props.projectionTransforms.to.toUpperCase() === 'WGS84') {
                        projectMethods = 'wgs84togcj02';
                        unprojectMethods = 'gcj02towgs84';
                    }
                    else if (props.projectionTransforms.to.toUpperCase() === 'GCJ02') {
                        projectMethods = 'gcj02towgs84';
                        unprojectMethods = 'wgs84togcj02';
                    }
                    if (projectMethods && unprojectMethods) {
                        projection.project = function (cartographic, result) {
                            result = coordtransform[projectMethods](CesiumMath.toDegrees(cartographic.longitude), CesiumMath.toDegrees(cartographic.latitude));
                            return nativeProject.call(this, new Cartographic(CesiumMath.toRadians(result[0]), CesiumMath.toRadians(result[1])));
                        };
                        projection.unproject = function (cartesian2, result) {
                            const cartographic = nativeUnProject.call(this, cartesian2);
                            result = coordtransform[unprojectMethods](CesiumMath.toDegrees(cartographic.longitude), CesiumMath.toDegrees(cartographic.latitude));
                            return new Cartographic(CesiumMath.toRadians(result[0]), CesiumMath.toRadians(result[1]));
                        };
                        imageryProvider._tilingScheme = tilingScheme;
                    }
                }
            }
            const parentVM = getVcParentInstance(vcInstance).proxy;
            return parentVM && parentVM.__updateProvider(imageryProvider);
        }
        else {
            const terrainProvider = vcInstance.cesiumObject;
            terrainProvider.readyPromise.then(() => {
                const listener = getInstanceListener(vcInstance, 'readyPromise');
                listener && ctx.emit('readyPromise', terrainProvider, viewer, vcInstance.proxy);
            });
            viewer.terrainProvider = terrainProvider;
            return true;
        }
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        const { viewer } = commonState.$services;
        if (vcInstance.cesiumClass.indexOf('ImageryProvider') !== -1) {
            const parentVM = getVcParentInstance(vcInstance).proxy;
            return parentVM && parentVM.__updateProvider(undefined);
        }
        else {
            const terrainProvider = new Cesium.EllipsoidTerrainProvider();
            terrainProvider.readyPromise.then(() => {
                const listener = getInstanceListener(vcInstance, 'readyPromise');
                listener && ctx.emit('readyPromise', terrainProvider, viewer, vcInstance.proxy);
            });
            viewer.terrainProvider = terrainProvider;
            return true;
        }
    });
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
    return {
        transformProps: commonState.transformProps,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function index$2 (props, ctx, vcInstance) {
    vcInstance.cesiumEvents = ['changedEvent', 'errorEvent', 'loadingEvent'];
    if (vcInstance.cesiumClass === 'KmlDataSource') {
        vcInstance.cesiumEvents.push('refreshEvent');
        vcInstance.cesiumEvents.push('unsupportedNodeEvent');
    }
    vcInstance.cesiumMembersEvents = [
        {
            name: 'clock',
            events: ['definitionChanged']
        },
        {
            name: 'clustering',
            events: ['clusterEvent']
        },
        {
            name: 'entities',
            events: ['collectionChanged']
        }
    ];
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.alreadyListening.push('entities');
    let unwatchFns = [];
    unwatchFns.push(watch(() => cloneDeep(props.entities), (newVal, oldVal) => {
        if (!vcInstance.mounted) {
            return;
        }
        const datasource = vcInstance.cesiumObject;
        const adds = differenceWith(newVal, oldVal, isEqual);
        const deletes = differenceWith(oldVal, newVal, isEqual);
        if (newVal.length === oldVal.length && adds.length === deletes.length) {
            for (let i = 0; i < adds.length; i++) {
                const options = newVal[i];
                const modifyEntity = datasource.entities.getById(deletes[i].id);
                modifyEntity && Object.keys(options).forEach(prop => {
                    modifyEntity[prop] = commonState.transformProp(prop, options[prop]);
                });
            }
        }
        else {
            const deletedEntities = [];
            for (let i = 0; i < deletes.length; i++) {
                const deleteEntity = datasource.entities.getById(deletes[i].id);
                deletedEntities.push(deleteEntity);
            }
            deletedEntities.forEach(v => {
                datasource.entities.remove(v);
            });
            for (let i = 0; i < adds.length; i++) {
                const entityOptions = adds[i];
                const entityOptionsTransform = commonState.transformProps(entityOptions);
                const entityAdded = datasource.entities.add(entityOptionsTransform);
                entityAdded.id !== entityOptions.id && (entityOptions.id = entityAdded.id);
            }
        }
    }, {
        deep: true
    }));
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const dataSources = commonState.$services.dataSources;
        const datasource = vcInstance.cesiumObject;
        datasource.show = props.show;
        for (let i = 0; i < props.entities.length; i++) {
            const entityOptions = props.entities[i];
            const entityOptionsTransform = commonState.transformProps(entityOptions);
            const entity = datasource.entities.add(entityOptionsTransform);
            entityOptions.id !== entity.id && (entityOptions.id = entity.id);
        }
        return dataSources.add(datasource).then(() => {
            return true;
        });
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        const dataSources = commonState.$services.dataSources;
        const datasource = vcInstance.cesiumObject;
        return dataSources && dataSources.remove(datasource);
    });
    const getServices = () => {
        return mergeDescriptors(commonState.getServices(), {
            get datasource() {
                return vcInstance.cesiumObject;
            },
            get entities() {
                var _a;
                return (_a = vcInstance.cesiumObject) === null || _a === void 0 ? void 0 : _a.entities;
            }
        });
    };
    onUnmounted(() => {
        unwatchFns.forEach(item => item());
        unwatchFns = [];
    });
    provide(vcKey, getServices());
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
    return {
        transformProps: commonState.transformProps,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function index$3 (props, ctx, vcInstance) {
    const commonState = useCommon(props, ctx, vcInstance);
    const childCount = ref(0);
    const instances = ref([]);
    vcInstance.createCesiumObject = () => __awaiter(this, void 0, void 0, function* () {
        var _a, _b;
        const options = commonState.transformProps(props);
        if (!options.asynchronous) {
            yield ((_b = (_a = Cesium[vcInstance.cesiumClass]).initializeTerrainHeights) === null || _b === void 0 ? void 0 : _b.call(_a));
        }
        if (props.geometryInstances) {
            if (isArray(props.geometryInstances)) {
                instances.value.push(...props.geometryInstances);
                childCount.value += props.geometryInstances.length;
            }
            else {
                childCount.value += 1;
                instances.value.push(props.geometryInstances);
            }
        }
        return new Cesium[vcInstance.cesiumClass](options);
    });
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const primitives = commonState.$services.primitives;
        const primitive = vcInstance.cesiumObject;
        primitive.readyPromise && primitive.readyPromise.then(e => {
            const listener = getInstanceListener(vcInstance, 'readyPromise');
            listener && ctx.emit('readyPromise', e, commonState.$services.viewer, vcInstance.proxy);
        });
        primitive._vcParent = primitives;
        const object = primitives && primitives.add(primitive);
        if (vcInstance.cesiumClass === 'ParticleSystem') {
            const intervalId = setInterval(() => {
                if (Cesium.defined(object._billboardCollection)) {
                    object._billboardCollection._vcParent = object;
                    clearInterval(intervalId);
                }
            }, 500);
        }
        return Cesium.defined(object);
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        childCount.value = 0;
        instances.value = [];
        const primitives = commonState.$services.primitives;
        const primitive = vcInstance.cesiumObject;
        return primitives && primitives.remove(primitive);
    });
    const updateGeometryInstances = (instance, index) => {
        instances.value.push(instance);
        if (index === childCount.value - 1) {
            const listener = getInstanceListener(vcInstance, 'update:geometryInstances');
            if (listener) {
                ctx.emit('update:geometryInstances', instances);
            }
            else {
                const primitive = vcInstance.cesiumObject;
                primitive.geometryInstances = index === 0 ? instance : instances.value;
            }
        }
        return true;
    };
    const getServices = () => {
        return mergeDescriptors(commonState.getServices(), {
            get primitive() {
                return vcInstance.cesiumObject;
            }
        });
    };
    provide(vcKey, getServices());
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject,
        __updateGeometryInstances: updateGeometryInstances,
        __childCount: childCount
    });
    return {
        transformProps: commonState.transformProps,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function index$4 (props, ctx, vcInstance) {
    vcInstance.cesiumEvents = [];
    vcInstance.renderByParent = true;
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const geometry = vcInstance.cesiumObject;
        const parentVM = getVcParentInstance(vcInstance).proxy;
        return parentVM.__updateGeometry(geometry);
    });
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
    return {
        transformProps: commonState.transformProps,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function index$5 (props, ctx, vcInstance) {
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const primitives = commonState.$services.primitives;
        const collection = vcInstance.cesiumObject;
        const object = primitives && primitives.add(collection);
        return Cesium.defined(object);
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        const primitives = commonState.$services.primitives;
        const collection = vcInstance.cesiumObject;
        return primitives && primitives.remove(collection);
    });
    const getServices = () => {
        return mergeDescriptors(commonState.getServices(), {
            get primitives() {
                return vcInstance.cesiumObject;
            }
        });
    };
    provide(vcKey, getServices());
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
    return {
        transformProps: commonState.transformProps,
        transformProp: commonState.transformProp,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function index$6 (props, ctx, vcInstance) {
    const commonState = useCommon(props, ctx, vcInstance);
    vcInstance.createCesiumObject = () => __awaiter(this, void 0, void 0, function* () {
        const options = commonState.transformProps(props);
        const primitives = commonState.$services.primitives;
        return primitives && primitives.add(options);
    });
    vcInstance.mount = () => __awaiter(this, void 0, void 0, function* () {
        const primitives = commonState.$services.primitives;
        const collectionItem = vcInstance.cesiumObject;
        return primitives && primitives.contains(collectionItem);
    });
    vcInstance.unmount = () => __awaiter(this, void 0, void 0, function* () {
        const primitives = commonState.$services.primitives;
        const collectionItem = vcInstance.cesiumObject;
        return primitives && !primitives.isDestroyed() && primitives.remove(collectionItem);
    });
    Object.assign(vcInstance.proxy, {
        createPromise: commonState.createPromise,
        load: commonState.load,
        unload: commonState.unload,
        reload: commonState.reload,
        cesiumObject: vcInstance.cesiumObject,
        getCesiumObject: () => vcInstance.cesiumObject
    });
    return {
        transformProps: commonState.transformProps,
        unwatchFns: commonState.unwatchFns,
        setPropsWatcher: commonState.setPropsWatcher
    };
}

function useVueCesium() {
    return inject(vcKey);
}

export { useCommon, index$2 as useDatasources, useEvents, index$4 as useGeometries, index as useGraphics, index$6 as usePrimitiveCollectionItems, index$5 as usePrimitiveCollections, index$3 as usePrimitives, index$1 as useProviders, useVueCesium };
