package com.bocloud.ims.service.transporter.vendor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.LocationDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.entity.enums.ServerAssetCategory;
import com.bocloud.cmp.model.*;
import com.bocloud.cmp.model.h3c.H3cSyncModel;
import com.bocloud.cmp.model.h3c.entity.*;
import com.bocloud.common.enums.OSCategory;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.exception.BoCloudDBException;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.common.utils.DateUtils;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.Ip.IpStatus;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.transporter.ResourceTransporter;
import com.bocloud.ims.service.utils.SyncH3cUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @ClassName: H3cTransportor.java
 * @Description: 同步H3c工具类
 * @author: ymh
 * @date: 2021年3月15日 下午4:58:43
 */
@Component
public class H3cTransporter implements ResourceTransporter {

    private static Logger logger = LoggerFactory.getLogger(H3cTransporter.class);
    @Autowired
    private VdcRepository vdcRepository; // 数据中心
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private StoreHostRepository storeHostRepository; // 存储与主机关系
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private NetworkHostRepository networkHostRepository; // 网络主机关系

    private SyncH3cUtils utils;
    @Autowired
    private ClusterNodeRepository clusterNodeRepository; // 集群节点
    @Autowired
    private ServerConfigRepository serverConfigRepository; // 主机配置
    @Autowired
    private ServerAssetsRepository serverAssetsRepository; // 主机资产
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private DataStoreFileRepository dataStoreFileRepository;
    @Autowired
    private IpPoolRepository ipPoolRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private LocationDriver locationDriver;
    @Autowired
    private PoolGroupRelationRepository poolGroupRelationRepository;

    /**
     * 同步平台实体
     *
     * @param vendor
     * @param data
     * @param userId
     */
    @Override
    public BocloudResult transport(CloudVendor vendor, Long userId) {
        try {
            BocloudResult bocloudResult = this.locationDriver.sync(vendor.getUuid());
            if (bocloudResult.isFailed()) {
                return bocloudResult;
            }
            Assert.notNull(bocloudResult.getData(), "数据同步异常！");
            Long vendorId = vendor.getId();

            if (null != bocloudResult.getData()) {
                if (cloudServerRepository.hasBuilding(vendorId)) {
                    return new BocloudResult(false, "该平台下有云主机正在创建，请稍后进行同步操作");
                }
                if (snapshotRepository.hasBuilding(vendorId)) {
                    return new BocloudResult(false, "该平台下有快照正在创建，请稍后进行同步操作");
                }

                String content = JSONObject.toJSONString(bocloudResult.getData());
                H3cSyncModel model = JSONObject.parseObject(content, H3cSyncModel.class);

                logger.info("start save vdc data ...... ");
                this.syncVdc(model.getVdcModels(), vendorId, userId, null);
                logger.info("end save vdc data ...... ");
                List<Vdc> vdcList = vdcRepository.listByVendor(vendorId);
                Map<String, Vdc> vdcMap = vdcList.stream()
                        .collect(Collectors.toMap(Vdc::getVdcVal, Function.identity(), (key1, key2) -> key2));

                logger.info("start save cluster data ...... ");
                this.syncCluster(model.getClusterModels(), vendorId, userId, vdcMap);
                logger.info("end save cluster data ...... ");
                List<Cluster> clusters = clusterRepository.listByVendor(vendorId);
                Map<String, Cluster> clusterMap = clusters.stream()
                        .collect(Collectors.toMap(Cluster::getClusterVal, Function.identity(), (key1, key2) -> key2));
                logger.info("start save Host data ...... ");
                this.syncHost(model.getHostModels(), vendor, userId, clusterMap, vdcMap);
                logger.info("end save Host data ...... ");
                List<Server> servers = serverRepository.listByVendor(vendorId);
                Map<String, Server> hostMap = servers.stream()
                        .collect(Collectors.toMap(Server::getUuid, Function.identity(), (key1, key2) -> key2));

                logger.info("start save Clouserver data ...... ");
                this.syncVms(model.getServerModels(), vendor, userId, clusterMap, hostMap, vdcMap);
                logger.info("end save Clouserver data ...... ");

                logger.info("start sava vmTemplate data ...... ");
                this.syncVmTemplates(model.getVmTemplateModels(), vendor, userId);
                logger.info("end save vmTemplate data ...... ");
            }
            return new BocloudResult(true, "云平台【" + vendor.getName() + "】平台数据同步成功");
        } catch (Exception e) {
            logger.error("Sync error:", e);
            return new BocloudResult(false, "同步h3c平台数据失败:" + e.getMessage());
        }
    }

    private void syncVmTemplates(List<RsDomain> vmTemplateModels, CloudVendor vendor, Long userId) {
        if (ListTool.isEmpty(vmTemplateModels)) {
            cloudServerRepository.removeTemplateByVid(vendor.getId(), userId);
            return;
        }
        List<CloudServer> listTemplate = cloudServerRepository.listTemplate(vendor.getId(), null);
        Map<String, CloudServer> templateMap = listTemplate.stream()
                .collect(Collectors.toMap(CloudServer::getInstanceId, Function.identity(), (key1, key2) -> key2));
        for (RsDomain domain : vmTemplateModels) {
            CloudServer cloudServer = new CloudServer();
            String instancdId = domain.getId() + "";
            if (templateMap.containsKey(instancdId)) {
                cloudServer = templateMap.get(instancdId);
                cloudServer.setName(domain.getName());
                cloudServer.setVendorId(vendor.getId());
                cloudServer.setRemark(domain.getDescription());
                cloudServer.setCpu(domain.getCpu());
                cloudServer.setPrivateIps(JSON.toJSONString(domain.getNetworks()));
                cloudServer.setMemory(new BigDecimal(domain.getMemory() / 1024));
                cloudServer.setDisk(new BigDecimal(domain.getStorageCapacity() / 1024).intValue());
                cloudServer.setInstanceId(instancdId);
                cloudServer.setIsTemplate(true);
                cloudServer.setOsName(domain.getOsBit());
                cloudServer.setOsVersion(domain.getOsVersion());
                cloudServer.setOsCategory(domain.getSystem().equals(0) ? "Windows" : "Linux");
                cloudServer.setOsVersion(domain.getOsVersion());
                cloudServer.setRecycle(false);
                cloudServer.setDataDisk(JSON.toJSONString(domain.getStorages()));
                cloudServerRepository.update(cloudServer);
                templateMap.remove(instancdId);
                continue;
            }
            cloudServer.setCreatorId(userId);
            cloudServer.setIsTemplate(true);
            cloudServer.setVendorId(vendor.getId());
            cloudServer.setMenderId(userId);
            cloudServer.setName(domain.getName());
            cloudServer.setPrivateIps(JSON.toJSONString(domain.getNetworks()));
            cloudServer.setRemark(domain.getDescription());
            cloudServer.setGmtVmCreate(domain.getCreateDate());
            cloudServer.setCpu(domain.getCpu());
            cloudServer.setOsName(domain.getOsBit());
            cloudServer.setOsVersion(domain.getOsVersion());
            cloudServer.setMemory(new BigDecimal(domain.getMemory() / 1024));
            cloudServer.setDisk(new BigDecimal(domain.getStorageCapacity() / 1024).intValue());
            cloudServer.setInstanceId(instancdId);
            cloudServer.setOsCategory(domain.getSystem().equals(0) ? "Windows" : "Linux");
            cloudServer.setOsVersion(domain.getOsVersion());
            cloudServer.setRecycle(false);
            cloudServer.setVendorType(vendor.getType());
            cloudServer.setGuid(UUID.randomUUID().toString());
            cloudServer.setDataDisk(JSON.toJSONString(domain.getStorages()));
            cloudServerRepository.save(cloudServer);
            templateMap.remove(instancdId);
        }
        for (Entry<String, CloudServer> entry : templateMap.entrySet()) {
            cloudServerRepository.remove(entry.getValue().getId(), userId);
        }

    }

