package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.NotifyMessage;
import com.bocloud.cmp.provider.utils.IPAddress;
import com.bocloud.cmp.vm.model.IpScanParam;
import com.bocloud.common.exception.BoCloudDBException;
import com.bocloud.common.model.*;
import com.bocloud.common.model.OperateResult.OperateCategory;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.params.IpPatchParams;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.Ip.IpStatus;
import com.bocloud.ims.entity.resource.hmc.HmcServer;
import com.bocloud.ims.entity.resource.nsx.*;
import com.bocloud.ims.interfaces.resource.IpService;
import com.bocloud.ims.repository.common.*;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.repository.resource.hmc.HmcServerRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
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.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author wangyu
 * @version 5.1.0
 * @description IP业务接口实现
 * @date: 2020-11-30
 */
@Service("ipService")
public class IpServiceImpl implements IpService {

    private static Logger logger = LoggerFactory.getLogger(IpServiceImpl.class);

    @Autowired
    private HmcServerRepository hmcServerRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private IpPoolRepository ipPoolRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private PoolGroupRepository poolGroupRepository;
    @Autowired
    private NsxRouterRepository routerRepository;
    @Autowired
    private NsxRouterPortRepository portRepository;
    @Autowired
    private NsxVcenterRelationRepository relationRepository;
    @Autowired
    private NsxSwitchPortRepository switchPortRepository;
    @Autowired
    private NsxSegmentRepository segmentRepository;
    @Autowired
    private NsxTierOneRepository tierOneRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public BocloudResult<GridBean<Ip>> list(Pager pager) {
        try {
            List<Object> pools = null;

            List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
            Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
            sorter.put("gmtCreate", Common.ONE);
            Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
            Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);

            GridBean gridBean = null;
            List<Ip> list = ipRepository.list(page, rows, params, sorter);
            for (Ip ip : list) {
                if (null != ip.getTarget() && null != ip.getCatalog()) {
                    if ("VM".equalsIgnoreCase(ip.getCatalog())) {
                        CloudServer server = cloudServerRepository.query(ip.getTarget());
                        if (null != server) {
                            ip.setTargetName(server.getName());
                        }
                    } else if ("PM".equalsIgnoreCase(ip.getCatalog())) {
                        Server host = serverRepository.query(ip.getTarget());
                        if (null != host) {
                            ip.setTargetName(host.getName());
                        }
                    }
                }
            }
            int total = ipRepository.count(params);
            gridBean = GridHelper.getBean(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list ip failure:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }

    }

