package com.bocloud.ims.service.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.entity.enums.ServerAssetCategory;
import com.bocloud.cmp.model.HostSystem;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.cmp.model.TagModel;
import com.bocloud.cmp.model.VMBean;
import com.bocloud.cmp.provider.utils.IPAddress;
import com.bocloud.common.enums.OSCategory;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.RequestContext.Catalog;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.repository.resource.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class SingleSyncVmwareUtils {

    private CloudServerRepository cloudServerRepository;
    private DataStoreRepository dataStoreRepository;
    private ServerRepository serverRepository;
    private SnapshotRepository snapshotRepository;
    private NetworkRepository networkRepository;
    private ClusterRepository clusterRepository;
    private StoreHostRepository storeHostRepository;
    private NetworkCardRepository networkCardRepository;
    private NetworkHostRepository networkHostRepository;
    private ServerConfigRepository serverConfigRepository;
    private ResourceRepository resourceRepository;
    private IpRepository ipRepository;
    private ImageRepository imageRepository;
    private VolumeRepository volumeRepository;
    private TagRepository tagRepository;
    private PortGroupRepository portGroupRepository;


    public SingleSyncVmwareUtils(ClusterRepository clusterRepository) {
        super();
        this.clusterRepository = clusterRepository;
    }

    public SingleSyncVmwareUtils(ServerRepository serverRepository, ServerConfigRepository serverConfigRepository,
                                 DataStoreRepository dataStoreRepository, StoreHostRepository storeHostRepository,
                                 NetworkRepository networkRepository, NetworkHostRepository networkHostRepository, NetworkCardRepository networkCardRepository,
                                 ResourceRepository resourceRepository, IpRepository ipRepository) {
        super();
        this.serverRepository = serverRepository;
        this.serverConfigRepository = serverConfigRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkRepository = networkRepository;
        this.networkHostRepository = networkHostRepository;
        this.networkCardRepository = networkCardRepository;
        this.resourceRepository = resourceRepository;
        this.ipRepository = ipRepository;
    }

    public SingleSyncVmwareUtils(CloudServerRepository cloudServerRepository, ImageRepository imageRepository, SnapshotRepository snapshotRepository, VolumeRepository volumeRepository,
                                 DataStoreRepository dataStoreRepository, StoreHostRepository storeHostRepository,
                                 NetworkRepository networkRepository, NetworkHostRepository networkHostRepository, NetworkCardRepository networkCardRepository,
                                 ResourceRepository resourceRepository, IpRepository ipRepository) {
        super();
        this.cloudServerRepository = cloudServerRepository;
        this.imageRepository = imageRepository;
        this.snapshotRepository = snapshotRepository;
        this.volumeRepository = volumeRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkRepository = networkRepository;
        this.networkHostRepository = networkHostRepository;
        this.networkCardRepository = networkCardRepository;
        this.resourceRepository = resourceRepository;
        this.ipRepository = ipRepository;
    }


    public SingleSyncVmwareUtils(CloudServerRepository cloudServerRepository, DataStoreRepository dataStoreRepository,
                                 ServerRepository serverRepository, SnapshotRepository snapshotRepository,
                                 NetworkRepository networkRepository, ClusterRepository clusterRepository,
                                 StoreHostRepository storeHostRepository, NetworkCardRepository networkCardRepository,
                                 PortGroupRepository portGroupRepository, NetworkHostRepository networkHostRepository,
                                 ServerConfigRepository serverConfigRepository, ResourceRepository resourceRepository,
                                 IpRepository ipRepository, ImageRepository imageRepository, VolumeRepository volumeRepository,
                                 TagRepository tagRepository) {
        super();
        this.cloudServerRepository = cloudServerRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.serverRepository = serverRepository;
        this.snapshotRepository = snapshotRepository;
        this.networkRepository = networkRepository;
        this.clusterRepository = clusterRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkCardRepository = networkCardRepository;
        this.portGroupRepository = portGroupRepository;
        this.networkHostRepository = networkHostRepository;
        this.serverConfigRepository = serverConfigRepository;
        this.resourceRepository = resourceRepository;
        this.ipRepository = ipRepository;
        this.imageRepository = imageRepository;
        this.volumeRepository = volumeRepository;
        this.tagRepository = tagRepository;
    }

    /***
     * 同步集群
     * @param oldCluster
     * @param newCluster
     * @param userId
     * @throws Exception
     */
    public void mergeCluster(Cluster oldCluster, Cluster newCluster, Long userId) throws Exception {
        oldCluster.setMemUsed(newCluster.getMemUsed());
        oldCluster.setMemTotal(newCluster.getMemTotal());
        oldCluster.setDiskUsed(newCluster.getDiskUsed());
        oldCluster.setDiskTotal(newCluster.getDiskTotal());
        oldCluster.setCpuUsed(newCluster.getCpuUsed());
        oldCluster.setCpuTotal(newCluster.getCpuTotal());
        oldCluster.setCpuCore(newCluster.getCpuCore());
        oldCluster.setHostNum(newCluster.getHostNum());
        oldCluster.setTemplateNum(newCluster.getTemplateNum());
        oldCluster.setVmNum(newCluster.getVmNum());
        oldCluster.setName(newCluster.getName());
        oldCluster.setMenderId(userId);
        if (null == oldCluster.getStatus()) {
            oldCluster.setStatus("RUNNING");
        }
        Long cpuExcessRatio = oldCluster.getCpuExcessRatio();
        if (null == cpuExcessRatio) {
            oldCluster.setCpuExcessRatio(4L);
        }
        BigDecimal cpuDistributableRatio = oldCluster.getCpuDistributableRatio();
        if (null == cpuDistributableRatio) {
            oldCluster.setCpuDistributableRatio(BigDecimal.valueOf(100));
        }
        BigDecimal memDistributableRatio = oldCluster.getMemDistributableRatio();
        if (null == memDistributableRatio) {
            oldCluster.setMemDistributableRatio(BigDecimal.valueOf(100));
        }
        oldCluster.setCategory("COMPUTE");
        clusterRepository.update(oldCluster);
    }

    /**
     * 同步宿主机
     *
     * @param oldHost
     * @param newHost
     * @param vendorId
     * @param vdcId
     * @param clusterId
     * @param userId
     * @param storeMap
     * @param networkMap
     * @param groupMap
     * @param switcherMap
     * @param ipPools
     * @throws Exception
     */
    public void mergeHost(Server oldHost, HostSystem newHost, Long vendorId, Long vdcId, Long clusterId, Long userId,
                          Map<String, DataStore> storeMap, Map<String, Network> networkMap, Map<String, String> groupMap,
                          Map<String, Long> switcherMap, List<IpPool> ipPools) throws Exception {

        BeanUtils.copyProperties(newHost, oldHost);
        oldHost.setManageIp(newHost.getHostIp());
        oldHost.setVdcId(vdcId);
        oldHost.setClusterId(clusterId);
        oldHost.setVendorId(vendorId);
        oldHost.setMenderId(userId);
        oldHost.setAssetCategory(ServerAssetCategory.HYPERVISOR.name());
        serverRepository.update(oldHost);
        // 更新资源
        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.PHYSICAL.name(),
                oldHost.getId());
        List<String> privateIps = Lists.newArrayList();
        privateIps.add(oldHost.getManageIp());
        if (null == resource) {
            resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.PHYSICAL.name(), oldHost.getId(),
                    JSONObject.toJSONString(privateIps), OSCategory.LINUX.name(), vendorId);
            resource.preSave(oldHost.getName(), oldHost.getPowerState(), userId, 0L);
            resource.setInventory(JSONObject.toJSONString(oldHost));
            resourceRepository.save(resource);
        } else {
            resource.setStatus(oldHost.getPowerState());
            resource.setPrivateIps(JSONObject.toJSONString(privateIps));
            resource.setMenderId(userId);
            resourceRepository.update(resource);
        }
        // 保存主机配置信息
        ServerConfig config = serverConfigRepository.getBySid(oldHost.getId());
        if (null != config) {
            config.setDiskCapacity(newHost.getDiskTotal());
            config.setCpuHz(newHost.getCpuTotal());
            config.setMemoryCapacity(newHost.getMemTotal());
            config.setCpuAmount(newHost.getCpuNum());
            config.setCpuMode(newHost.getCpuModel());
            config.setCpuCore(newHost.getCpuCore());
            config.setCpuUsed(newHost.getCpuUsed());
            config.setMemUsed(newHost.getMemUsed());
            config.setDiskUsed(newHost.getDiskUsed());
            config.setEsxVersion(newHost.getEsxVersion());
            config.setEvc(newHost.getEvc());
            config.setAssignedLicense(newHost.getAssignedLicense());
            config.setIpmiAddress(newHost.getIpmiAddress());
            config.setIpmiAccount(newHost.getIpmiAccount());
            config.setIpmiPassword(newHost.getIpmiPassword());
            config.setIpmiPort(623);
            serverConfigRepository.update(config);
        } else {
            addServerConfig(newHost, oldHost.getId());
        }
        Long hostId = oldHost.getId();
        // 处理IP地址
        if (!org.apache.commons.lang3.StringUtils.isEmpty(oldHost.getManageIp())) {
            Ip ip = ipRepository.checkExist(oldHost.getManageIp(), null, vendorId);
            if (null == ip) {
                String address = oldHost.getManageIp();
                ip = new Ip(address, null, null, null, vendorId, IDFactory.instance().uuid(), null, Ip.IpStatus.used);
                ip.setCatalog("PM");
                ip.setTarget(hostId);
                for (IpPool pool : ipPools) {
                    String dns = null;
                    if (!org.apache.commons.lang3.StringUtils.isEmpty(pool.getDnsNames())) {
                        List<String> dnss = JSONArray.parseArray(pool.getDnsNames(), String.class);
                        if (!ListTool.isEmpty(dnss)) {
                            dns = dnss.get(0);
                        }
                    }
                    List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                    IPAddress ipAddress = IPAddress.getIPAddress(address);
                    boolean flag = ipAddress.isInPools(address, poolList);
                    if (flag) {
                        ip.setMask(ipAddress.getMask(pool.getCidr()));
                        ip.setGateway(pool.getGateway());
                        ip.setDns(dns);
                        ip.setPoolId(pool.getId());
                        break;
                    }
                }
                ipRepository.save(ip);
            } else {
                ip.setTarget(hostId);
                ip.setCatalog("PM");
                ip.setStatus(Ip.IpStatus.used);
                ip.setVendorId(vendorId);
                ipRepository.update(ip);
            }
        }
        // 同步该宿主机和存储的关系
        mergeStoreHost(vendorId, hostId, "PM", newHost.getStores(), storeMap);
        // 同步该宿主机与网络的关系
        mergeNetworkHost(vendorId, hostId, "PM",
                JSONArray.parseArray(JSONObject.toJSONString(newHost.getNetworks()), Network.class), networkMap,
                groupMap);
        // 同步该宿主机下的网卡
        List<NetworkCard> cards = networkCardRepository.listByHost(hostId, "PM");
        syncNetworkCard(cards, JSONArray.parseArray(JSONObject.toJSONString(newHost.getNetcards()), NetworkCard.class), vendorId, hostId, userId, "PM", switcherMap);
    }

    /***
     *  同步该主机和存储的关系
     * @param vendorId
     * @param hostId
     * @param category
     * @param datastores
     * @param storeMap
     * @throws Exception
     */
    public void mergeStoreHost(Long vendorId, Long hostId, String category, List<String> datastores,
                               Map<String, DataStore> storeMap) throws Exception {
        List<StoreHost> storeHosts = storeHostRepository.list(hostId, category);
        Map<String, StoreHost> oldStore = Maps.newHashMap();
        for (StoreHost storeHost : storeHosts) {
            DataStore dataStore = dataStoreRepository.query(storeHost.getStoreId());
            if (null != dataStore) {
                oldStore.put(dataStore.getStoreVal(), storeHost);
            }
        }
        if (!ListTool.isEmpty(datastores)) {
            for (String datastore : datastores) {
                if (oldStore.containsKey(datastore)) {
                    oldStore.remove(datastore);
                    continue;
                }
                if (storeMap.containsKey(datastore)) {
                    storeHostRepository
                            .save(new StoreHost(storeMap.get(datastore).getId(), hostId, vendorId, category));
                }
            }
        }
        for (String dataStore : oldStore.keySet()) {
            storeHostRepository.delete(oldStore.get(dataStore));
        }
    }

    /***
     * 同步宿主机与网络的关系
     * @param vendorId
     * @param hostId
     * @param category
     * @param networks
     * @param networkMap
     * @param groupMap
     * @throws Exception
     */
    public void mergeNetworkHost(Long vendorId, Long hostId, String category, List<Network> networks,
                                 Map<String, Network> networkMap, Map<String, String> groupMap) throws Exception {
        List<NetworkHost> networkHosts = networkHostRepository.list(hostId, category);
        Map<String, NetworkHost> oldNetwork = Maps.newHashMap();
        for (NetworkHost networkHost : networkHosts) {
            Network network = networkRepository.query(networkHost.getNetworkId());
            if (null == network) {
                continue;
            }
            oldNetwork.put(network.getNetworkVal(), networkHost);
        }
        if (!ListTool.isEmpty(networks)) {
            Map<String, Network> netMap = Maps.newHashMap();
            for (String key : networkMap.keySet()) {
                netMap.put(key, networkMap.get(key));
            }
            for (Network network : networks) {
                String val = network.getNetworkVal();
                if (oldNetwork.containsKey(val)) {// 主机网络关系存在,且是标准交换机
                    oldNetwork.remove(val);
                } else if (groupMap.containsKey(val) && oldNetwork.containsKey(groupMap.get(val))) {// 主机网络关系存在,且是分布式交换机
                    oldNetwork.remove(groupMap.get(val));
                    netMap.remove(groupMap.get(val));
                } else if (netMap.containsKey(val)) { // 主机网络关系不存在，且是标准交换机
                    networkHostRepository.save(new NetworkHost(netMap.get(val).getId(), hostId, vendorId, category));
                } else if (groupMap.containsKey(val) && netMap.containsKey(groupMap.get(val))) {// 主机网络关系不存在，且是分布式交换机
                    networkHostRepository
                            .save(new NetworkHost(netMap.get(groupMap.get(val)).getId(), hostId, vendorId, category));
                    netMap.remove(groupMap.get(val));
                }
            }
        }
        Iterator<String> iterator = oldNetwork.keySet().iterator();
        while (iterator.hasNext()) {
            networkHostRepository.delete(NetworkHost.class, oldNetwork.get(iterator.next()).getId());
        }
    }

    /**
     * 同步虚拟机
     *
     * @param oldServer
     * @param newServer
     * @param hostStatus
     * @param vendorId
     * @param hostId
     * @param userId
     * @param storeMap
     * @param networkMap
     * @param groupMap
     * @param type
     * @param pools
     * @throws Exception
     */
    public void mergeServer(CloudServer oldServer, CloudServer newServer, String hostStatus, Long vendorId, Long hostId,
                            Long userId, Map<String, DataStore> storeMap, Map<String, Network> networkMap, Map<String, String> groupMap,
                            String type, List<IpPool> pools) throws Exception {
        if (BocloudStatus.Server.BUILDING.name().equals(oldServer.getStatus())) {
            return;
        }
        String managerIp = oldServer.getManagerIp();
        String privateIps = oldServer.getPrivateIps();
        String oldPasswd = oldServer.getPassword();
        String oldAccount = oldServer.getAccount();
        String uuid = oldServer.getUuid();
        VMBean bean = new VMBean();
        BeanUtils.copyProperties(newServer, bean);
        BeanUtils.copyProperties(bean, oldServer);
        oldServer.setAccount(oldAccount);
        oldServer.setPassword(oldPasswd);
        oldServer.setName(URLDecoder.decode(oldServer.getName(), "utf-8"));
        oldServer.setMenderId(userId);
        oldServer.setVendorId(vendorId);
        oldServer.setHostId(hostId);
        oldServer.setUuid(uuid);
        if (StringUtils.isEmpty(newServer.getManagerIp()) || "poweredOff".equalsIgnoreCase(newServer.getStatus())) {
            oldServer.setManagerIp(managerIp);
        } else {
            oldServer.setManagerIp(newServer.getManagerIp());
        }
        if (StringUtils.isEmpty(newServer.getPrivateIps()) || "poweredOff".equalsIgnoreCase(newServer.getStatus())) {
            oldServer.setPrivateIps(privateIps);
        } else {
            oldServer.setPrivateIps(newServer.getPrivateIps());
        }
        if ("UNKNOWN".equals(hostStatus)) {
            if ("poweredOn".equalsIgnoreCase(oldServer.getStatus())) {
                oldServer.setStatus("UNKNOWNON");
            } else if ("poweredOff".equalsIgnoreCase(oldServer.getStatus())) {
                oldServer.setStatus("UNKNOWNOFF");
            } else if ("suspended".equalsIgnoreCase(oldServer.getStatus())) {
                oldServer.setStatus("UNKNOWNSUSPEND");
            } else {
                oldServer.setStatus(hostStatus);
            }
        } else if ("poweredOn".equalsIgnoreCase(oldServer.getStatus())) {
            oldServer.setStatus(BocloudStatus.Server.RUNNING.name());
            oldServer.setManagerIp(newServer.getManagerIp());
            oldServer.setPrivateIps(newServer.getPrivateIps());
        } else if ("poweredOff".equalsIgnoreCase(oldServer.getStatus())) {
            oldServer.setStatus(BocloudStatus.Server.STOPPED.name());
        } else if ("suspended".equalsIgnoreCase(oldServer.getStatus())) {
            oldServer.setStatus(BocloudStatus.Server.SUSPENDED.name());
        } else {
            oldServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
        }
        if (null == oldServer.getCatalog()) {
            oldServer.setCatalog(Catalog.Manager);
        }

        cloudServerRepository.update(oldServer);
        //syncTag(newServer.getTagModels(),newServer.getResourceId(), TagType.instance.name(),oldServer.getVendorId(),null);
        Long serverId = oldServer.getId();
        List<Image> images = imageRepository.listByTemplate(serverId, vendorId);
        if (newServer.getIsTemplate()) {
            Image image = imageRepository.getByImageUuid(oldServer.getInstanceId());
            if (null == image) {
                image = new Image();
                image.setName(newServer.getName());
                image.setStatus("ACTIVE");
                image.setTemplateId(oldServer.getId());
                image.setVendorType(type);
                image.setImageUuid(newServer.getInstanceId());
                image.setSize(newServer.getDisk().doubleValue());
                image.preSave(userId, userId, vendorId, 0L, 0L);
                image.setCatalog("VM");
                image.setOsCategory(newServer.getOsCategory());
                image.setOsName(newServer.getOsName());
                imageRepository.save(image);
            } else {
                image.setName(newServer.getName());
                image.setMenderId(userId);
                image.setSize(newServer.getDisk().doubleValue());
                image.setImageUuid(newServer.getInstanceId());
                image.setOsCategory(newServer.getOsCategory());
                image.setOsName(newServer.getOsName());
                imageRepository.update(image);
            }
            resourceRepository.remove(serverId, ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                    userId);
        } else if (!ListTool.isEmpty(images) && !newServer.getIsTemplate()) {
            imageRepository.removeByTemplate(serverId, userId);
        } else {
            // 处理IP
            List<String> ips = Lists.newArrayList();
            if (!org.apache.commons.lang3.StringUtils.isEmpty(oldServer.getPrivateIps())) {
                List<JSONObject> objects = JSONObject.parseArray(oldServer.getPrivateIps(), JSONObject.class);
                for (JSONObject object : objects) {
                    String address = object.getString("address");
                    if (org.apache.commons.lang3.StringUtils.isEmpty(address)) {
                        continue;
                    }
                    ips.add(address);
                    Ip ip = ipRepository.checkExist(address, null, vendorId);
                    if (null == ip) {
                        ip = new Ip(address, null, null, null, vendorId, IDFactory.instance().uuid(), null,
                                Ip.IpStatus.used);
                        ip.setCatalog("VM");
                        ip.setTarget(serverId);
                        for (IpPool pool : pools) {
                            String dns = null;
                            if (!org.apache.commons.lang3.StringUtils.isEmpty(pool.getDnsNames())) {
                                List<String> dnss = JSONArray.parseArray(pool.getDnsNames(), String.class);
                                if (!ListTool.isEmpty(dnss)) {
                                    dns = dnss.get(0);
                                }
                            }
                            List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                            IPAddress ipAddress = IPAddress.getIPAddress(address);
                            boolean flag = ipAddress.isInPools(address, poolList);
                            if (flag) {
                                ip.setMask(ipAddress.getMask(pool.getCidr()));
                                ip.setGateway(pool.getGateway());
                                ip.setDns(dns);
                                ip.setPoolId(pool.getId());
                                break;
                            }
                        }
                        ipRepository.save(ip);
                    } else {
                        ip.setTarget(serverId);
                        ip.setCatalog("VM");
                        ip.setStatus(Ip.IpStatus.used);
                        ip.setVendorId(vendorId);
                        ipRepository.update(ip);
                    }
                }
            }
            // 更新资源表
            Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                    ResourceCatalog.LOGICAL.name(), serverId);
            if (null == resource) {
                resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), serverId,
                        JSONObject.toJSONString(ips), oldServer.getOsCategory(), vendorId);
                resource.preSave(oldServer.getName(), oldServer.getStatus(), userId, 0L);
                resource.setInventory(JSONObject.toJSONString(oldServer));
                resourceRepository.save(resource);
            } else {
                resource.setName(oldServer.getName());
                resource.setStatus(oldServer.getStatus());
                resource.setPrivateIps(JSONObject.toJSONString(ips));
                resource.setMenderId(userId);
                resource.setOsCategory(oldServer.getOsCategory());
                resource.setInventory(JSONObject.toJSONString(oldServer));
                resourceRepository.update(resource);
            }
        }
        // 同步该虚拟机和存储的关系
        mergeStoreHost(vendorId, serverId, "VM", newServer.getStores(), storeMap);
        // 同步该虚拟机和网络的关系
        mergeNetworkHost(vendorId, serverId, "VM", newServer.getNetworks(), networkMap, groupMap);
        // 同步该虚拟机下的网卡
        List<NetworkCard> oldCards = networkCardRepository.listByHost(serverId, "VM");
        syncNetworkCard(oldCards, newServer.getNetcards(), vendorId, serverId, userId, "VM", Maps.newHashMap());
        // 同步该虚拟机下的快照
        List<Snapshot> shots = snapshotRepository.listByVMid(serverId);
        syncSnapshot(shots, newServer.getSnapshots(), vendorId, serverId, userId);
        // 同步该虚拟机下的磁盘设备
        List<Volume> disks = volumeRepository.listByServerId(serverId);
        syncDiskDevice(storeMap, disks, newServer.getDiskDevices(), oldServer.getVdcId(), vendorId, serverId, userId);
    }

    /**
     * 同步虚拟机下磁盘设备信息
     *
     * @param storeMap
     * @param oldDisks
     * @param newDisks
     * @param vdcId
     * @param vendorId
     * @param serverId
     * @param userId
     * @throws Exception
     */
    public void syncDiskDevice(Map<String, DataStore> storeMap, List<Volume> oldDisks, List<Volume> newDisks,
                               Long vdcId, Long vendorId, Long serverId, Long userId) throws Exception {
        // 该虚拟机下没有任何硬盘设备
        if (!ListTool.isEmpty(oldDisks) && ListTool.isEmpty(newDisks)) {
            volumeRepository.removeByServerId(serverId, userId);
        } else if (!ListTool.isEmpty(oldDisks) && !ListTool.isEmpty(newDisks)) {
            Map<String, Volume> oldMap = Maps.newHashMap();
            for (Volume disk : oldDisks) {
                oldMap.put(disk.getName(), disk);
            }
            for (Volume disk : newDisks) {
                String storeName = disk.getDataStoreName();
                if (!StringUtils.isEmpty(storeName)) {
                    DataStore store = dataStoreRepository.getByName(storeName, vdcId);
                    if (null != store) {
                        disk.setDataStoreId(store.getId());
                    }
                }
                if (oldMap.containsKey(disk.getName())) {
                    Volume oldDisk = oldMap.get(disk.getName());
                    oldDisk.setName(disk.getName());
                    oldDisk.setMenderId(userId);
                    oldDisk.setSize(disk.getSize());
                    oldDisk.setDiskObjectId(disk.getDiskObjectId());
                    oldDisk.setDataStoreId(disk.getDataStoreId());
                    oldDisk.setVolumeUuid(disk.getVolumeUuid());
                    if (null == oldDisk.getCatalog()) {
                        oldDisk.setCatalog(Catalog.Manager);
                    }
                    if (null != disk.getStoreVal()) {
                        DataStore dataStore = storeMap.get(disk.getStoreVal());
                        if (null != dataStore) {
                            oldDisk.setDataStoreId(dataStore.getId());
                        }
                    }
                    volumeRepository.update(oldDisk);
                    oldMap.remove(disk.getName());
                } else {
                    disk.preSave(userId, userId, 0L, vendorId);
                    disk.setServerId(serverId);
                    disk.setVolumeUuid(IDFactory.instance().uuid());
                    disk.setCatalog(Catalog.Manager);
                    if (null != disk.getStoreVal()) {
                        DataStore dataStore = storeMap.get(disk.getStoreVal());
                        if (null != dataStore) {
                            disk.setDataStoreId(dataStore.getId());
                        }
                    }
                    volumeRepository.save(disk);
                    oldMap.remove(disk.getName());
                }
            }
            Iterator<Volume> disks = oldMap.values().iterator();
            while (disks.hasNext()) {
                Long id = disks.next().getId();
                volumeRepository.remove(id, userId);
            }
        } else if (ListTool.isEmpty(oldDisks) && !ListTool.isEmpty(newDisks)) {
            for (Volume disk : newDisks) {
                disk.preSave(userId, userId, 0L, vendorId);
                disk.setServerId(serverId);
                disk.setVolumeUuid(IDFactory.instance().uuid());
                String storeName = disk.getDataStoreName();
                if (!StringUtils.isEmpty(storeName)) {
                    DataStore store = dataStoreRepository.getByName(storeName, vdcId);
                    if (null != store) {
                        disk.setDataStoreId(store.getId());
                    }
                }
                disk.setCatalog(Catalog.Manager);
                volumeRepository.save(disk);
            }
        }
    }

    /**
     * 保存主机配置信息
     *
     * @param host
     * @param serverId
     * @throws Exception
     */
    public ServerConfig addServerConfig(HostSystem host, Long serverId) throws Exception {
        ServerConfig config = new ServerConfig();
        config.setDiskCapacity(host.getDiskTotal());
        config.setCpuHz(host.getCpuTotal());
        config.setMemoryCapacity(host.getMemTotal());
        config.setCpuAmount(host.getCpuNum());
        config.setCpuMode(host.getCpuModel());
        config.setCpuCore(host.getCpuCore());
        config.setCpuUsed(host.getCpuUsed());
        config.setMemUsed(host.getMemUsed());
        config.setDiskUsed(host.getDiskUsed());
        config.setServerId(serverId);
        config.setVendor(host.getVendor());
        config.setEsxVersion(host.getEsxVersion());
        config.setEvc(host.getEvc());
        config.setAssignedLicense(host.getAssignedLicense());
        config.setIpmiAddress(host.getIpmiAddress());
        config.setIpmiAccount(host.getIpmiAccount());
        config.setIpmiPassword(host.getIpmiPassword());
        config.setIpmiPort(623);
        serverConfigRepository.save(config);
        return config;
    }

    /**
     * 添加虚拟机及之下的快照信息
     *
     * @param storeMap
     * @param cloudServer
     * @param vendorId
     * @param hostId
     * @param vdcId
     * @param userId
     * @param status
     * @param networkMap
     * @param groupMap
     * @param type
     * @param pools
     * @throws Exception
     */
    public void addServerCascade(Map<String, DataStore> storeMap, CloudServer cloudServer, Long vendorId, Long hostId,
                                 Long vdcId, Long userId, String status, Map<String, Network> networkMap, Map<String, String> groupMap,
                                 String type, List<IpPool> pools) throws Exception {
        cloudServer.preSave(userId, userId, vendorId, hostId, vdcId, null, 0L, 0L);
        if ("UNKNOWN".equals(status)) {
            if ("poweredOn".equalsIgnoreCase(cloudServer.getStatus())) {
                cloudServer.setStatus("UNKNOWNON");
            } else if ("poweredOff".equalsIgnoreCase(cloudServer.getStatus())) {
                cloudServer.setStatus("UNKNOWNOFF");
            } else if ("suspended".equalsIgnoreCase(cloudServer.getStatus())) {
                cloudServer.setStatus("UNKNOWNSUSPEND");
            } else {
                cloudServer.setStatus(status);
            }
        } else if ("poweredOn".equalsIgnoreCase(cloudServer.getStatus())) {
            cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
        } else if ("poweredOff".equalsIgnoreCase(cloudServer.getStatus())) {
            cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
        } else if ("suspended".equalsIgnoreCase(cloudServer.getStatus())) {
            cloudServer.setStatus(BocloudStatus.Server.SUSPENDED.name());
        } else {
            cloudServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
        }
        cloudServer.setName(URLDecoder.decode(cloudServer.getName(), "utf-8"));
        cloudServer.setResourceId(IDFactory.instance().uuid());
        cloudServer.setRecycle(false);
        cloudServer.setCatalog(Catalog.Manager);
        cloudServerRepository.save(cloudServer);
        Long serverId = cloudServer.getId();
        if (cloudServer.getIsTemplate()) {
            Image image = new Image();
            image.setName(cloudServer.getName());
            image.setStatus("ACTIVE");
            image.setTemplateId(cloudServer.getId());
            image.setSize(cloudServer.getDisk().doubleValue());
            image.setVendorType(type);
            image.setImageUuid(cloudServer.getInstanceId());
            image.preSave(userId, userId, vendorId, 0L, 0L);
            image.setCatalog("VM");
            image.setOsCategory(cloudServer.getOsCategory());
            image.setOsName(cloudServer.getOsName());
            imageRepository.save(image);
        } else {
            // 保存资源
            List<String> privateIps = Lists.newArrayList();
            if (!org.apache.commons.lang3.StringUtils.isEmpty(cloudServer.getPrivateIps())) {
                List<JSONObject> objects = JSONObject.parseArray(cloudServer.getPrivateIps(), JSONObject.class);
                for (JSONObject object : objects) {
                    String address = object.getString("address");
                    if (org.apache.commons.lang3.StringUtils.isEmpty(address)) {
                        continue;
                    }
                    privateIps.add(address);
                    Ip ip = ipRepository.checkExist(address, null, vendorId);
                    if (null == ip) {
                        ip = new Ip(address, null, null, null, vendorId, IDFactory.instance().uuid(), null,
                                Ip.IpStatus.used);
                        ip.setCatalog("VM");
                        ip.setTarget(cloudServer.getId());
                        for (IpPool pool : pools) {
                            String dns = null;
                            if (!org.apache.commons.lang3.StringUtils.isEmpty(pool.getDnsNames())) {
                                List<String> dnss = JSONArray.parseArray(pool.getDnsNames(), String.class);
                                if (!ListTool.isEmpty(dnss)) {
                                    dns = dnss.get(0);
                                }
                            }
                            List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                            IPAddress ipAddress = IPAddress.getIPAddress(address);
                            boolean flag = ipAddress.isInPools(address, poolList);
                            if (flag) {
                                ip.setMask(ipAddress.getMask(pool.getCidr()));
                                ip.setGateway(pool.getGateway());
                                ip.setDns(dns);
                                ip.setPoolId(pool.getId());
                                break;
                            }
                        }
                        ipRepository.save(ip);
                    } else {
                        ip.setTarget(serverId);
                        ip.setCatalog("VM");
                        ip.setStatus(Ip.IpStatus.used);
                        ip.setVendorId(vendorId);
                        ipRepository.update(ip);
                    }
                }
            }
            Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                    ResourceCatalog.LOGICAL.name(), serverId);
            if (null == resource) {
                resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), serverId,
                        JSONObject.toJSONString(privateIps), cloudServer.getOsCategory(), vendorId);
                resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, 0L);
                resource.setInventory(JSONObject.toJSONString(cloudServer));
                resourceRepository.save(resource);
            } else {
                resource.setStatus(cloudServer.getStatus());
                resource.setPrivateIps(JSONObject.toJSONString(privateIps));
                resource.setMenderId(userId);
                resource.setOsCategory(cloudServer.getOsCategory());
                resourceRepository.update(resource);
            }
        }
        // 同步存储
        addStore(vendorId, serverId, userId, "VM", cloudServer.getStores(), storeMap);
        // 同步网络
        addNetwork(vendorId, serverId, userId, "VM", cloudServer.getNetworks(), networkMap, groupMap);
        // 同步网卡
        addCard(vendorId, serverId, userId, "VM", cloudServer.getNetcards(), Maps.newHashMap());
        // 同步快照
        addSnapshot(vendorId, serverId, userId, cloudServer.getSnapshots());
        // 增加磁盘设备
        addDiskDevice(storeMap, vendorId, cloudServer.getVdcId(), serverId, userId, cloudServer.getDiskDevices());
    }

    /**
     * 添加磁盘设备
     *
     * @param storeMap
     * @param vendorId
     * @param vdcId
     * @param serverId
     * @param userId
     * @param disks
     * @throws Exception
     */
    public void addDiskDevice(Map<String, DataStore> storeMap, Long vendorId, Long vdcId, Long serverId, Long userId,
                              List<Volume> disks) throws Exception {
        if (!ListTool.isEmpty(disks)) {
            for (Volume disk : disks) {
                disk.preSave(userId, userId, 0L, vendorId);
                disk.setServerId(serverId);
                disk.setVolumeUuid(IDFactory.instance().uuid());
                String storeName = disk.getDataStoreName();
                if (!StringUtils.isEmpty(storeName)) {
                    DataStore store = dataStoreRepository.getByName(storeName, vdcId);
                    if (null != store) {
                        disk.setDataStoreId(store.getId());
                    }
                }
                disk.setCatalog(Catalog.Manager);
                if (null != disk.getStoreVal()) {
                    DataStore dataStore = storeMap.get(disk.getStoreVal());
                    if (null != dataStore) {
                        disk.setDataStoreId(dataStore.getId());
                    }
                }
                volumeRepository.save(disk);
            }
        }
    }

    public void addStore(Long vendorId, Long hostId, Long userId, String category, List<String> stores,
                         Map<String, DataStore> storeMap) throws Exception {
        if (!ListTool.isEmpty(stores)) {
            for (String store : stores) {
                if (storeMap.containsKey(store)) {
                    storeHostRepository.save(new StoreHost(storeMap.get(store).getId(), hostId, vendorId, category));
                }
            }
        }
    }

    public void addNetwork(Long vendorId, Long hostId, Long userId, String category, List<Network> networks,
                           Map<String, Network> networkMap, Map<String, String> groupMap) throws Exception {
        if (ListTool.isEmpty(networks)) {
            return;
        }
        Map<String, Network> netMap = Maps.newHashMap();
        for (String key : networkMap.keySet()) {
            netMap.put(key, networkMap.get(key));
        }
        for (Network network : networks) {
            String val = network.getNetworkVal();
            if (netMap.containsKey(val)) {// 网络存在则直接保存,标准网络
                networkHostRepository.save(new NetworkHost(netMap.get(val).getId(), hostId, vendorId, category));
            } else if (groupMap.containsKey(val) && netMap.containsKey(groupMap.get(val))) {// 网络不存，且在端口组中，则是分布式网络
                networkHostRepository
                        .save(new NetworkHost(netMap.get(groupMap.get(val)).getId(), hostId, vendorId, category));
                netMap.remove(groupMap.get(val));
            }
        }
    }

    public void addCard(Long vendorId, Long hostId, Long userId, String category, List<NetworkCard> cards,
                        Map<String, Long> switcherMap) throws Exception {
        if (ListTool.isEmpty(cards)) {
            return;
        }
        for (NetworkCard card : cards) {
            card.preSave(userId, userId, vendorId, hostId, category);
            if (!StringUtils.isEmpty(card.getSwitcher())) {
                card.setSwitcherId(switcherMap.get(card.getSwitcher()));
            }
            networkCardRepository.save(card);
        }
    }

    public void addSnapshot(Long vendorId, Long serverId, Long userId, List<Snapshot> snapshots) throws Exception {
        if (ListTool.isEmpty(snapshots)) {
            return;
        }
        for (Snapshot snapshot : snapshots) {
            snapshot.preSave(userId, userId, vendorId, serverId, 0L);
            snapshot.setCatalog(Catalog.Manager);
            snapshot.setSnapshotType("VM");
            snapshotRepository.save(snapshot);
        }
    }

    /**
     * 同步网卡
     *
     * @param oldCards
     * @param newCards
     * @param vendorId
     * @param hostId
     * @param userId
     * @throws Exception
     */
    public void syncNetworkCard(List<NetworkCard> oldCards, List<NetworkCard> newCards, Long vendorId, Long hostId,
                                Long userId, String category, Map<String, Long> switcherMap) throws Exception {
        if (ListTool.isEmpty(oldCards) && !ListTool.isEmpty(newCards)) {// 数据库不存在，该宿主机下存在网卡，则全部新增
            // 新增
            for (NetworkCard card : newCards) {
                card.preSave(userId, userId, vendorId, hostId, category);
                if (!StringUtils.isEmpty(card.getSwitcher())) {
                    card.setSwitcherId(switcherMap.get(card.getSwitcher()));
                }
                networkCardRepository.save(card);
            }
        } else if (!ListTool.isEmpty(oldCards) && !ListTool.isEmpty(newCards)) {// 数据库存在，该宿主机存在网卡，则更新或新增
            Map<String, NetworkCard> oldShot = Maps.newHashMap();
            for (NetworkCard card : oldCards) {
                oldShot.put(card.getMac(), card);
            }
            // 同步网卡更新新增
            for (NetworkCard card : newCards) {
                if (oldShot.containsKey(card.getMac())) {
                    NetworkCard netCard = oldShot.get(card.getMac());
                    netCard.setName(card.getName());
                    netCard.setMenderId(userId);
                    netCard.setVendorId(vendorId);
                    netCard.setHostId(hostId);
                    netCard.setLabel(card.getLabel());
                    netCard.setUsed(card.getUsed());
                    netCard.setPortType(card.getPortType());
                    if (!StringUtils.isEmpty(card.getSwitcher()) && card.getUsed()) {
                        netCard.setSwitcherId(switcherMap.get(card.getSwitcher()));
                    } else {
                        netCard.setSwitcherId(null);
                    }
                    networkCardRepository.update(netCard);
                    // 移除存在更新的网卡
                    oldShot.remove(card.getMac());
                } else {
                    card.preSave(userId, userId, vendorId, hostId, category);
                    if (!StringUtils.isEmpty(card.getSwitcher()) && card.getUsed()) {
                        card.setSwitcherId(switcherMap.get(card.getSwitcher()));
                    } else {
                        card.setSwitcherId(null);
                    }
                    networkCardRepository.save(card);
                }
            }
            // 同步删除不存在的快照
            Iterator<NetworkCard> cards = oldShot.values().iterator();
            while (cards.hasNext()) {
                networkCardRepository.remove(cards.next().getId(), userId);
            }
        } else if (!ListTool.isEmpty(oldCards) && ListTool.isEmpty(newCards)) {// 数据库存在，该虚拟机不存在网卡，则全部删除
            networkCardRepository.removeByHost(hostId, category, userId);
        }
    }

    /**
     * 同步快照
     *
     * @param oldShots
     * @param newShots
     * @param vendorId
     * @param vmId
     * @param userId
     * @throws Exception
     */
    public void syncSnapshot(List<Snapshot> oldShots, List<Snapshot> newShots, Long vendorId, Long vmId, Long userId)
            throws Exception {
        if (ListTool.isEmpty(oldShots) && !ListTool.isEmpty(newShots)) {// 数据库不存在，该虚拟机下存在快照，则全部新增
            // 新增
            for (Snapshot snapshot : newShots) {
                snapshot.preSave(userId, userId, vendorId, vmId, 0L);
                snapshot.setCatalog(Catalog.Manager);
                snapshot.setSnapshotType("VM");
                snapshotRepository.save(snapshot);
            }
        } else if (!ListTool.isEmpty(oldShots) && !ListTool.isEmpty(newShots)) {// 数据库存在，该虚拟机下存在快照，则全部新增更新或删除
            Map<String, Snapshot> oldShot = Maps.newHashMap();
            for (Snapshot shot : oldShots) {
                oldShot.put(shot.getSnapshotUuid() + shot.getSnapshotVal(), shot);
            }
            // 同步快照更新新增
            for (Snapshot snapshot : newShots) {
                if (oldShot.containsKey(snapshot.getSnapshotUuid() + snapshot.getSnapshotVal())) {
                    Snapshot shot = oldShot.get(snapshot.getSnapshotUuid() + snapshot.getSnapshotVal());
                    SnapshotModel bean = new SnapshotModel();
                    BeanUtils.copyProperties(snapshot, bean);
                    BeanUtils.copyProperties(bean, shot);
                    shot.setMenderId(userId);
                    shot.setVendorId(vendorId);
                    shot.setVmId(vmId);
                    if (null == shot.getCatalog()) {
                        shot.setCatalog(Catalog.Manager);
                    }
                    snapshot.setSnapshotType("VM");
                    snapshotRepository.update(shot);
                    // 移除存在更新的快照
                    oldShot.remove(snapshot.getSnapshotUuid() + snapshot.getSnapshotVal());
                } else {
                    snapshot.preSave(userId, userId, vendorId, vmId, 0L);
                    snapshot.setCatalog(Catalog.Manager);
                    snapshot.setSnapshotType("VM");
                    snapshotRepository.save(snapshot);
                }
            }
            // 同步删除不存在的快照
            Iterator<Snapshot> shots = oldShot.values().iterator();
            while (shots.hasNext()) {
                snapshotRepository.remove(shots.next().getId(), userId);
            }
        } else if (!ListTool.isEmpty(oldShots) && ListTool.isEmpty(newShots)) {// 数据库存在，该虚拟机不存在快照，则全部删除
            snapshotRepository.removeByVm(vmId, userId);
        }
    }

    /***
     * 标签
     * @param models
     * @param resourceId
     * @param resourceType
     * @param vendorId
     * @param regionId
     * @throws Exception
     */
    private void syncTag(List<TagModel> models, String resourceId, String resourceType, Long vendorId, String regionId)
            throws Exception {
        if (null == models) {
            return;
        }
        if (ListTool.isEmpty(models)) {
            tagRepository.removeByRes(vendorId, regionId, resourceId, resourceType);
            return;
        }
        List<Tag> tagList = tagRepository.listByRes(vendorId, regionId, resourceId, resourceType);
        Map<String, Tag> tagMap = Maps.newHashMap();
        for (Tag tag : tagList) {
            tagMap.put(tag.getKey() + "_" + resourceId + "_" + resourceType, tag);
        }
        for (TagModel model : models) {
            Tag tag = new Tag();
            if (tagMap.containsKey(model.getKey() + "_" + resourceId + "_" + resourceType)) {
                tag = tagMap.get(model.getKey() + "_" + resourceId + "_" + resourceType);
                BeanUtils.copyProperties(model, tag);
                tag.setResourceType(resourceType);
                tag.setVendorId(vendorId);
                tag.setGmtModify(new Date());
                tag.setRegionId(regionId);
                tagRepository.update(tag);
                tagMap.remove(model.getKey() + "_" + resourceId + "_" + resourceType);
                continue;
            }
            BeanUtils.copyProperties(model, tag);
            tag.setResourceType(model.getResourceType());
            tag.setVendorId(vendorId);
            tag.setRegionId(regionId);
            tagRepository.save(tag);
            tagMap.remove(model.getKey() + "_" + resourceId + "_" + resourceType);
        }
        for (Map.Entry<String, Tag> entry : tagMap.entrySet()) {
            tagRepository.remove(entry.getValue().getId());
        }
    }
}