    private void syncStoragePool(HostModel hostModel, CloudVendor vendor, Long userId, Map<String, Cluster> clusterMap,
                                 Server server, Map<String, Vdc> vdcMap) throws Exception {
        List<RsStoragePool> rsStoragePools = hostModel.getRsStoragePools();
        Long hostId = server.getId();
        List<DataStore> oldDataStores = dataStoreRepository.listByHost(hostId);
        if (ListTool.isEmpty(rsStoragePools)) {
            for (DataStore store : oldDataStores) {
                storeHostRepository.deleteByStore(store.getId());
                dataStoreRepository.remove(store.getId(), userId);
                // 删除存储与cmp资源池的关系
                poolGroupRelationRepository.removeByTarget(store.getId(), "Storage");
                dataStoreFileRepository.removeByDataStore(store.getId());
            }
            return;
        }
        Map<String, DataStore> oldDataStoreMap = Maps.newHashMap();
        for (DataStore oldDataStore : oldDataStores) {
            oldDataStoreMap.put(oldDataStore.getStoreVal(), oldDataStore);
        }

        for (RsStoragePool rsStoragePool : rsStoragePools) {
            String storagePoolUuid = hostModel.getUuid() + "_" + rsStoragePool.getName();
            DataStore dataStore = new DataStore();
            if (oldDataStoreMap.containsKey(storagePoolUuid)) {
                dataStore = oldDataStoreMap.get(storagePoolUuid);
                dataStore.setStoreVal(storagePoolUuid);
                dataStore.setName(rsStoragePool.getName());
                dataStore.setCapacity(BigDecimal.valueOf(rsStoragePool.getTotalSize())
                        .divide(BigDecimal.valueOf(1024), 2, BigDecimal.ROUND_HALF_UP).longValue());
                dataStore.setFreeSpace(BigDecimal.valueOf(rsStoragePool.getFreeSize())
                        .divide(BigDecimal.valueOf(1024), 2, BigDecimal.ROUND_HALF_UP).longValue());
                if (clusterMap.containsKey(hostModel.getClusterUuid())
                        && null != clusterMap.get(hostModel.getClusterUuid())) {
                    dataStore.setVdcId(clusterMap.get(hostModel.getClusterUuid()).getVdcId());
                }
                dataStore.setMenderId(userId);
                dataStore.setServerId(hostId);
                dataStore.setHostNum(1);
                dataStore.setType(rsStoragePool.getType());
                dataStore.setPath(rsStoragePool.getPath());
                // 状态。1 表示活动状态， 0 表示不活动状态
                dataStore.setStatus(String.valueOf(rsStoragePool.getStatus()));
                dataStoreRepository.update(dataStore);
                List<StoreHost> storeHosts = storeHostRepository.list(dataStore.getId(), hostId, vendor.getId(), "PM");
                if (ListTool.isEmpty(storeHosts)) {
                    StoreHost entity = new StoreHost(dataStore.getId(), hostId, vendor.getId(), "PM");
                    storeHostRepository.save(entity);
                }
                List<RsStorageVolume> rsStorageVolumes = rsStoragePool.getRsStorageVolumes();
                syncStoreFile(rsStorageVolumes, vendor.getId(), hostId, userId, dataStore);
                oldDataStoreMap.remove(dataStore.getStoreVal());
            } else {
                dataStore.setGuid(UUID.randomUUID().toString());
                dataStore.setStoreVal(storagePoolUuid);
                dataStore.setName(rsStoragePool.getName());
                dataStore.setCapacity(
                        BigDecimal.valueOf(rsStoragePool.getTotalSize()).divide(BigDecimal.valueOf(1024)).longValue());
                dataStore.setFreeSpace(
                        BigDecimal.valueOf(rsStoragePool.getFreeSize()).divide(BigDecimal.valueOf(1024)).longValue());
                if (clusterMap.containsKey(hostModel.getClusterUuid())
                        && null != clusterMap.get(hostModel.getClusterUuid())) {
                    dataStore.setVdcId(clusterMap.get(hostModel.getClusterUuid()).getVdcId());
                }
                dataStore.setMenderId(userId);
                dataStore.setHostNum(1);
                dataStore.setServerId(hostId);
                dataStore.setType(rsStoragePool.getType());
                dataStore.setPath(rsStoragePool.getPath());
                // 状态。1 表示活动状态， 0 表示不活动状态
                dataStore.setStatus(String.valueOf(rsStoragePool.getStatus()));
                dataStore.setCreatorId(userId);
                dataStore.setVendorId(vendor.getId());
                dataStoreRepository.save(dataStore);
                StoreHost entity = new StoreHost(dataStore.getId(), hostId, vendor.getId(), "PM");
                storeHostRepository.save(entity);
                List<RsStorageVolume> rsStorageVolumes = rsStoragePool.getRsStorageVolumes();
                syncStoreFile(rsStorageVolumes, vendor.getId(), hostId, userId, dataStore);
            }
        }
        for (Entry<String, DataStore> entry : oldDataStoreMap.entrySet()) {
            dataStoreRepository.remove(entry.getValue().getId(), userId);
            storeHostRepository.deleteByStore(entry.getValue().getId());
            // 删除存储与cmp资源池的关系
            poolGroupRelationRepository.removeByTarget(entry.getValue().getId(), "Storage");
            dataStoreFileRepository.removeByDataStore(entry.getValue().getId());
        }
    }

    public void syncStoreFile(List<RsStorageVolume> rsStorageVolumes, Long vendorId, Long hostId, Long userId,
                              DataStore dataStore) throws Exception {
        if (ListTool.isEmpty(rsStorageVolumes)) {
            dataStoreFileRepository.removeByDataStore(dataStore.getId());
            return;
        }
        List<DataStoreFile> dataStoreFiles = dataStoreFileRepository.listByDataStore(dataStore.getId());
        Map<String, DataStoreFile> dataStoreFileMap = dataStoreFiles.stream()
                .collect(Collectors.toMap(DataStoreFile::getName, Function.identity(), (key1, key2) -> key2));

        for (RsStorageVolume rsStorageVolume : rsStorageVolumes) {
            String storageVolumeName = rsStorageVolume.getName();
            DataStoreFile dataStoreFile = new DataStoreFile();
            if (dataStoreFileMap.containsKey(storageVolumeName)) {
                dataStoreFile = dataStoreFileMap.get(storageVolumeName);
                dataStoreFile.setSize(BigDecimal.valueOf(rsStorageVolume.getSize()).divide(BigDecimal.valueOf(1024))
                        .setScale(2, BigDecimal.ROUND_HALF_UP));
                dataStoreFile.setAllocation(BigDecimal.valueOf(rsStorageVolume.getAllocation())
                        .divide(BigDecimal.valueOf(1024)).setScale(2, BigDecimal.ROUND_HALF_UP));
                dataStoreFile.setVdcId(dataStore.getVdcId());
                dataStoreFile.setHostId(hostId);
                dataStoreFile.setStoreId(dataStore.getId());
                dataStoreFile.setFormat(rsStorageVolume.getFormat());
                dataStoreFile
                        .setUsers(StringUtils.isEmpty(rsStorageVolume.getUsers()) ? null : rsStorageVolume.getUsers());
                dataStoreFileRepository.update(dataStoreFile);
                dataStoreFileMap.remove(storageVolumeName);
            } else {
                dataStoreFile.setName(storageVolumeName);
                dataStoreFile.setSize(BigDecimal.valueOf(rsStorageVolume.getSize()).divide(BigDecimal.valueOf(1024))
                        .setScale(2, BigDecimal.ROUND_HALF_UP));
                dataStoreFile.setAllocation(BigDecimal.valueOf(rsStorageVolume.getAllocation())
                        .divide(BigDecimal.valueOf(1024)).setScale(2, BigDecimal.ROUND_HALF_UP));
                dataStoreFile.setVdcId(dataStore.getVdcId());
                dataStoreFile.setVendorId(vendorId);
                dataStoreFile.setHostId(hostId);
                dataStoreFile.setStoreId(dataStore.getId());
                dataStoreFile.setCreatorId(userId);
                dataStoreFile.setFormat(rsStorageVolume.getFormat());
                dataStoreFile
                        .setUsers(StringUtils.isEmpty(rsStorageVolume.getUsers()) ? null : rsStorageVolume.getUsers());
                dataStoreFileRepository.save(dataStoreFile);
            }
        }
        for (Entry<String, DataStoreFile> entry : dataStoreFileMap.entrySet()) {
            dataStoreFileRepository.remove(entry.getValue().getId(), userId);
        }
    }

    // 数据中心状态转换
    public String dataStoreStatusConvertor(Integer statusNum) {
        String status = "inactive";
        switch (statusNum) {
            case 1:
                status = "green";
                break;
            case 0:
                break;
            default:
                break;
        }
        return status;
    }