    @Override
    public BocloudResult condition(String condition, RequestContext context) {
        try {
            List<Object> pools = null;
            JSONObject object = JSONObject.parseObject(condition);
            if ("achieveIps".equalsIgnoreCase(object.getString("condition"))) {
                BocloudResult<List<Ip>> result = this.achieveIps(object.getLong("count"), "");
                return new BocloudResult<>(result.isSuccess(), result.getData(), result.getMessage());
            } else if ("alarmIps".equalsIgnoreCase(object.getString("condition"))) {
                return this.alarmIps(object.getLong("vendorId"));
            } else if ("preAllocation".equalsIgnoreCase(object.getString("condition"))) {
                return this.preAllocation(object.getLong("poolId"), object.getInteger("count"), context);
            } else if ("checkIp".equalsIgnoreCase(object.getString("condition"))) {
                List<String> ips = JSONArray.parseArray(object.getString("ips"), String.class);
                return this.checkIp(object.getLong("poolId"), ips, context);
            }
//			if ("ipCount".equalsIgnoreCase(object.getString("condition"))) {
//				String poolName = null;
//				Long vendorId = null;
//				Iterator<Param> iterator = params.iterator();
//				while (iterator.hasNext()) {
//					Param param = iterator.next();
//					Map<String, Object> map = param.getParam();
//					for (String key : map.keySet()) {
//						if ("poolName".equals(key)) {
//							poolName = String.valueOf(map.get(key));
//							iterator.remove();
//							break;
//						}
//						if ("vendorId".equals(key)) {
//							vendorId = Long.valueOf((int) map.get(key));
//							break;
//						}
//					}
//				}
//				// 根据条件查询ip池
//				ArrayList<Param> paramsData = new ArrayList<>();
//				if (null != vendorId && 0L != vendorId) {
//					paramsData.add(new Param(MapTools.simpleMap("vendorId", vendorId), Sign.EQ));
//				}
//				if (null != poolName) {
//					paramsData.add(new Param(MapTools.simpleMap("name", poolName), Sign.LK));
//				}
//				List<IpPool> ipPools = ipPoolRepository.list(1, Integer.MAX_VALUE, paramsData, null);
//				pools = Lists.newArrayList();
//				for (IpPool ipPool : ipPools) {
//					pools.add(ipPool.getId());
//				}
//				if (!pools.isEmpty()) {
//					params.add(new Param(MapTools.simpleMap("pool_id", InBuilder.build(pools)), Sign.IN));
//				}
//			}
//			GridBean gridBean = null;
//			if (null == sorter) {
//				sorter = Maps.newHashMap();
//			}
//			List<Ip> list = ipRepository.list(page, rows, params, sorter);
//			for (Ip ip : list) {
//				if (null != ip.getTarget() && null != ip.getCatalog()) {
//					if ("VM".equalsIgnoreCase(ip.getCatalog())) {
//						CloudServer server = cloudServerRepository.query(ip.getTarget());
//						if (null != server) {
//							ip.setTargetName(server.getName());
//						}
//					} else if ("PM".equalsIgnoreCase(ip.getCatalog())) {
//						Server host = serverRepository.query(ip.getTarget());
//						if (null != host) {
//							ip.setTargetName(host.getName());
//						}
//					}
//				}
//			}
//			int total = ipRepository.count(params);
//			gridBean = GridHelper.getBean(page, rows, total, list);
//			return new BocloudResult<>(true, gridBean, "查询成功");
            return new BocloudResult<>(false, "参数格式错误");
        } catch (Exception e) {
            logger.error("list ip failure:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }

    }

    @Override
    public BocloudResult<Ip> detail(Long id) {
        try {
            Ip ip = this.ipRepository.query(id);
            if (null == ip) {
                return new BocloudResult<>(false, "IP不存在");
            }
            if (null != ip.getTarget() && null != ip.getCatalog()) {
                if ("VM".equalsIgnoreCase(ip.getCatalog())) {
                    CloudServer server = cloudServerRepository.query(ip.getTarget());
                    if (null != server) {
                        ip.setTargetName(server.getName());
                    }
                } else if ("PM".equalsIgnoreCase(ip.getCatalog())) {
                    Server host = serverRepository.query(ip.getTarget());
                    if (null != host) {
                        ip.setTargetName(host.getName());
                    }
                }
            }
            return new BocloudResult<>(true, ip, "查询IP详情成功");
        } catch (Exception e) {
            logger.error("Get IP Exception：", e);
            return new BocloudResult<>(false, "查询IP详情失败");
        }
    }

    @Override
    public BocloudResult<List<Ip>> achieveIps(Long count, String version) {
        String path = Ip.class.getSimpleName() + "_vendor_assign";
        List<Ip> assignIps = new ArrayList<>();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            if (StringUtils.isEmpty(version)) {
                version = "V4";
            }
            List<IpPool> pools = ipPoolRepository.listByIpVersion(version);
            Assert.notEmpty(pools, "当前所选云平台下未找到IP池数据");
            List<String> statusList = new ArrayList<>();
            statusList.add(IpStatus.free.name());
            // 查询所有未使用ip地址
            List<Ip> unusedIps = new ArrayList<>();
            for (IpPool pool : pools) {
                List<Ip> ips = ipRepository.listByStatus(statusList, pool.getId());
                if (!ListTool.isEmpty(ips)) {
                    unusedIps.addAll(ips);
                }
            }
            if (unusedIps.size() < count) {
                return new BocloudResult<>(false, "可用ip不足");
            }
            for (Ip ip : unusedIps) {
                if (assignIps.size() == count) {
                    break;
                }
                // 分配之前先ping
//				if (ping(ip.getIp(), 4, 2000)) {
//					ip.setStatus(IpStatus.locked);
//					ip.setTarget(null);
//					ip.setCatalog(null);
//					ipRepository.update(ip);
//					continue;
//				}
                Ip existIp = ipRepository.query(ip.getId());
                if (null == existIp || IpStatus.free != existIp.getStatus()) {
                    continue;
                }
                existIp.setCatalog("VM");
                existIp.setStatus(IpStatus.lock);
                ipRepository.update(existIp);
                assignIps.add(existIp);
            }
            if (assignIps.isEmpty() || assignIps.size() < count) {
                return new BocloudResult<>(false, "ip池下无IP可分配!");
            }
            logger.info("分配的ip地址：{}", JSONObject.toJSON(assignIps));
            return new BocloudResult<>(true, assignIps, "success");
        } catch (Exception e) {
            for (Ip assignIp : assignIps) {
                ipRepository.makeFreeById(assignIp.getId());
            }
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Ip>> assginIps(Long poolId, Long count, String version) {
        String path = Ip.class.getSimpleName() + "_vendor_assign" + poolId;
        List<Ip> assignIps = new ArrayList<>();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            if (StringUtils.isEmpty(version)) {
                version = "V4";
            }
            IpPool ipPool = ipPoolRepository.query(poolId);
            Assert.notNull(ipPool, "当前所选云平台下未找到IP池数据");
            List<String> statusList = new ArrayList<>();
            statusList.add(IpStatus.free.name());
            // 查询所有未使用ip地址
            List<Ip> unusedIps = new ArrayList<>();
            List<Ip> ips = ipRepository.listByStatus(statusList, ipPool.getId());
            if (!ListTool.isEmpty(ips)) {
                unusedIps.addAll(ips);
            }
            if (unusedIps.size() < count) {
                return new BocloudResult<>(false, "可用ip不足");
            }
            for (Ip ip : unusedIps) {
                if (assignIps.size() == count) {
                    break;
                }
                Ip existIp = ipRepository.query(ip.getId());
                if (null == existIp || IpStatus.free != existIp.getStatus()) {
                    continue;
                }
                existIp.setCatalog("VM");
                existIp.setStatus(IpStatus.lock);
                ipRepository.update(existIp);
                assignIps.add(existIp);
            }
            if (assignIps.isEmpty() || assignIps.size() < count) {
                return new BocloudResult<>(false, "ip池下无IP可分配!");
            }
            logger.info("分配的ip地址：{}", JSONObject.toJSON(assignIps));
            return new BocloudResult<>(true, assignIps, "success");
        } catch (Exception e) {
            for (Ip assignIp : assignIps) {
                ipRepository.makeFreeById(assignIp.getId());
            }
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult processRubbishIp(Long vendorId) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (null == vendor) {
                logger.error("Cloud vendor does not exists");
                return new BocloudResult<>(false, "云平台不存在");
            }
            List<CloudServer> servers = cloudServerRepository.listByVid(vendorId);
            List<Server> hosts = serverRepository.listByVendor(vendorId);
            Set<String> vmExistIps = Sets.newHashSet();
            Set<String> pmExistIps = Sets.newHashSet();
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            switch (provider) {
                case VMWARE:
                case FUSIONCLOUD:
                    for (CloudServer server : servers) {
                        String privateIps = server.getPrivateIps();
                        if (StringUtils.isEmpty(privateIps)) {
                            continue;
                        }
                        List<JSONObject> objects = JSONArray.parseArray(privateIps, JSONObject.class);
                        for (JSONObject object : objects) {
                            String address = object.getString("address");
                            if (!StringUtils.isEmpty(address)) {
                                vmExistIps.add(address);
                            }
                        }
                    }
                    for (Server host : hosts) {
                        String manageIp = host.getManageIp();
                        String serviceIp = host.getServiceIp();
                        if (!StringUtils.isEmpty(manageIp)) {
                            pmExistIps.add(manageIp);
                        }
                        if (!StringUtils.isEmpty(serviceIp)) {
                            pmExistIps.add(serviceIp);
                        }
                    }
                    break;
                case HMC:
                    List<HmcServer> hmcServers = hmcServerRepository.listByVendorId(vendorId);
                    for (HmcServer server : hmcServers) {
                        String address = server.getPrimaryIpAddress();
                        if (!StringUtils.isEmpty(address)) {
                            pmExistIps.add(address);
                        }
                    }
                    break;
                case UNKNOWN:
                    break;
                default:
                    break;
            }
            List<String> vmExistIpList = new ArrayList<>(vmExistIps);
            ipRepository.makeFree("VM", vmExistIpList, vendorId);
            ipRepository.deleteNullIp("VM", vendorId);
            List<String> pmExistIpList = new ArrayList<>(pmExistIps);
            ipRepository.makeFree("PM", pmExistIpList, vendorId);
            ipRepository.deleteNullIp("PM", vendorId);
            return new BocloudResult<>(true, "处理垃圾IP数据成功");
        } catch (Exception e) {
            return new BocloudResult<>(false, "处理垃圾IP数据失败");
        }
    }

    /**
     * 从网络资源池下的IP池中分配IP地址
     *
     * @param vendorId
     * @param poolGroupId
     * @param count
     * @return
     */
    @Override
    public BocloudResult<List<Ip>> achieveIps(Long vendorId, Long poolGroupId, Integer count) {
        String path = Ip.class.getSimpleName() + "_vendor_" + vendorId;
        List<Ip> assignIps = new ArrayList<>();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(20, TimeUnit.SECONDS), "请求超时");
            PoolGroup poolGroup = poolGroupRepository.query(poolGroupId);
            if (null == poolGroup) {
                return new BocloudResult<>(false, "网络资源池不存在");
            }
            List<IpPool> pools = ipPoolRepository.listByGroupId(poolGroupId);
            if (ListTool.isEmpty(pools)) {
                logger.warn("This vendor does not exist ip!");
                return new BocloudResult<>(false, "网络资源池【" + poolGroup.getName() + "】下无IP可分配!");
            }
            List<String> statusList = new ArrayList<>();
            statusList.add(IpStatus.free.name());
            // 查询所有未使用ip地址
            List<Ip> unusedIps = new ArrayList<>();
            for (IpPool pool : pools) {
                List<Ip> ips = ipRepository.listByStatus(statusList, pool.getId());
                if (!ListTool.isEmpty(ips)) {
                    unusedIps.addAll(ips);
                }
            }
            if (unusedIps.size() < count) {
                return new BocloudResult<>(false, "可用ip不足");
            }
            for (Ip ip : unusedIps) {
                if (assignIps.size() == count) {
                    break;
                }
                // 分配之前先ping
//                if (ping(ip.getIp(), 4, 2000)) {
//                    ip.setStatus(IpStatus.locked);
//                    ip.setTarget(null);
//                    ip.setCatalog(null);
//                    ipRepository.update(ip);
//                    continue;
//                }
                Ip existIp = ipRepository.query(ip.getId());
                if (null == existIp || IpStatus.free != existIp.getStatus()) {
                    continue;
                }
                existIp.setCatalog("VM");
                existIp.setStatus(IpStatus.lock);
                ipRepository.update(existIp);
                assignIps.add(existIp);
            }
            if (assignIps.isEmpty() || assignIps.size() < count) {
                return new BocloudResult<>(false, "ip池下无IP可分配!");
            }
            logger.info("分配的ip地址：{}", JSONObject.toJSON(assignIps));
            return new BocloudResult<>(true, assignIps, "success");
        } catch (Exception e) {
            for (Ip assignIp : assignIps) {
                ipRepository.makeFreeById(assignIp.getId());
            }
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<String>> alarmIps(Long vendorId) {
        try {
            Map<String, String> ipMap = Maps.newHashMap();
            List<Server> servers = serverRepository.listByVendor(vendorId);
            for (Server server : servers) {
                String ip = server.getManageIp();
                if (!StringUtils.isEmpty(ip)) {
                    ipMap.put(ip, ip);
                }
            }
            List<CloudServer> vms = cloudServerRepository.listByVendorId(vendorId);
            for (CloudServer vm : vms) {
                String privateIps = vm.getPrivateIps();
                if (!StringUtils.isEmpty(privateIps)) {
                    CloudProvider provider = CloudProvider.valueOf(vm.getVendorType());
                    switch (provider) {
                        case OPENSTACK:
                            List<JSONObject> privateObjs = JSONArray.parseArray(privateIps, JSONObject.class);
                            for (JSONObject object : privateObjs) {
                                List<Object> addresses = object.getJSONArray("addresses");
                                for (Object address : addresses) {
                                    if (StringUtils.isEmpty(JSONObject.parseObject(JSONObject.toJSONString(address))
                                            .getString("address"))) {
                                        continue;
                                    }
                                    String addr = JSONObject.parseObject(JSONObject.toJSONString(address))
                                            .getString("address");
                                    if (!StringUtils.isEmpty(addr)) {
                                        ipMap.put(addr, addr);
                                    }
                                }
                            }
                            break;
                        case VMWARE:
                            List<JSONObject> vcIps = JSONArray.parseArray(privateIps, JSONObject.class);
                            for (JSONObject vcIp : vcIps) {
                                String address = vcIp.getString("address");
                                if (!StringUtils.isEmpty(address)) {
                                    ipMap.put(address, address);
                                }
                            }
                            break;
                        default:
                            break;
                    }

                }
            }
            return new BocloudResult<>(true, new ArrayList<>(ipMap.values()), "查询成功");
        } catch (Exception e) {
            logger.error("Get error message:", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<List<Ip>> achieveNsxIps(Long routerPortId, Integer count, String version) {
        Long start = System.currentTimeMillis();
        String path = Ip.class.getSimpleName() + "_nsx_subnet_" + routerPortId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(1, TimeUnit.MINUTES), "分配nsx IP地址请求超时");
            NsxRouterPort routerPort = portRepository.query(routerPortId);
            Assert.notNull(routerPort, "路由器端口不存在");
            NsxLogicalRouter router = routerRepository.query(routerPort.getRouterId());
            Assert.notNull(router, "路由器不存在");
            List<IpPool> pools = ipPoolRepository.listByPortId(routerPortId, version);
            Assert.notEmpty(pools, "路由器端口下未找到IP池");
            Map<String, String> map = new ConcurrentHashMap<>();
            // nsx关联vcenter云平台下所有已用IP地址
            List<NsxVcenterRelation> relations = relationRepository.listByNsxVendorId(routerPort.getVendorId());
            for (NsxVcenterRelation relation : relations) {
                List<Ip> vcVendorIps = ipRepository.listByVcIpPoolIps(relation.getVcenterVendorId());
                for (Ip ip : vcVendorIps) {
                    map.put(ip.getIp(), ip.getIp());
                }
            }
            // 路由器下所有路由器端口已使用IP
            List<NsxRouterPort> ports = portRepository.listByRouterId(router.getId());
            List<Long> portIds = new ArrayList<>();
            for (NsxRouterPort port : ports) {
                portIds.add(port.getId());
            }
            // 路由器端口下所有路由器端口子网IP地址池下的已用IP
            if (!ListTool.isEmpty(portIds)) {
                List<IpPool> ipPools = ipPoolRepository.listByPortIds(portIds, version);
                for (IpPool pool : ipPools) {
                    List<Ip> ips = ipRepository.listByPool(pool.getId());
                    for (Ip ip : ips) {
                        map.put(ip.getIp(), ip.getIp());
                    }
                }
            }
            // 云平台已锁定的IP(手动在管理端添加)
            List<Ip> lockIps = ipRepository.listLockedIps();
            for (Ip ip : lockIps) {
                map.put(ip.getIp(), ip.getIp());
            }
            List<Ip> list = new ArrayList<>();
            List<Ip> reachableIps = new ArrayList<>();
            int index = 0;
            for (IpPool pool : pools) {
                List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                String dns = JSONArray.parseArray(pool.getDnsNames(), String.class).get(0);
                for (String ipPools : poolList) {
                    String[] startEndIp = ipPools.split("-");
                    IPAddress address = IPAddress.getIPAddress(startEndIp[0]);
                    BigInteger ipstart = address.ipToInteger(startEndIp[0]);// 获取起始IP的开始位置
                    BigInteger ipend = address.ipToInteger(startEndIp[1]);// 获取终止IP的结束位置
                    while (ipend.compareTo(ipstart) >= 0) {
                        String ipKey = address.integerToIp(ipstart);
                        if (!map.containsKey(ipKey)) {
                            Ip ip = new Ip(ipKey, address.getMask(pool.getCidr()), pool.getGateway(), dns,
                                    pool.getVendorId(), IDFactory.instance().uuid(), pool.getId(), IpStatus.used);
                            ip.setCatalog("VM");
                            list.add(ip);
                            index++;
                        }
                        if (index >= count) {
                            break;
                        }
                        ipstart = ipstart.add(new BigInteger("1"));
                    }
                    if (index >= count) {
                        break;
                    }
                }
                if (index >= count) {
                    break;
                }
            }
            if (list.isEmpty() || list.size() < count) {
                logger.info("路由器端口{}下无可用IP", routerPort.getName());
                return new BocloudResult<>(false, "此平台下无IP可分配!");
            }
            if (!ListTool.isEmpty(reachableIps)) {
                ipRepository.batchCreate(reachableIps);
            }
            if (!ListTool.isEmpty(list)) {
                ipRepository.batchCreate(list);
            }
            logger.info("从路由器端口{}下子网获取到的IP地址：{}", routerPort.getName(), JSONObject.toJSON(list));
            Long end = System.currentTimeMillis();
            logger.info("分配nsx下IP地址耗时：{}毫秒", (end - start));
            return new BocloudResult<>(true, list, "success");
        } catch (Exception e) {
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = BoCloudDBException.class)
    public BocloudResult deleteBySubnetId(String ip, Long subnetId) {
        String path = Ip.class.getSimpleName() + "_subnet_" + ip;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            List<NsxSwitchPort> ports = switchPortRepository.listBySwitchId(subnetId);
            for (NsxSwitchPort port : ports) {
                List<NsxRouterPort> routerPorts = portRepository.listByLinkedSwitchPortId(port.getId());
                for (NsxRouterPort routerPort : routerPorts) {
                    List<IpPool> ipPools = ipPoolRepository.listByPortId(routerPort.getId(), "V4");
                    for (IpPool ipPool : ipPools) {
                        ipRepository.delete(ip, ipPool.getId());
                    }
                }
            }
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    @Override
    @Transactional(rollbackFor = BoCloudDBException.class)
    public BocloudResult batchSave(JSONObject object, RequestContext context) {
        try {
            String start = object.getString("start");
            String end = object.getString("end");
            IPAddress address = IPAddress.getIPAddress(start);
            BigInteger ipstart = address.ipToInteger(start);// 获取起始IP的开始位置
            BigInteger ipend = address.ipToInteger(end);// 获取终止IP的结束位置
            List<Ip> ips = new ArrayList<>();
            List<Ip> existIps = ipRepository.listLockedIps();
            Map<String, String> ipMap = new HashMap<>();
            existIps.forEach(i -> ipMap.put(i.getIp(), i.getIp()));
            while (ipend.compareTo(ipstart) >= 0) {
                String ipKey = address.integerToIp(ipstart);
                if (ipMap.containsKey(ipKey)) {
                    continue;
                }
                ips.add(new Ip(ipKey, null, null, null, 0L, null, null, IpStatus.lock));
                ipstart = ipstart.add(new BigInteger("1"));
            }
            if (!ListTool.isEmpty(ips)) {
                ipRepository.batchCreate(ips);
            }
            return new BocloudResult<>(true, "批量保存成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, "批量保存失败");
        }
    }

    @Override
    @Transactional(rollbackFor = BoCloudDBException.class)
    public BocloudResult remove(Long id) {
        String path = Ip.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Boolean flag = ipRepository.delete(id);
            if (!flag) {
                return new BocloudResult<>(false, "删除失败");
            }
            return new BocloudResult<>(true, "删除成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, "删除失败");
        }
    }

    @Override
    public BocloudResult<List<Ip>> achieveDhcpIps(Long poolId, Long count, String version) {
        String path = Ip.class.getSimpleName() + "_vendor_assign";
        List<Ip> assignIps = new ArrayList<>();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            if (StringUtils.isEmpty(version)) {
                version = "V4";
            }
            List<String> statusList = new ArrayList<>();
            statusList.add(IpStatus.free.name());
            // 查询所有未使用ip地址
            List<Ip> unusedIps = new ArrayList<>();
            List<Ip> ips = ipRepository.listByStatus(statusList, poolId);
            if (!ListTool.isEmpty(ips)) {
                unusedIps = new ArrayList<>(ips);
            }
            if (unusedIps.size() < count) {
                return new BocloudResult<>(false, "可用ip不足");
            }
            // dhcp方式从ip池中随机查找未使用的ip进行分配
            while (assignIps.size() < count) {
                int index = new Random().nextInt(unusedIps.size());
                Ip ip = unusedIps.get(index);
                // 分配之前先ping
                if (ping(ip.getIp(), 4, 2000)) {
                    ip.setStatus(IpStatus.lock);
                    ip.setTarget(null);
                    ip.setCatalog(null);
                    ipRepository.update(ip);
                    unusedIps.remove(index);
                    continue;
                }
                Ip existIp = ipRepository.query(ip.getId());
                if (null == existIp || IpStatus.free != existIp.getStatus()) {
                    unusedIps.remove(index);
                    continue;
                }
                existIp.setCatalog("VM");
                existIp.setStatus(IpStatus.lock);
                ipRepository.update(existIp);
                assignIps.add(existIp);
                unusedIps.remove(index);
            }
            if (assignIps.isEmpty() || assignIps.size() < count) {
                return new BocloudResult<>(false, "ip池下无IP可分配!");
            }
            logger.info("分配的ip地址：{}", JSONObject.toJSON(assignIps));
            return new BocloudResult<>(true, assignIps, "success");
        } catch (Exception e) {
            for (Ip assignIp : assignIps) {
                ipRepository.makeFreeById(assignIp.getId());
            }
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult scan(IpScanParam param, RequestContext context) {
        Long vendorId = param.getVendorId();
        Long poolId = param.getPoolId();
        List<Long> poolIds = param.getPoolIds();
        String path;
        if (null != vendorId && 0L != vendorId) {
            path = Ip.class.getSimpleName() + "_vendor_" + vendorId;
        } else if (null != poolId && 0L != poolId) {
            path = Ip.class.getSimpleName() + "_pool_" + poolId;
        } else {
            path = Ip.class.getSimpleName() + "_pools";
        }
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            List<IpPool> pools = new ArrayList<>();
            if (null != vendorId && 0L != vendorId) {
                pools = ipPoolRepository.listByIpVersion("V4");
            } else if (null != poolId && 0L != poolId) {
                IpPool pool = ipPoolRepository.query(poolId);
                Assert.notNull(pool, "IP池不存在");
                pools.add(pool);
            } else {
                pools = ipPoolRepository.pools(poolIds);
            }
            final List<IpPool> finalPools = pools;
            new Thread(() -> {
                List<Ip> reachableIps = new ArrayList<>();
                boolean success = true;
                String message = "IP扫描完成，本次扫描未锁定任何IP地址";
                for (IpPool pool : finalPools) {
                    List<String> statusList = new ArrayList<>();
                    statusList.add(IpStatus.free.name());
                    List<Ip> ips = ipRepository.listByStatus(statusList, pool.getId());
                    for (Ip ip : ips) {
                        ip = ipRepository.query(ip.getId());
                        if (null == ip || IpStatus.used == ip.getStatus()) {
                            continue;
                        }
                        // IP池扫描，若虚机名称包含此IP，将此IP标记为已使用，主要针对一些因vmtool未开启未获取到IP的机器及关机状态机器
                        CloudServer cloudServer = cloudServerRepository.checkCloudServerName(ip.getIp());
                        if (null != cloudServer) {
                            ip.setStatus(IpStatus.used);
                            ip.setTarget(cloudServer.getId());
                            ip.setVendorId(cloudServer.getVendorId());
                            ip.setCatalog("VM");
                            ipRepository.update(ip);
                            reachableIps.add(ip);
                        } else {
                            if (ping(ip.getIp(), 4, 2000)) {
                                ip.setStatus(IpStatus.lock);
                                ip.setTarget(null);

                                ip.setCatalog(null);
                                ipRepository.update(ip);
                                reachableIps.add(ip);
                            }
                        }

                    }
                }
                if (!ListTool.isEmpty(reachableIps)) {
                    String ipMsg = "";
                    for (Ip ip : reachableIps) {
                        ipMsg += ip.getIp() + ",";
                        ipRepository.save(ip);
                    }
                    if (ipMsg.lastIndexOf(",") > 0) {
                        ipMsg = ipMsg.substring(0, ipMsg.lastIndexOf(","));
                    }
                    message = "IP扫描完成，本次扫描锁定了以下IP地址：【" + ipMsg + "】";
                }
                resourceEventPublisher.send(new OperateResult(success, message, "resource.ip", null,
                        OperateCategory.ResourceEvent, context));
                // 发送站内信
                NotifyMessage notifyMessage = new NotifyMessage(context, "IP扫描任务", message, true, false);
                amqpTemplate.convertAndSend("event.notice.queue", notifyMessage);
            }).start();
            return new BocloudResult<>(true, "IP地址扫描任务已下发，请耐心等待扫描结果...");
        } catch (Exception e) {
            logger.error("Get error message:{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    public static boolean ping(String ipAddress, int pingTimes, int timeOut) {
        logger.info("开始ping{}", ipAddress);
        BufferedReader in = null;
        Runtime r = Runtime.getRuntime(); // 将要执行的ping命令,此命令是windows格式的命令
        String osName = System.getProperty("os.name");
        String pingCommand = "ping " + ipAddress + " -c " + pingTimes;
        if (osName.contains("Windows") || osName.contains("windows")) {
            pingCommand = "ping " + ipAddress + " -n " + pingTimes + " -w " + timeOut;
        }
        try {
            Process p = r.exec(pingCommand);
            if (p == null) {
                return false;
            }
            in = new BufferedReader(new InputStreamReader(p.getInputStream())); // 逐行检查输出,计算类似出现=23ms TTL=62字样的次数
            int connectedCount = 0;
            String line = null;
            while ((line = in.readLine()) != null) {
                connectedCount += getCheckResult(line);
            }
            // 如果出现类似=23ms TTL=62这样的字样,出现的次数=测试次数则返回真
            logger.info("结束ping{},ping次数{}", ipAddress, pingTimes);
            return connectedCount == pingTimes;
        } catch (Exception ex) {
            ex.printStackTrace(); // 出现异常则返回假
            return false;
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
    private static int getCheckResult(String line) {
        if (line.contains("ttl") || line.contains("TTL")) {
            return 1;
        }
        return 0;
    }

    @Override
    public BocloudResult<List<Ip>> preAllocation(Long poolId, Integer count, RequestContext context) {
        String path = Ip.class.getSimpleName() + "_pool_" + poolId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            IpPool pool = ipPoolRepository.query(poolId);
            Assert.notNull(pool, "IP池不存在");
            // Ip池已使用IP地址
            List<Ip> ips = ipRepository.listByStatus(Arrays.asList("used", "lock", "preempt"), poolId);
            Map<String, Ip> map = Maps.newHashMap();
            for (Ip ip : ips) {
                map.put(ip.getIp(), ip);
            }
            // 已锁定IP地址
            List<Ip> lockIps = ipRepository.listLockedIps();
            for (Ip ip : lockIps) {
                map.put(ip.getIp(), ip);
            }
            List<Ip> reachableIps = new ArrayList<>();
            int index = 0;
            List<Ip> poolIds = ipRepository.listByPool(poolId);
            for (Ip ip : poolIds) {
                String ipKey = ip.getIp();
                if (!map.containsKey(ipKey)) {
                    reachableIps.add(ip);
                    index++;
                }
                if (index >= count) {
                    break;
                }
            }
            if (reachableIps.isEmpty() ) {
                return new BocloudResult<>(false, "该IP池下无IP可分配!");
            }
            if (reachableIps.size() < count ) {
                return new BocloudResult<>(false, "此IP池下可分配IP不足!");
            }
            return new BocloudResult<>(true, reachableIps, "分配成功");
        } catch (Exception e) {
            logger.error("Pre allocation Ip failed:{}", e.getMessage());
            return new BocloudResult<>(false, "分配IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult checkIp(Long poolId, List<String> ips, RequestContext context) {
        try {
            if (ListTool.isEmpty(ips)) {
                return new BocloudResult<>(false, "无IP可校验");
            }
            for (String ip : ips) {
                Ip database = ipRepository.checkIp(poolId, ip);
                if (null != database) {
                    return new BocloudResult<>(false, "IP地址【" + ip + "】已被使用，请重新设置");
                }
            }
            return new BocloudResult<>(true, "IP校验通过");
        } catch (Exception e) {
            logger.error("Get error message:{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Ip>> achievePoolIps(Long poolId, Long count, String version) {
        IpPool pool = null;
        try {
            pool = ipPoolRepository.query(poolId);
            Assert.notNull(pool, "IP池不存在");
        } catch (Exception e) {
            logger.error("Get error mesage：{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
        String path = Ip.class.getSimpleName() + "_vendor_assign";
        List<Ip> assignIps = new ArrayList<>();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(600, TimeUnit.SECONDS), "请求超时");
            List<String> statusList = new ArrayList<>();
            // 查询所有未使用ip地址
            statusList.add(IpStatus.free.name());
            List<Ip> unusedIps = ipRepository.listByStatus(statusList, poolId);
            for (Ip ip : unusedIps) {
                if (assignIps.size() == count) {
                    break;
                }
                if (ping(ip.getIp(), 4, 2000)) {
                    ip.setStatus(IpStatus.lock);
                    ip.setTarget(null);
                    ip.setCatalog(null);
                    ipRepository.update(ip);
                    continue;
                }
                Ip existIp = ipRepository.query(ip.getId());
                if (null == existIp || IpStatus.free != existIp.getStatus()) {
                    continue;
                }
                existIp.setCatalog("VM");
                existIp.setStatus(IpStatus.lock);
                ipRepository.update(existIp);
                assignIps.add(existIp);
            }
            if (assignIps.isEmpty() || assignIps.size() < count) {
                return new BocloudResult<>(false, "ip池下无IP可分配!");
            }
            logger.info("分配的ip地址：{}", JSONObject.toJSON(assignIps));
            return new BocloudResult<>(true, assignIps, "success");
        } catch (Exception e) {
            for (Ip assignIp : assignIps) {
                assignIp.setStatus(IpStatus.free);
                ipRepository.update(assignIp);
            }
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<Ip>> achieveNsxSegmentIps(Long segmentId, Integer count, String version) {
        Long start = System.currentTimeMillis();
        String path = Ip.class.getSimpleName() + "_nsx_segment_" + segmentId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(1, TimeUnit.MINUTES), "分配nsx IP地址请求超时");
            NsxSegment segment = segmentRepository.query(segmentId);
            Assert.notNull(segment, "分段不存在");
            List<IpPool> pools = ipPoolRepository.listBySegmentId(segmentId, version);
            Assert.notEmpty(pools, "路由器端口下未找到IP池");
            Map<String, String> map = new ConcurrentHashMap<>();
            // nsx关联vcenter云平台下所有已用IP地址
            List<NsxVcenterRelation> relations = relationRepository.listByNsxVendorId(segment.getVendorId());
            for (NsxVcenterRelation relation : relations) {
                List<Ip> vcVendorIps = ipRepository.listByVcIpPoolIps(relation.getVcenterVendorId());
                for (Ip ip : vcVendorIps) {
                    map.put(ip.getIp(), ip.getIp());
                }
            }
            // Tier1下所有分段已使用IP
            List<NsxSegment> segments = segmentRepository.listByConnectivityPath(segment.getConnectivityPath());
            List<Long> segmentIds = new ArrayList<>();
            for (NsxSegment nsxSegment : segments) {
                segmentIds.add(nsxSegment.getId());
            }
            // 路由器端口下所有路由器端口子网IP地址池下的已用IP
            if (!ListTool.isEmpty(segmentIds)) {
                List<IpPool> ipPools = ipPoolRepository.listBySegmentIds(segmentIds, version);
                for (IpPool pool : ipPools) {
                    List<Ip> ips = ipRepository.listByPool(pool.getId());
                    for (Ip ip : ips) {
                        map.put(ip.getIp(), ip.getIp());
                    }
                }
            }
            // 云平台已锁定的IP(手动在管理端添加)
            List<Ip> lockIps = ipRepository.listLockedIps();
            for (Ip ip : lockIps) {
                map.put(ip.getIp(), ip.getIp());
            }
            List<Ip> list = new ArrayList<>();
            List<Ip> reachableIps = new ArrayList<>();
            int index = 0;
            for (IpPool pool : pools) {
                List<String> poolList = JSONArray.parseArray(pool.getPools(), String.class);
                String dns = JSONArray.parseArray(pool.getDnsNames(), String.class).get(0);
                for (String ipPools : poolList) {
                    String[] startEndIp = ipPools.split("-");
                    IPAddress address = IPAddress.getIPAddress(startEndIp[0]);
                    BigInteger ipstart = address.ipToInteger(startEndIp[0]);// 获取起始IP的开始位置
                    BigInteger ipend = address.ipToInteger(startEndIp[1]);// 获取终止IP的结束位置
                    while (ipend.compareTo(ipstart) >= 0) {
                        String ipKey = address.integerToIp(ipstart);
                        if (!map.containsKey(ipKey)) {
                            Ip ip = new Ip(ipKey, address.getMask(pool.getCidr()), pool.getGateway(), dns,
                                    pool.getVendorId(), IDFactory.instance().uuid(), pool.getId(), IpStatus.used);
                            ip.setCatalog("VM");
                            list.add(ip);
                            index++;
                        }
                        if (index >= count) {
                            break;
                        }
                        ipstart = ipstart.add(new BigInteger("1"));
                    }
                    if (index >= count) {
                        break;
                    }
                }
                if (index >= count) {
                    break;
                }
            }
            if (list.isEmpty() || list.size() < count) {
                logger.info("分段{}下无可用IP", segment.getName());
                return new BocloudResult<>(false, "分段【" + segment.getName() + "】下无IP可分配!");
            }
            if (!ListTool.isEmpty(reachableIps)) {
                ipRepository.batchCreate(reachableIps);
            }
            if (!ListTool.isEmpty(list)) {
                ipRepository.batchCreate(list);
            }
            logger.info("从分段{}下子网获取到的IP地址：{}", segment.getName(), JSONObject.toJSON(list));
            Long end = System.currentTimeMillis();
            logger.info("分配nsx下IP地址耗时：{}毫秒", (end - start));
            return new BocloudResult<>(true, list, "success");
        } catch (Exception e) {
            logger.error("Achieve Ips failed:", e);
            return new BocloudResult<>(false, "获取IP失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult action(Long id, IpPatchParams.Action status, String remark, RequestContext context) {
        String path = Ip.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Ip ip = ipRepository.query(id);
            Assert.notNull(ip, "ip不存在");
            switch (status) {
                case lock:
                    ip.setStatus(IpStatus.lock);
                    ip.setCatalog(null);
                    ip.setRemark(remark);
                    ipRepository.update(ip);
                    return new BocloudResult<>(true, "编辑成功");
                case free:
                    ipRepository.makeFreeById(ip.getId());
                    return new BocloudResult<>(true, "释放成功");
                default:
                    return new BocloudResult<>(false, "暂不支持");
            }
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, "操作失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult batchUpdate(List<Long> ids, IpPatchParams.Action action, String remark, RequestContext context) {
        ArrayList<Ip> ips = new ArrayList<>();
        for (Long id : ids) {
            String path = Ip.class.getSimpleName() + "_" + id;
            try (BocloudACLock lock = lockFactory.getACLock(path)) {
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                Ip ip = ipRepository.query(id);
                Assert.notNull(ip, "ip不存在");
                switch (action) {
                    case lock:
                        ip.setStatus(IpStatus.lock);
                        ip.setCatalog(null);
                        ip.setRemark(remark);
                        ips.add(ip);
                        break;
                    case free:
                        ip.setCatalog(null);
                        ip.setTarget(null);
                        ip.setRemark(remark);
                        ip.setStatus(IpStatus.free);
                        ips.add(ip);
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
                logger.error("Get error message：{}", e.getMessage());
                return new BocloudResult<>(false, "操作失败：" + e.getMessage());
            }
        }
        if (!ips.isEmpty()) {
            ipRepository.batchUpdate(ips, ips.size());
        }
        return new BocloudResult<>(true, "操作成功。");
    }
}