    private void syncVswitchs(HostModel hostModel, CloudVendor vendor, Long userId, Map<String, Cluster> clusterMap,
                              Server server, Map<String, Vdc> vdcMap) throws Exception {

        List<RsVSwitch> h3cSwitchers = hostModel.getH3cSwitchers();
        Long hostId = server.getId();
        // 同步主机标准交换机
        List<Switcher> oldSwitchers = switcherRepository.listByHostId(hostId);
        if (ListTool.isEmpty(h3cSwitchers)) {
            for (Switcher switcher : oldSwitchers) {
                List<Network> networks = networkRepository.listBySwitcher(switcher.getId());
                for (Network network : networks) {
                    networkRepository.remove(network.getId(), userId);
                    subnetRepository.removeByNetworkId(network.getId(), userId);
                }

            }
            switcherRepository.removeByHostId(hostId, userId);
            return;
        }
        Map<String, Switcher> oldMap = Maps.newHashMap();
        if (!ListTool.isEmpty(oldSwitchers)) {
            for (Switcher switcher : oldSwitchers) {
                oldMap.put(switcher.getSwitcherVal(), switcher);
            }
        }
        for (RsVSwitch rsVSwitch : h3cSwitchers) {
            String vswitchUuid = rsVSwitch.getId() + "";
            Switcher switcher = new Switcher();
            if (oldMap.containsKey(vswitchUuid)) {
                switcher = oldMap.get(vswitchUuid);
                switcher.setSwitcherVal(vswitchUuid);
                switcher.setPortNum(rsVSwitch.getPortNum());
                switcher.setGmtModify(new Date());
                switcher.setHostId(hostId);
                switcher.setVendorId(vendor.getId());
                switcher.setNetworkType(rsVSwitch.getNetworkType());
                switcher.setVdcId(server.getVdcId());
                switcher.setName(rsVSwitch.getName());
                switcher.setStatus(String.valueOf(rsVSwitch.getStatus()));
                switcher.setPolicy(rsVSwitch.getBondMode());
                switcher.setRemark(rsVSwitch.getDescription());
                switcher.setActiveNics(rsVSwitch.getPnic());
                // 转发模式。0 : veb; 1: vepa; 2:多通道。
                switcher.setProps(String.valueOf(rsVSwitch.getMode()));
                switcherRepository.update(switcher);
                syncNetworks(rsVSwitch, vendor.getId(), server.getVdcId(), userId, switcher.getId());
                // 移除存在更新的交换机
                oldMap.remove(switcher.getSwitcherVal());
            } else {
                switcher.setHostId(hostId);
                switcher.setVendorId(vendor.getId());
                switcher.setGuid(UUID.randomUUID().toString());
                switcher.setActiveNics(rsVSwitch.getPnic());
                switcher.setNetworkType(rsVSwitch.getNetworkType());
                switcher.setRemark(rsVSwitch.getDescription());
                switcher.setSwitcherVal(vswitchUuid);
                switcher.setPortNum(rsVSwitch.getPortNum());
                switcher.setStatus(String.valueOf(rsVSwitch.getStatus()));
                switcher.preSave(userId, userId, vendor.getId(), server.getVdcId(), hostId);
                switcher.setType("VSWITCH");
                // 转发模式。0 : veb; 1: vepa; 2:多通道。
                switcher.setProps(String.valueOf(rsVSwitch.getMode()));
                switcherRepository.save(switcher);
                syncNetworks(rsVSwitch, vendor.getId(), server.getVdcId(), userId, switcher.getId());
            }
        }
        for (Entry<String, Switcher> entry : oldMap.entrySet()) {
            switcherRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncNetworks(RsVSwitch rsVSwitch, Long vendorId, Long vdcId, Long userId, Long switcherId) {
        List<Network> oldNetworks = networkRepository.listBySwitcher(switcherId);
        Network network = null;
        if (ListTool.isEmpty(oldNetworks)) {
            network = new Network();
            network.setSwitcherId(switcherId);
            network.setGuid(UUID.randomUUID().toString());
            network.setName(rsVSwitch.getName());
            network.setType("VSWITCH");
            network.preSave(userId, userId, vendorId, vdcId);
            network.setGmtModify(new Date());
            networkRepository.save(network);
            syncSubnets(network, rsVSwitch, vendorId, userId);
        } else {
            network = oldNetworks.get(0);
            network.setSwitcherId(switcherId);
            network.setName(rsVSwitch.getName());
            network.preSave(userId, userId, vendorId, vdcId);
            network.setGmtModify(new Date());
            networkRepository.update(network);
            syncSubnets(network, rsVSwitch, vendorId, userId);
        }
    }

    private void syncSubnets(Network network, RsVSwitch rsVSwitch, Long vendorId, Long userId) {
        List<Subnet> subnets = subnetRepository.listByNetwork(network.getId());
        Subnet subnet = null;
        if (ListTool.isEmpty(subnets)) {
            subnet = new Subnet();
            subnet.setName(rsVSwitch.getName());
            subnet.setCreatorId(userId);
            subnet.setCreatorId(userId);
            subnet.setMenderId(userId);
            subnet.setVendorId(vendorId);
            subnet.setAddress(rsVSwitch.getAddress());
            subnet.setGateway(rsVSwitch.getGateway());
            subnet.setCidr(rsVSwitch.getNetmask());
            subnet.setNetworkId(network.getId());
            subnetRepository.save(subnet);
        } else {
            subnet = subnets.get(0);
            subnet.setName(rsVSwitch.getName());
            subnet.setAddress(rsVSwitch.getAddress());
            subnet.setGateway(rsVSwitch.getGateway());
            subnet.setCidr(rsVSwitch.getNetmask());
            subnet.setGmtModify(new Date());
            subnetRepository.update(subnet);
        }
    }

    private void syncVms(List<RsDomain> serverModels, CloudVendor vendor, Long userId, Map<String, Cluster> clusterMap,
                         Map<String, Server> hostMap, Map<String, Vdc> vdcMap) {
        if (ListTool.isEmpty(serverModels)) {
            cloudServerRepository.removeByVid(vendor.getId(), userId);
            return;
        }
        List<CloudServer> cloudServers = cloudServerRepository.listByVendorId(vendor.getId());
        Map<String, CloudServer> cloudServerMap = cloudServers.stream()
                .collect(Collectors.toMap(CloudServer::getInstanceId, Function.identity(), (key1, key2) -> key2));

        for (RsDomain domain : serverModels) {
            CloudServer cloudServer = new CloudServer();
            String instancdId = domain.getId() + "";
            if (cloudServerMap.containsKey(instancdId)) {
                cloudServer = cloudServerMap.get(instancdId);
                cloudServer.setName(domain.getTitle());
                cloudServer.setStatus(statusConvertor(domain.getStatus()));
                cloudServer.setVendorId(vendor.getId());
                cloudServer.setRemark(domain.getDescription());
                cloudServer.setCpu(domain.getCpu());
                cloudServer.setMemory(new BigDecimal(domain.getMemory() / 1024));
                cloudServer.setDisk(getBootVolumeSize(domain.getStorages()));
                List<RsDomainNetwork> networks = domain.getNetworks();
                List<String> currentVmIps = new ArrayList<String>();
                if (!ListTool.isEmpty(networks)) {
                    for (RsDomainNetwork rsDomainNetwork : networks) {
                        rsDomainNetwork.setAddress(rsDomainNetwork.getIpAddr());
                        currentVmIps.add(rsDomainNetwork.getIpAddr());
                    }
                    cloudServer.setPrivateIps(JSON.toJSONString(networks));
                    cloudServer.setManagerIp(networks.get(0).getIpAddr());
                }
                cloudServer.setInstanceId(instancdId);
                cloudServer.setOsCategory(domain.getOsDesc());
                cloudServer.setOsName(domain.getOsBit());
                cloudServer.setOsVersion(domain.getOsVersion());
                if (hostMap.containsKey(domain.getHostId() + "") && null != hostMap.get(domain.getHostId() + "")) {
                    cloudServer.setHostId(hostMap.get(domain.getHostId() + "").getId());
                }
                if (vdcMap.containsKey(domain.getHostPoolId() + "")
                        && null != vdcMap.get(domain.getHostPoolId() + "")) {
                    cloudServer.setVdcId(vdcMap.get(domain.getHostPoolId() + "").getId());
                }
                cloudServer.setRecycle(false);
                cloudServerRepository.update(cloudServer);
                if (!ListTool.isEmpty(currentVmIps)) {
                    for (String vmIp : currentVmIps) {
                        syncIps(vmIp, "VM", cloudServer.getVendorId(), cloudServer.getId());
                    }
                }
                syncVolumes(cloudServer, domain, userId);
                syncVmSnapshots(domain, cloudServer, userId, vendor.getId());
                cloudServerMap.remove(instancdId);
                continue;
            }
            cloudServer.setCreatorId(0L);
            cloudServer.setIsTemplate(false);
            cloudServer.setVendorId(vendor.getId());
            cloudServer.setMenderId(0L);
            cloudServer.setName(domain.getTitle());
            cloudServer.setStatus(statusConvertor(domain.getStatus()));
            cloudServer.setRemark(domain.getDescription());
            cloudServer.setGmtVmCreate(domain.getCreateDate());
            cloudServer.setCpu(domain.getCpu());
            cloudServer.setMemory(new BigDecimal(domain.getMemory() / 1024));
            cloudServer.setDisk(getBootVolumeSize(domain.getStorages()));
            List<RsDomainNetwork> networks = domain.getNetworks();
            List<String> currentVmIps = new ArrayList<String>();
            if (!ListTool.isEmpty(networks)) {
                for (RsDomainNetwork rsDomainNetwork : networks) {
                    rsDomainNetwork.setAddress(rsDomainNetwork.getIpAddr());
                    currentVmIps.add(rsDomainNetwork.getIpAddr());
                }
                cloudServer.setPrivateIps(JSON.toJSONString(networks));
                cloudServer.setManagerIp(networks.get(0).getIpAddr());
            }
            cloudServer.setInstanceId(instancdId);
            cloudServer.setOsCategory(domain.getOsDesc());
            cloudServer.setOsName(domain.getOsBit());
            cloudServer.setOsVersion(domain.getOsVersion());
            cloudServer.setVendorType(vendor.getType());
            cloudServer.setGuid(UUID.randomUUID().toString());
            if (hostMap.containsKey(domain.getHostId() + "") && null != hostMap.get(domain.getHostId() + "")) {
                cloudServer.setHostId(hostMap.get(domain.getHostId() + "").getId());
            }
            if (vdcMap.containsKey(domain.getHostPoolId() + "") && null != vdcMap.get(domain.getHostPoolId() + "")) {
                cloudServer.setVdcId(vdcMap.get(domain.getHostPoolId() + "").getId());
            }
            cloudServer.setRecycle(false);
            cloudServer.setTenantId(0L);
            cloudServer.setProjectId(0L);
            cloudServer.setBusinessId(0L);
            cloudServer.setRecycle(false);
            cloudServerRepository.save(cloudServer);
            if (!ListTool.isEmpty(currentVmIps)) {
                for (String vmIp : currentVmIps) {
                    syncIps(vmIp, "VM", cloudServer.getVendorId(), cloudServer.getId());
                }
            }
            syncVolumes(cloudServer, domain, userId);
            syncVmSnapshots(domain, cloudServer, userId, vendor.getId());
            cloudServerMap.remove(instancdId);
        }
        for (Entry<String, CloudServer> entry : cloudServerMap.entrySet()) {
            cloudServerRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncVmSnapshots(RsDomain domain, CloudServer cloudServer, Long userId, Long vendorId) {
        List<RsSnapshot> rsSnapshots = domain.getRsSnapshots();
        if (ListTool.isEmpty(rsSnapshots)) {
            snapshotRepository.removeByVm(cloudServer.getId(), userId);
            return;
        }
        List<Snapshot> snapshots = snapshotRepository.listByVMid(cloudServer.getId());
        Map<String, Snapshot> snapshotMap = Maps.newHashMap();
        for (Snapshot snapshot : snapshots) {
            String key = cloudServer.getId() + "_" + snapshot.getName();
            if (snapshotMap.containsKey(key)) {
                snapshotRepository.remove(snapshot.getId(), userId);
            } else {
                snapshotMap.put(key, snapshot);
            }
        }
        for (RsSnapshot rsSnapshot : rsSnapshots) {
            Snapshot snapshot = new Snapshot();
            String key = cloudServer.getId() + "_" + rsSnapshot.getName();
            if (snapshotMap.containsKey(key)) {
                snapshot = snapshotMap.get(key);
                snapshot.setCreateTime(DateUtils.stringToDate(rsSnapshot.getCreationTime(), "yyyy-MM-dd HH:ss:mm"));
                snapshot.setName(rsSnapshot.getName());
                snapshot.setSnapshotUuid(rsSnapshot.getName());
                snapshot.setSnapshotVal(rsSnapshot.getName());
                snapshot.setRemark(rsSnapshot.getDesc());
                snapshot.setSnapshotType("VM");
                snapshot.setKeyPath(rsSnapshot.getSnapshotTitle());
                snapshotRepository.update(snapshot);
                snapshotMap.remove(key);
                continue;
            }
            snapshot.setCreatorId(userId);
            snapshot.setVendorId(vendorId);
            snapshot.setMenderId(userId);
            snapshot.setCreateTime(DateUtils.stringToDate(rsSnapshot.getCreationTime(), "yyyy-MM-dd HH:ss:mm"));
            snapshot.setName(rsSnapshot.getName());
            snapshot.setSnapshotUuid(rsSnapshot.getName());
            snapshot.setSnapshotVal(rsSnapshot.getName());
            snapshot.setRemark(rsSnapshot.getDesc());
            snapshot.setStatus("AVAILABLE");
            snapshot.setVmId(cloudServer.getId());
            snapshot.setSnapshotType("VM");
            snapshot.setKeyPath(rsSnapshot.getSnapshotTitle());
            snapshotRepository.save(snapshot);
            snapshotMap.remove(key);
        }
        for (Entry<String, Snapshot> entry : snapshotMap.entrySet()) {
            snapshotRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步云主机下的盘符
     *
     * @param cloudServer
     * @param domain
     * @param userId
     */
    public void syncVolumes(CloudServer cloudServer, RsDomain domain, Long userId) {
        List<RsDomainStorage> storages = domain.getStorages();
        if (ListTool.isEmpty(storages)) {
            volumeRepository.removeByServerId(cloudServer.getId(), userId);
            return;
        }
        List<Volume> volumes = volumeRepository.listByServerId(cloudServer.getId());
        Map<String, Volume> volumeMap = Maps.newHashMap();
        for (Volume volume : volumes) {
            String key = cloudServer.getId() + "_" + volume.getDevice() + "_" + volume.getFileSystem();
            if (volumeMap.containsKey(key)) {
                volumeRepository.remove(volume.getId(), userId);
            } else {
                volumeMap.put(key, volume);
            }
        }
        for (RsDomainStorage model : storages) {
            if (null == model.getCapacity() || 0 == model.getCapacity() || StringUtils.isEmpty(model.getDevice())
                    || !"disk".equalsIgnoreCase(model.getDiskDevice()) || StringUtils.isEmpty(model.getStoreFile())) {
                continue;
            }
            String storeFile = model.getStoreFile();
            String volumeName = storeFile.substring(storeFile.lastIndexOf("/") + 1);
            String storagePoolPath = storeFile.substring(0, storeFile.lastIndexOf("/"));
            DataStore dataStore = dataStoreRepository.getByServerId(cloudServer.getHostId(), storagePoolPath);
            Volume volume = new Volume();
            String key = cloudServer.getId() + "_" + model.getDevice() + "_" + model.getStoreFile();
            if (volumeMap.containsKey(key)) {
                volume = volumeMap.get(key);
                volume.setServerId(cloudServer.getId());
                volume.setInstanceId(cloudServer.getInstanceId());
                volume.setSize(model.getCapacity().intValue() / 1024);
                volume.setFileSystem(model.getStoreFile());
                volume.setVolumeType(model.getType());
                volume.setName(volumeName);
                volume.setVendorId(cloudServer.getVendorId());
                String device = model.getDevice();
                volume.setDevice(model.getDevice());
                volume.setBootVolume("vda".equalsIgnoreCase(device));
                volume.setDeleteWithInstance("vda".equalsIgnoreCase(device));
                volume.setStatus("IN-USE");
                if (null != dataStore) {
                    volume.setDataStoreId(dataStore.getId());
                }
                volumeRepository.update(volume);
                volumeMap.remove(key);
                continue;
            }
            volume.setCreatorId(userId);
            volume.setVendorId(cloudServer.getVendorId());
            volume.setMenderId(userId);
            volume.setStatus("IN-USE");
            volume.setServerId(cloudServer.getId());
            volume.setInstanceId(cloudServer.getInstanceId());
            volume.setSize(model.getCapacity().intValue() / 1024);
            volume.setFileSystem(model.getStoreFile());
            volume.setName(volumeName);
            String device = model.getDevice();
            volume.setDevice(model.getDevice());
            volume.setBootVolume("vda".equalsIgnoreCase(device));
            volume.setDeleteWithInstance("vda".equalsIgnoreCase(device));
            volume.setVolumeType(model.getType());
            if (null != dataStore) {
                volume.setDataStoreId(dataStore.getId());
            }
            volumeRepository.save(volume);
            volumeMap.remove(key);
        }
        for (Entry<String, Volume> entry : volumeMap.entrySet()) {
            volumeRepository.remove(entry.getValue().getId(), userId);
        }

    }

    public Integer getBootVolumeSize(List<RsDomainStorage> storages) {
        Integer diskSize = 0;
        if (!ListTool.isEmpty(storages)) {
            for (RsDomainStorage rsDomainStorage : storages) {
                if ("vda".equalsIgnoreCase(rsDomainStorage.getDevice()) && rsDomainStorage.getCapacity() > 0) {
                    diskSize = (rsDomainStorage.getCapacity().intValue() / 1024);
                    break;
                }
            }
        }
        return diskSize;
    }

    // 云主机状态。 2：运行 3：关闭 4：暂停。
    public String statusConvertor(Integer statusNum) {
        String status = BocloudStatus.Server.EXCEPTION.name();
        switch (statusNum) {
            case 1:
            case 2:
                status = BocloudStatus.Server.RUNNING.name();
                break;
            case 0:
            case 3:
                status = BocloudStatus.Server.STOPPED.name();
                break;
            case 4:
                status = BocloudStatus.Server.PAUSED.name();
                break;
            default:
                break;
        }
        return status;
    }

    public void syncHost(List<HostModel> hostModels, CloudVendor vendor, Long userId, Map<String, Cluster> clusterMap,
                         Map<String, Vdc> vdcMap) throws Exception {
        Long vendorId = vendor.getId();
        if (ListTool.isEmpty(hostModels)) {
            serverRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<Server> servers = serverRepository.listByVendor(vendorId);
        Map<String, Server> serverMap = servers.stream()
                .collect(Collectors.toMap(Server::getUuid, Function.identity(), (key1, key2) -> key2));

        for (HostModel model : hostModels) {
            Server server = new Server();
            String serverUuid = model.getUuid();
            if (serverMap.containsKey(serverUuid)) {
                server = serverMap.get(serverUuid);
                if (clusterMap.containsKey(model.getClusterUuid()) && null != clusterMap.get(model.getClusterUuid())) {
                    server.setClusterId(clusterMap.get(model.getClusterUuid()).getId());
                    server.setVdcId(clusterMap.get(model.getClusterUuid()).getVdcId());
                }
                server.setManageIp(model.getHostIp());
                server.setUuid(serverUuid);
                server.setStatus(model.getStatus());
                server.setPowerState(model.getPowerState());
                server.setName(model.getName());
                server.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
                server.setCpuModel(model.getCpuModel());
                server.setOsCategory(model.getOsCategory());
                serverRepository.update(server);
                syncIps(model.getHostIp(), "PM", vendorId, server.getId());
                List<String> privateIps = Lists.newArrayList();
                privateIps.add(server.getManageIp());
                syncResource(ResourceCatalog.PHYSICAL.name(), server.getId(), JSON.toJSONString(server),
                        server.getName(), server.getPowerState(), JSON.toJSONString(privateIps), vendorId, userId, 0L,
                        0L);
                syncServerConfig(server.getId(), vendorId, userId, model);
                // 同步主机下的交换机
                logger.info("start save Vswitchs data ....... ");
                syncVswitchs(model, vendor, userId, clusterMap, server, vdcMap);
                logger.info("end save Vswitchs data ....... ");
                // 同步主机下的存储池
                logger.info("start save StoragePool data ....... ");
                syncStoragePool(model, vendor, userId, clusterMap, server, vdcMap);
                logger.info("end save StoragePool data ....... ");
                // 同步物理网卡
                logger.info("start save networkcard data ....... ");
                syncNetworkCard(model, vendor, userId, server);
                logger.info("end save networkcard data ....... ");
                serverMap.remove(serverUuid);
                continue;
            }
            server.setCreatorId(userId);
            server.setVendorId(vendorId);
            server.setMenderId(userId);
            if (clusterMap.containsKey(model.getClusterUuid()) && null != clusterMap.get(model.getClusterUuid())) {
                server.setClusterId(clusterMap.get(model.getClusterUuid()).getId());
                server.setVdcId(clusterMap.get(model.getClusterUuid()).getVdcId());
            }
            server.setManageIp(model.getHostIp());
            server.setUuid(serverUuid);
            server.setStatus(model.getStatus());
            server.setPowerState(model.getPowerState());
            server.setName(model.getName());
            server.setVendorId(vendorId);
            server.setMenderId(userId);
            server.setCreatorId(userId);
            server.setGuid(UUID.randomUUID().toString());
            server.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
            server.setCpuModel(model.getCpuModel());
            server.setOsCategory(model.getOsCategory());
            serverRepository.save(server);
            syncIps(model.getHostIp(), "PM", vendorId, server.getId());
            List<String> privateIps = Lists.newArrayList();
            privateIps.add(server.getManageIp());
            syncResource(ResourceCatalog.PHYSICAL.name(), server.getId(), JSON.toJSONString(server), server.getName(),
                    server.getPowerState(), JSON.toJSONString(privateIps), vendorId, userId, 0L, 0L);
            syncServerConfig(server.getId(), vendorId, userId, model);
            // 同步主机下的交换机
            logger.info("start save Vswitchs data ....... ");
            syncVswitchs(model, vendor, userId, clusterMap, server, vdcMap);
            logger.info("end save Vswitchs data ....... ");
            // 同步主机下的存储池
            logger.info("start save StoragePool data ....... ");
            syncStoragePool(model, vendor, userId, clusterMap, server, vdcMap);
            logger.info("end save StoragePool data ....... ");
            // 同步物理网卡
            logger.info("start save networkcard data ....... ");
            syncNetworkCard(model, vendor, userId, server);
            logger.info("end save networkcard data ....... ");
            serverMap.remove(serverUuid);
        }
        for (Entry<String, Server> entry : serverMap.entrySet()) {
            serverRepository.remove(entry.getValue().getId(), userId);
        }

    }

    private void syncNetworkCard(HostModel model, CloudVendor vendor, Long userId, Server server) throws Exception {
        List<NetworkCardModel> netcards = model.getNetcards();
        if (ListTool.isEmpty(netcards)) {
            networkCardRepository.removeByHost(server.getId(), "PM", userId);
            return;
        }
        List<NetworkCard> networkCards = networkCardRepository.listByHost(server.getId(), "PM");
        Map<String, NetworkCard> networkCardMap = Maps.newHashMap();
        for (NetworkCard networkCard : networkCards) {
            String key = server.getId() + "_" + networkCard.getName();
            if (networkCardMap.containsKey(key)) {
                networkCardRepository.remove(networkCard.getId(), userId);
            } else {
                networkCardMap.put(key, networkCard);
            }
        }
        for (NetworkCardModel networkCardModel : netcards) {
            NetworkCard networkCard = new NetworkCard();
            String key = server.getId() + "_" + networkCardModel.getName();
            if (networkCardMap.containsKey(key)) {
                networkCard = networkCardMap.get(key);
                networkCard.setName(networkCardModel.getName());
                networkCard.setRemark(networkCardModel.getRemark());
                networkCard.setUsed(networkCardModel.getUsed());
                networkCard.setCategory("PM");
                networkCard.setMac(networkCardModel.getMac());
                networkCard.setHostId(server.getId());
                networkCardRepository.update(networkCard);
                networkCardMap.remove(key);
                continue;
            }
            networkCard.setCreatorId(userId);
            networkCard.setOwnerId(userId);
            networkCard.setVendorId(vendor.getId());
            networkCard.setMenderId(userId);
            networkCard.setName(networkCardModel.getName());
            networkCard.setRemark(networkCardModel.getRemark());
            networkCard.setHostId(server.getId());
            networkCard.setUsed(networkCardModel.getUsed());
            networkCard.setCategory("PM");
            networkCard.setMac(networkCardModel.getMac());
            networkCardRepository.save(networkCard);
            networkCardMap.remove(key);
        }
        for (Entry<String, NetworkCard> entry : networkCardMap.entrySet()) {
            networkCardRepository.remove(entry.getValue().getId(), userId);
        }

    }

    public void syncIps(String ipAddress, String catalog, Long vendorId, Long target) {
        // 处理IP地址
        if (StringUtils.isEmpty(ipAddress)) {
            return;
        }
        try {
            Ip ipExist = ipRepository.checkExist(ipAddress, 0L, vendorId);
            if (null == ipExist) {
                Ip ip = new Ip(ipAddress, null, null, null, vendorId, IDFactory.instance().uuid(), null, IpStatus.used);
                ip.setCatalog(catalog);
                ip.setTarget(target);
                ipRepository.save(ip);
            } else {
                ipExist.setCatalog(catalog);
                ipExist.setTarget(target);
                ipRepository.update(ipExist);
            }
        } catch (BoCloudDBException e) {
            logger.error("处理IP异常 catalog :" + catalog + " target : " + target + " vendorId : " + vendorId
                    + " ipAddress : " + ipAddress);
        }
    }

    private void syncServerConfig(Long hostId, Long vendorId, Long userId, HostModel hostModel) {
        // 保存主机配置信息
        ServerConfig config = serverConfigRepository.getBySid(hostId);
        if (null != config) {
            config.setDiskCapacity(BigDecimal.valueOf(hostModel.getDiskTotal())
                    .divide(BigDecimal.valueOf(1024), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
            config.setCpuHz(hostModel.getCpuTotal());
            config.setMemoryCapacity(hostModel.getMemTotal());
            config.setCpuAmount(hostModel.getCpuNum());
            config.setCpuMode(hostModel.getCpuModel());
            config.setCpuCore(hostModel.getCpuCore());
            config.setCpuUsed(hostModel.getCpuUsed());
            config.setMemUsed(hostModel.getMemUsed());
            config.setDiskUsed(hostModel.getDiskUsed());
            config.setVendor(hostModel.getVendor());
            config.setEsxVersion(hostModel.getEsxVersion());
            config.setEvc(hostModel.getEvc());
            config.setAssignedLicense(hostModel.getAssignedLicense());
            config.setIpmiAddress(hostModel.getIpmiAddress());
            config.setIpmiAccount(hostModel.getIpmiAccount());
            config.setIpmiPassword(hostModel.getIpmiPassword());
            config.setIpmiPort(623);
            serverConfigRepository.update(config);
        } else {
            config = new ServerConfig();
            config.setDiskCapacity(BigDecimal.valueOf(hostModel.getDiskTotal())
                    .divide(BigDecimal.valueOf(1024), 2, BigDecimal.ROUND_HALF_UP).doubleValue());
            config.setCpuHz(hostModel.getCpuTotal());
            config.setMemoryCapacity(hostModel.getMemTotal());
            config.setCpuAmount(hostModel.getCpuNum());
            config.setCpuMode(hostModel.getCpuModel());
            config.setCpuCore(hostModel.getCpuCore());
            config.setCpuUsed(hostModel.getCpuUsed());
            config.setMemUsed(hostModel.getMemUsed());
            config.setDiskUsed(hostModel.getDiskUsed());
            config.setServerId(hostId);
            config.setVendor(hostModel.getVendor());
            config.setEsxVersion(hostModel.getEsxVersion());
            config.setEvc(hostModel.getEvc());
            config.setAssignedLicense(hostModel.getAssignedLicense());
            config.setIpmiAddress(hostModel.getIpmiAddress());
            config.setIpmiAccount(hostModel.getIpmiAccount());
            config.setIpmiPassword(hostModel.getIpmiPassword());
            config.setIpmiPort(623);
            serverConfigRepository.save(config);
        }
    }

    public void syncResource(String catalog, Long targetId, String inventory, String name, String status,
                             String privateIps, Long vendorId, Long userId, Long tenantId, Long projectId) {
        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(), catalog, targetId);
        if (null == resource) {
            resource = new Resource(ResourceCategory.Computer.name(), catalog, targetId,
                    JSONObject.toJSONString(privateIps), OSCategory.LINUX.name(), vendorId);
            resource.preSave(name, status, userId, tenantId, projectId);
            resource.setInventory(inventory);
            resourceRepository.save(resource);
        } else {
            resource.setStatus(status);
            resource.setPrivateIps(privateIps);
            resource.setMenderId(userId);
            resource.setGmtModify(new Date());
            resource.setMenderId(userId);
            resourceRepository.update(resource);
        }
    }

    private void syncCluster(List<ClusterModel> clusterModels, Long vendorId, Long userId, Map<String, Vdc> vdcMap) {
        if (ListTool.isEmpty(clusterModels)) {
            clusterRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<Cluster> clusters = clusterRepository.listByVendor(vendorId);
        Map<String, Cluster> clusterMap = clusters.stream()
                .collect(Collectors.toMap(Cluster::getClusterVal, Function.identity(), (key1, key2) -> key2));
        for (ClusterModel model : clusterModels) {
            Cluster cluster = new Cluster();
            String clusterVal = model.getClusterVal();
            if (clusterMap.containsKey(clusterVal)) {
                cluster = clusterMap.get(clusterVal);
                if (vdcMap.containsKey(model.getVdcUuid()) && null != vdcMap.get(model.getVdcUuid())) {
                    cluster.setVdcId(vdcMap.get(model.getVdcUuid()).getId());
                }
                cluster.setCreatorId(userId);
                cluster.setVendorId(vendorId);
                cluster.setMenderId(userId);
                cluster.setMemUsed(model.getMemUsed());
                cluster.setMemTotal(model.getMemTotal());
                cluster.setDiskUsed(model.getDiskUsed());
                cluster.setDiskTotal(model.getDiskTotal());
                cluster.setCpuUsed(model.getCpuUsed());
                cluster.setCpuTotal(model.getCpuTotal());
                cluster.setCpuCore(model.getCpuCore());
                cluster.setHostNum(model.getHostNum());
                cluster.setTemplateNum(model.getTemplateNum());
                cluster.setVmNum(model.getVmNum());
                cluster.setName(model.getName());
                cluster.setCpuExcessRatio(1L);
                cluster.setUuid(clusterVal);
                cluster.setType(CloudProvider.H3C.name());
                cluster.setClusterVal(clusterVal);
                cluster.setRemark(model.getRemark());
                clusterRepository.update(cluster);
                clusterMap.remove(clusterVal);
                continue;
            }
            cluster.setCreatorId(userId);
            cluster.setVendorId(vendorId);
            cluster.setMenderId(userId);
            if (vdcMap.containsKey(model.getVdcUuid()) && null != vdcMap.get(model.getVdcUuid())) {
                cluster.setVdcId(vdcMap.get(model.getVdcUuid()).getId());
            }
            cluster.setMemUsed(model.getMemUsed());
            cluster.setGuid(UUID.randomUUID().toString());
            cluster.setMemTotal(model.getMemTotal());
            cluster.setDiskUsed(model.getDiskUsed());
            cluster.setDiskTotal(model.getDiskTotal());
            cluster.setCpuUsed(model.getCpuUsed());
            cluster.setCpuTotal(model.getCpuTotal());
            cluster.setCpuCore(model.getCpuCore());
            cluster.setHostNum(model.getHostNum());
            cluster.setTemplateNum(model.getTemplateNum());
            cluster.setVmNum(model.getVmNum());
            cluster.setName(model.getName());
            cluster.setCpuExcessRatio(1L);
            cluster.setUuid(clusterVal);
            cluster.setType(CloudProvider.H3C.name());
            cluster.setClusterVal(clusterVal);
            cluster.setRemark(model.getRemark());
            clusterRepository.save(cluster);
            clusterMap.remove(clusterVal);
        }
        for (Entry<String, Cluster> entry : clusterMap.entrySet()) {
            clusterRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步vpc专用网络
     *
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncVdc(List<VDCModel> vdcModels, Long vendorId, Long userId, Region region) throws Exception {
        if (ListTool.isEmpty(vdcModels)) {
            vdcRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<Vdc> vdcList = vdcRepository.listByVendor(vendorId);
        Map<String, Vdc> vdcMap = vdcList.stream()
                .collect(Collectors.toMap(Vdc::getVdcVal, Function.identity(), (key1, key2) -> key2));

        for (VDCModel model : vdcModels) {
            Vdc vdc = new Vdc();
            String vdcVal = model.getVdcVal();
            if (vdcMap.containsKey(vdcVal)) {
                vdc = vdcMap.get(vdcVal);
                vdc.setCreatorId(userId);
                vdc.setVendorId(vendorId);
                vdc.setMenderId(userId);
                vdc.setCpuTotal(model.getCpuTotal());
                vdc.setCpuUsed(model.getCpuUsed());
                vdc.setDiskTotal(model.getDiskTotal());
                vdc.setDiskUsed(model.getDiskUsed());
                vdc.setMemTotal(model.getMemTotal());
                vdc.setMemUsed(model.getMemUsed());
                vdc.setName(model.getName());
                vdc.setVdcVal(vdcVal);
                vdc.setUuid(vdcVal);
                vdcRepository.update(vdc);
                vdcMap.remove(vdcVal);
                continue;
            }
            vdc.setCreatorId(userId);
            vdc.setGuid(UUID.randomUUID().toString());
            vdc.setVendorId(vendorId);
            vdc.setMenderId(userId);
            vdc.setCpuTotal(model.getCpuTotal());
            vdc.setCpuUsed(model.getCpuUsed());
            vdc.setDiskTotal(model.getDiskTotal());
            vdc.setDiskUsed(model.getDiskUsed());
            vdc.setMemTotal(model.getMemTotal());
            vdc.setMemUsed(model.getMemUsed());
            vdc.setName(model.getName());
            vdc.setVdcVal(vdcVal);
            vdc.setUuid(vdcVal);
            vdc.setType(CloudProvider.H3C.name());
            vdcRepository.save(vdc);
            vdcMap.remove(vdcVal);
        }
        for (Entry<String, Vdc> entry : vdcMap.entrySet()) {
            vdcRepository.remove(entry.getValue().getId(), userId);
        }
    }

    // /**
    // * 同步平台实体
    // *
    // * @param vendor
    // * @param data
    // * @param userId
    // */
    // public BocloudResult sync(CloudVendor vendor, Object data, Long userId) {
    // CmdbModel model = new CmdbModel();
    // model.setUuid(IDFactory.instance().uuid());
    // model.setServiceName(BoCloudService.IMS.name());
    // model.setManagerId(userId);
    // List<CmdbInfo> infos = Lists.newArrayList();
    // // 添加云平台数据
    // infos.add(CmdbInfoConvertor.getInfo(vendor, null, null));
    // try {
    // if (null != data) {
    // Long vendorId = vendor.getId();
    // if (cloudServerRepository.hasBuilding(vendorId)) {
    // return new BocloudResult(false, "该平台下有云主机正在创建，请稍后进行同步操作");
    // }
    // if (snapshotRepository.hasBuilding(vendorId)) {
    // return new BocloudResult(false, "该平台下有快照正在创建，请稍后进行同步操作");
    // }
    // // 获取数据库的旧的主机数据
    // List<Server> hosts = serverRepository.listByVendor(vendorId);
    // Map<String, Server> oldHostMap = Maps.newHashMap();
    // for (Server host : hosts) {
    // // host的uuid 不能为空
    // oldHostMap.put(host.getUuid(), host);
    // }
    // // 获取数据库里面的旧的vdc数据
    // List<Vdc> vdcs = vdcRepository.listByVendor(vendorId);
    // Map<String, Vdc> oldVdcMap = Maps.newHashMap();
    // for (Vdc vdc : vdcs) {
    // oldVdcMap.put(vdc.getVdcVal(), vdc);
    // }
    // // 获取同步数据
    // String content = JSONObject.toJSONString(data);
    // List<Vdc> allVdcs = JSONObject.parseArray(content, Vdc.class);
    // logger.info("Start sync datacenter of vendor[" + vendorId + "]");
    // for (Vdc vdc : allVdcs) {
    // Long vdcId = null;
    // String vdcGuid = null;
    // List<CmdbRelation> relations = Lists.newArrayList();
    // relations.add(new CmdbRelation(ModuleCode.VENDOR.name(), 1L,
    // ListUtils.getList(vendor.getGuid())));
    // relations.add(new CmdbRelation(ModuleCode.VENDOR.name(), 2L,
    // ListUtils.getList(vendor.getGuid())));
    // if (oldVdcMap.containsKey(vdc.getVdcVal())) {
    // Vdc oldVdc = oldVdcMap.get(vdc.getVdcVal());
    // utils.updateVdc(userId, vdc, oldVdc);
    // vdcId = oldVdc.getId();
    // vdcGuid = oldVdc.getGuid();
    // // 移除存在更新的数据中心
    // oldVdcMap.remove(vdc.getVdcVal());
    // infos.add(CmdbInfoConvertor.getInfo(oldVdc, null, relations));
    // } else {
    // utils.addVdc(userId, vendorId, vdc);
    // vdcId = vdc.getId();
    // vdcGuid = vdc.getGuid();
    // // cmdb更新数据中心数据
    // infos.add(CmdbInfoConvertor.getInfo(vdc, null, relations));
    // }
    // // 查询当前云平台下数据库已存在的云主机数据
    // List<CloudServer> oldServers = cloudServerRepository.listByVdcId(vdcId);
    // Map<String, CloudServer> oldCloudServerMap = Maps.newHashMap();
    // for (CloudServer server : oldServers) {
    // // instanceId 不能为空
    // if (StringUtils.isEmpty(server.getInstanceId())) {
    // oldCloudServerMap.put(server.getName(), server);
    // } else {
    // oldCloudServerMap.put(server.getInstanceId(), server);
    // }
    // }
    // // 同步宿主机
    // List<HostSystem> newHostSystems = vdc.getHosts();
    // if (!ListTool.isEmpty(newHostSystems)) {
    // logger.info("Start sync host of datacenter[" + vdcId + "]");
    // syncHost(newHostSystems, oldHostMap, vendorId, vdc, null, userId,
    // vendor.getType(),
    // oldCloudServerMap, infos, vendor.getGuid(), vdcGuid, null);
    // }
    // // 同步集群
    // List<Cluster> clusters = clusterRepository.listByVdc(vdcId);
    // logger.info("Start sync cluster of datacenter[" + vdcId + "]");
    // vdc.setId(vdcId);
    // syncCluster(clusters, vdc.getClusters(), vendorId, vdc, userId,
    // oldHostMap, vendor.getType(),
    // oldCloudServerMap, infos, vendor.getGuid(), vdcGuid);
    // // 删除当前云平台下不存在的云主机相关数据
    // Iterator<CloudServer> removeServers =
    // oldCloudServerMap.values().iterator();
    // while (removeServers.hasNext()) {
    // CloudServer removeServer = removeServers.next();
    // removeCloudServerCascade(removeServer, userId, vendorId);
    // // cmdb删除云主机数据
    // infos.add(CmdbInfoConvertor.getInfo(removeServer, "delete", null));
    // }
    // }
    // // 同步数据中心，删除不存在的数据中心
    // logger.info("Remove data centers that does not exists");
    // removeVdc(oldVdcMap, userId, infos);
    // // 同步宿主机，删除不存在的宿主机
    // logger.info("Remove hosts that does not exists");
    // removeHostCascade(oldHostMap, userId);
    // }
    // // 删除IP表中不存在的脏数据
    // ipService.processRubbishIp(vendor.getId());
    // model.setData(infos);
    // // 发送消息到cmdb模块，进行数据同步
    // amqpTemplate.convertAndSend("cmdb.message.queue",
    // JSONObject.parseObject(JSONObject.toJSONString(model)));
    // return new BocloudResult(true, "同步h3c平台数据成功");
    // } catch (Exception e) {
    // logger.error("Sync error:", e);
    // return new BocloudResult(false, "同步h3c平台数据失败");
    // }
    // }

    /**
     * 同步数据中心(删除)
     *
     * @param userId
     * @throws Exception
     */
    private void removeVdc(Map<String, Vdc> oldVdcMap, Long userId) throws Exception {
        Iterator<Vdc> vdcs = oldVdcMap.values().iterator();
        while (vdcs.hasNext()) {
            Vdc vdc = vdcs.next();
            vdcRepository.remove(vdc.getId(), userId);
            List<Cluster> clusters = clusterRepository.listByVdc(vdc.getId());
            for (Cluster cluster : clusters) {
                List<Server> servers = serverRepository.listByCluster(cluster.getId());
                for (Server server : servers) {
                    Resource hostResource = resourceRepository.query("Computer", "PHYSICAL", server.getId());
                    resourceRepository.remove(hostResource.getId(), userId);
                    List<CloudServer> cloudServers = cloudServerRepository.listByHid(server.getId());
                    for (CloudServer cloudServer : cloudServers) {
                        Resource vmResource = resourceRepository.query("Computer", "LOGICAL", cloudServer.getId());
                        resourceRepository.remove(vmResource.getId(), userId);
                    }
                }
                serverRepository.deleteByCluster(cluster.getId(), userId);
            }
            clusterRepository.removeByVdc(vdc.getId(), userId);
        }
    }

    /**
     * 同步集群(更新新增)
     *
     * @param oldClusters
     * @param newClusters
     * @param vendorId
     * @param vdc
     * @param userId
     * @param oldHostMap
     * @param type
     * @param oldServerMap
     * @throws Exception
     */
    private void syncCluster(List<Cluster> oldClusters, List<Cluster> newClusters, Long vendorId, Vdc vdc, Long userId,
                             Map<String, Server> oldHostMap, String type, Map<String, CloudServer> oldServerMap, String vendorGuid,
                             String vdcGuid) throws Exception {
        if (!ListTool.isEmpty(oldClusters) && ListTool.isEmpty(newClusters)) {
            clusterRepository.removeByVdc(vdc.getId(), userId);
        } else {
            Map<String, Cluster> oldMap = Maps.newHashMap();
            for (Cluster cluster : oldClusters) {
                oldMap.put(cluster.getClusterVal(), cluster);
            }
            for (Cluster cluster : newClusters) {
                Long clusterId = null;
                String clusterGuid = null;
                if (oldMap.containsKey(cluster.getClusterVal())) {
                    Cluster oldCluster = oldMap.get(cluster.getClusterVal());
                    // 更新集群
                    utils.mergeCluster(oldCluster, cluster, userId);
                    // 移除存在更新的集群
                    oldMap.remove(cluster.getClusterVal());
                    clusterId = oldCluster.getId();
                    clusterGuid = oldCluster.getGuid();
                } else {
                    utils.addCluster(vendorId, vdc.getId(), userId, cluster);
                    clusterId = cluster.getId();
                    clusterGuid = cluster.getGuid();
                }

                // 同步宿主机
                List<HostSystem> newHostSystems = cluster.getHosts();
                if (null != newHostSystems) {
                    logger.info("Start sync host of hosts");
                    syncHost(newHostSystems, oldHostMap, vendorId, vdc, clusterId, userId, type, oldServerMap,
                            vendorGuid, vdcGuid, clusterGuid);
                }
            }
            // 删除不存在的集群
            Iterator<Cluster> clusters = oldMap.values().iterator();
            while (clusters.hasNext()) {
                Cluster cluster = clusters.next();
                clusterRepository.remove(cluster.getId(), userId);
            }
        }
    }

    /**
     * 同步宿主机(新增或更新已存在的宿主机)
     *
     * @param hosts
     * @param oldHostMap
     * @param vendorId
     * @param vdc
     * @param clusterId
     * @param userId
     * @param type
     * @param oldServerMap
     * @throws Exception
     */
    private void syncHost(List<HostSystem> hosts, Map<String, Server> oldHostMap, Long vendorId, Vdc vdc,
                          Long clusterId, Long userId, String type, Map<String, CloudServer> oldServerMap, String vendorGuid,
                          String vdcGuid, String clusterGuid) throws Exception {
        for (HostSystem host : hosts) {
            Long hostId = null;
            // 更新宿主机以及相关实体对象
            if (oldHostMap.containsKey(host.getUuid())) {
                Server pm = oldHostMap.get(host.getUuid());
                hostId = pm.getId();
                // 同步主机标准交换机
                List<Switcher> switchers = switcherRepository.listByHostId(hostId);
                utils.syncSwitcher(switchers,
                        JSONArray.parseArray(JSONObject.toJSONString(host.getSwitchers()), Switcher.class), vendorId,
                        vdc, hostId, userId, "VSWITCH");
                switchers = switcherRepository.listByHostId(hostId);
                Map<String, Long> oldSwitcherMap = Maps.newHashMap();
                for (Switcher switcher : switchers) {
                    oldSwitcherMap.put(switcher.getSwitcherVal(), switcher.getId());
                }
                // 更新宿主机
                utils.mergeHost(pm, host, vendorId, vdc.getId(), clusterId, userId, oldSwitcherMap);
                // 同步该宿主机下的云主机
                List<CloudServer> cloudServers = JSONArray.parseArray(JSONObject.toJSONString(host.getServers()),
                        CloudServer.class);
                logger.info("Start sync virtual machine of host[" + pm.getId() + "]");
                syncCloudServer(oldServerMap, cloudServers, vendorId, pm.getId(), vdc.getId(), userId,
                        pm.getPowerState(), type, vendorGuid, vdcGuid, clusterGuid, pm.getGuid(), switchers);
                // 移除存在更新的宿主机
                oldHostMap.remove(host.getUuid());
                // 同步集群节点
                ClusterNode node = clusterNodeRepository.queryByRid(pm.getResourceId());
                if (null != node) {
                    if (null == clusterId) {
                        clusterNodeRepository.removeByRid(node.getResourceId(), userId);
                    } else {
                        node.setClusterId(clusterId);
                        node.setMenderId(userId);
                        node.setIp(pm.getManageIp());
                        node.setStatus(pm.getStatus());
                        clusterNodeRepository.update(node);
                    }
                }
                ServerConfig config = serverConfigRepository.getBySid(pm.getId());
            } else {
                // 新增
                List<IpPool> pools = ipPoolRepository.listByIpVersion(null);
                utils.addHostCascade(vendorId, vdc.getId(), clusterId, userId, type, host, null, null, pools);

            }
        }
    }

    /**
     * 删除不存在的宿主机
     *
     * @param oldHostMap
     * @param userId
     * @throws Exception
     */
    private void removeHostCascade(Map<String, Server> oldHostMap, Long userId) throws Exception {
        Iterator<Server> hosts = oldHostMap.values().iterator();
        while (hosts.hasNext()) {
            Server host = hosts.next();
            utils.removeHostCascade(host, userId, null);
        }
    }

    /**
     * 同步云主机下相关数据
     *
     * @param oldServerMap
     * @param newServers
     * @param vendorId
     * @param hostId
     * @param vdcId
     * @param userId
     * @param status
     * @param type
     * @param switchers
     * @throws Exception
     */
    private void syncCloudServer(Map<String, CloudServer> oldServerMap, List<CloudServer> newServers, Long vendorId,
                                 Long hostId, Long vdcId, Long userId, String status, String type, String vendorGuid, String vdcGuid,
                                 String clusterGuid, String hostGuid, List<Switcher> switchers) throws Exception {
        if (!ListTool.isEmpty(newServers)) {
            List<IpPool> pools = ipPoolRepository.listByIpVersion(null);
            for (CloudServer newServer : newServers) {
                if (oldServerMap.containsKey(newServer.getInstanceId())
                        || oldServerMap.containsKey(newServer.getName())) {
                    CloudServer oldServer = null;
                    if (oldServerMap.containsKey(newServer.getInstanceId())) {
                        oldServer = oldServerMap.get(newServer.getInstanceId());
                        // 移除存在更新的云主机
                        oldServerMap.remove(newServer.getInstanceId());
                    } else {
                        oldServer = oldServerMap.get(newServer.getName());
                        // 移除存在更新的云主机
                        oldServerMap.remove(newServer.getName());
                    }
                    // 更新云主机
                    utils.mergeCloudServer(oldServer, newServer, status, vendorId, hostId, userId, type, switchers,
                            pools);
                } else {
                    newServer.setVendorType(type);
                    utils.addCloudServerCascade(newServer, vendorId, hostId, vdcId, userId, status, type, switchers,
                            pools);
                }
            }
        }
    }

    private void removeCloudServerCascade(CloudServer server, Long userId, Long vendorId) throws Exception {
        String status = server.getStatus();
        Long id = server.getId();
        if (BocloudStatus.Server.BUILDING.name().equals(status)) {
            return;
        }
        if (server.getIsTemplate() != null && server.getIsTemplate()) {
            imageRepository.removeByTemplate(id, userId);
        }
        snapshotRepository.removeByVm(id, userId);
        storeHostRepository.deleteByHost(id, "VM");
        networkHostRepository.deleteByHost(id, "VM");
        networkCardRepository.removeByHost(id, "VM", userId);
        resourceRepository.remove(id, ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), userId);
        cloudServerRepository.remove(id, userId);
        // 回收IP
        ipRepository.delete(id, "VM", vendorId);
    }

    public VdcRepository getVdcRepository() {
        return vdcRepository;
    }

    public void setVdcRepository(VdcRepository vdcRepository) {
        this.vdcRepository = vdcRepository;
    }

    public CloudServerRepository getCloudServerRepository() {
        return cloudServerRepository;
    }

    public void setCloudServerRepository(CloudServerRepository cloudServerRepository) {
        this.cloudServerRepository = cloudServerRepository;
    }

    public SnapshotRepository getSnapshotRepository() {
        return snapshotRepository;
    }

    public void setSnapshotRepository(SnapshotRepository snapshotRepository) {
        this.snapshotRepository = snapshotRepository;
    }

    public NetworkRepository getNetworkRepository() {
        return networkRepository;
    }

    public void setNetworkRepository(NetworkRepository networkRepository) {
        this.networkRepository = networkRepository;
    }

    public ClusterRepository getClusterRepository() {
        return clusterRepository;
    }

    public void setClusterRepository(ClusterRepository clusterRepository) {
        this.clusterRepository = clusterRepository;
    }

    public StoreHostRepository getStoreHostRepository() {
        return storeHostRepository;
    }

    public void setStoreHostRepository(StoreHostRepository storeHostRepository) {
        this.storeHostRepository = storeHostRepository;
    }

    public ServerRepository getServerRepository() {
        return serverRepository;
    }

    public void setServerRepository(ServerRepository serverRepository) {
        this.serverRepository = serverRepository;
    }

    public NetworkCardRepository getNetworkCardRepository() {
        return networkCardRepository;
    }

    public void setNetworkCardRepository(NetworkCardRepository networkCardRepository) {
        this.networkCardRepository = networkCardRepository;
    }

    public NetworkHostRepository getNetworkHostRepository() {
        return networkHostRepository;
    }

    public void setNetworkHostRepository(NetworkHostRepository networkHostRepository) {
        this.networkHostRepository = networkHostRepository;
    }

    public SyncH3cUtils getUtils() {
        return utils;
    }

    public void setUtils(SyncH3cUtils utils) {
        this.utils = utils;
    }

    public ClusterNodeRepository getClusterNodeRepository() {
        return clusterNodeRepository;
    }

    public void setClusterNodeRepository(ClusterNodeRepository clusterNodeRepository) {
        this.clusterNodeRepository = clusterNodeRepository;
    }

    public ServerConfigRepository getServerConfigRepository() {
        return serverConfigRepository;
    }

    public void setServerConfigRepository(ServerConfigRepository serverConfigRepository) {
        this.serverConfigRepository = serverConfigRepository;
    }

    public ServerAssetsRepository getServerAssetsRepository() {
        return serverAssetsRepository;
    }

    public void setServerAssetsRepository(ServerAssetsRepository serverAssetsRepository) {
        this.serverAssetsRepository = serverAssetsRepository;
    }

    public ResourceRepository getResourceRepository() {
        return resourceRepository;
    }

    public void setResourceRepository(ResourceRepository resourceRepository) {
        this.resourceRepository = resourceRepository;
    }

    public IpRepository getIpRepository() {
        return ipRepository;
    }

    public void setIpRepository(IpRepository ipRepository) {
        this.ipRepository = ipRepository;
    }

    public SwitcherRepository getSwitcherRepository() {
        return switcherRepository;
    }

    public void setSwitcherRepository(SwitcherRepository switcherRepository) {
        this.switcherRepository = switcherRepository;
    }

    public ImageRepository getImageRepository() {
        return imageRepository;
    }

    public void setImageRepository(ImageRepository imageRepository) {
        this.imageRepository = imageRepository;
    }

    public AmqpTemplate getAmqpTemplate() {
        return amqpTemplate;
    }

    public void setAmqpTemplate(AmqpTemplate amqpTemplate) {
        this.amqpTemplate = amqpTemplate;
    }
}
