package com.bocloud.ims.service.builder;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.IpModel;
import com.bocloud.cmp.model.NetcardOperation;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.provider.utils.IPAddress;
import com.bocloud.common.encrypt.DESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.OperateResult.OperateCategory;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.common.enums.ServerAction;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.DataStore;
import com.bocloud.ims.entity.resource.Image;
import com.bocloud.ims.entity.resource.Ip;
import com.bocloud.ims.entity.resource.Ip.IpStatus;
import com.bocloud.ims.entity.resource.IpPool;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.NetworkCard;
import com.bocloud.ims.entity.resource.PortGroup;
import com.bocloud.ims.entity.resource.Resource;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerLabel;
import com.bocloud.ims.entity.resource.Switcher;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.DataStoreRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.IpPoolRepository;
import com.bocloud.ims.repository.resource.IpRepository;
import com.bocloud.ims.repository.resource.NetworkCardRepository;
import com.bocloud.ims.repository.resource.NetworkHostRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.PortGroupRepository;
import com.bocloud.ims.repository.resource.ResourceEventRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.ServerLabelRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.StoreHostRepository;
import com.bocloud.ims.repository.resource.SwitcherRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.internal.worker.LvmService;
import com.bocloud.ims.service.utils.PasswordGenerator;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.SyncVmwareUtils;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class VMServerBuilder implements ServerBuilder {

    private static OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    private static Logger logger = LoggerFactory.getLogger(VMServerBuilder.class);
    private CloudServerRepository cloudServerRepository;
    private ServerRepository serverRepository;
    private DataStoreRepository dataStoreRepository;
    private NetworkRepository networkRepository;
    private NetworkCardRepository networkCardRepository;
    private PortGroupRepository portGroupRepository;
    private SwitcherRepository switcherRepository;
    private StoreHostRepository storeHostRepository;
    private NetworkHostRepository networkHostRepository;
    private IpRepository ipRepository;
    private ResourceRepository resourceRepository;
    private ResourceEventRepository resourceEventRepository;
    private VolumeRepository volumeRepository;
    private ServerLabelRepository serverLabelRepository;
    private ServerDriver serverDriver;
    private ResourceEventPublisher resourceEventPublisher;
    private RequestContext context;
    private CloudVendor vendor;
    private ServerModel model;
    private IpPoolRepository ipPoolRepository;
    private SmsTenantService smsTenantService;
    private LockFactory lockFactory;
    private ImageRepository imageRepository;
    private SmsProjectService smsProjectService;
    private LvmService lvmService;
    private AmqpTemplate amqpTemplate;

    public VMServerBuilder(CloudServerRepository cloudServerRepository, ServerRepository serverRepository,
        DataStoreRepository dataStoreRepository, NetworkRepository networkRepository,
        NetworkCardRepository networkCardRepository, PortGroupRepository portGroupRepository,
        SwitcherRepository switcherRepository, StoreHostRepository storeHostRepository,
        NetworkHostRepository networkHostRepository, IpRepository ipRepository, ResourceRepository resourceRepository,
        ResourceEventRepository resourceEventRepository, VolumeRepository volumeRepository,
        ServerLabelRepository serverLabelRepository, ServerDriver serverDriver, RequestContext context,
        CloudVendor vendor, ResourceEventPublisher resourceEventPublisher, IpPoolRepository ipPoolRepository,
        SmsTenantService smsTenantService, LockFactory lockFactory, SmsProjectService smsProjectService,
        LvmService lvmService, AmqpTemplate amqpTemplate) {
        super();
        this.cloudServerRepository = cloudServerRepository;
        this.serverRepository = serverRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.networkRepository = networkRepository;
        this.networkCardRepository = networkCardRepository;
        this.portGroupRepository = portGroupRepository;
        this.switcherRepository = switcherRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkHostRepository = networkHostRepository;
        this.ipRepository = ipRepository;
        this.resourceRepository = resourceRepository;
        this.resourceEventRepository = resourceEventRepository;
        this.volumeRepository = volumeRepository;
        this.serverLabelRepository = serverLabelRepository;
        this.serverDriver = serverDriver;
        this.context = context;
        this.vendor = vendor;
        this.resourceEventPublisher = resourceEventPublisher;
        this.ipPoolRepository = ipPoolRepository;
        this.smsTenantService = smsTenantService;
        this.lockFactory = lockFactory;
        this.smsProjectService = smsProjectService;
        this.lvmService = lvmService;
        this.amqpTemplate = amqpTemplate;
    }

    public VMServerBuilder(CloudServerRepository cloudServerRepository, ServerRepository serverRepository,
        DataStoreRepository dataStoreRepository, NetworkRepository networkRepository,
        NetworkCardRepository networkCardRepository, PortGroupRepository portGroupRepository,
        SwitcherRepository switcherRepository, StoreHostRepository storeHostRepository,
        NetworkHostRepository networkHostRepository, IpRepository ipRepository, ResourceRepository resourceRepository,
        ResourceEventRepository resourceEventRepository, VolumeRepository volumeRepository,
        ServerLabelRepository serverLabelRepository, ServerDriver serverDriver, RequestContext context,
        CloudVendor vendor, ResourceEventPublisher resourceEventPublisher, IpPoolRepository ipPoolRepository,
        SmsTenantService smsTenantService, LockFactory lockFactory, ImageRepository imageRepository,
        SmsProjectService smsProjectService, LvmService lvmService, AmqpTemplate amqpTemplate) {
        super();
        this.cloudServerRepository = cloudServerRepository;
        this.serverRepository = serverRepository;
        this.dataStoreRepository = dataStoreRepository;
        this.networkRepository = networkRepository;
        this.networkCardRepository = networkCardRepository;
        this.portGroupRepository = portGroupRepository;
        this.switcherRepository = switcherRepository;
        this.storeHostRepository = storeHostRepository;
        this.networkHostRepository = networkHostRepository;
        this.ipRepository = ipRepository;
        this.resourceRepository = resourceRepository;
        this.resourceEventRepository = resourceEventRepository;
        this.volumeRepository = volumeRepository;
        this.serverLabelRepository = serverLabelRepository;
        this.serverDriver = serverDriver;
        this.context = context;
        this.vendor = vendor;
        this.resourceEventPublisher = resourceEventPublisher;
        this.ipPoolRepository = ipPoolRepository;
        this.smsTenantService = smsTenantService;
        this.lockFactory = lockFactory;
        this.imageRepository = imageRepository;
        this.smsProjectService = smsProjectService;
        this.lvmService = lvmService;
        this.amqpTemplate = amqpTemplate;
    }

    @Override
    public BocloudResult<ServerModel> prepare(JSONObject object) {
        List<NetcardOperation> operations =
            Optional.ofNullable(JSONObject.parseArray(object.getString("operations"), NetcardOperation.class))
                .orElse(new ArrayList<>());
        // 虚拟机每个网卡所包含的IP地址
        Map<String, IpModel> ipMap = Maps.newHashMap();
        for (NetcardOperation operation : operations) {
            if (null != operation.getIp()) {
                ipMap.put(operation.getIp().getIp(), operation.getIp());
            }
            if (null != operation.getIpv6()) {
                ipMap.put(operation.getIpv6().getIp(), operation.getIpv6());
            }
        }
        try {
            Server host = serverRepository.query(object.getLong("hostId"));
            if (null == host) {
                return new BocloudResult<>(false, "宿主机不存在");
            }
            DataStore store = dataStoreRepository.query(object.getLong("storeId"));
            if (null == store) {
                return new BocloudResult<>(false, "数据存储不存在");
            }
            CloudServer template = cloudServerRepository.query(object.getLong("templateId"));
            if (null == template) {
                return new BocloudResult<>(false, "模板不存在");
            }
            String name = object.getString("name");// 虚拟机名
            String remark = object.getString("remark");// 描述
            model = new ServerModel(name, remark);
            model.prepareData(object.getInteger("cpu"), object.getBigDecimal("memory"), object.getInteger("disk"),
                host.getName(), host.getClusterName(), host.getVdcName(), store.getName(), template.getName(),
                operations);
            String disks = object.getString("disks");
            if (!StringUtils.isEmpty(disks)) {
                model.setDisks(JSONArray.parseArray(disks, Integer.class));
            } else {
                model.setDisks(Lists.newArrayList());
            }
            if (object.containsKey("dataStoreNames")) {
                model.setDataStoreNames(object.getJSONArray("dataStoreNames").toJavaList(String.class));
            } else {
                model.setDataStoreNames(Lists.newArrayList());
            }
            if (object.containsKey("addDiskList")) {
                model.setAddDiskList(JSONArray.parseArray(object.getString("addDiskList"), JSONObject.class));
            } else {
                model.setAddDiskList(Lists.newArrayList());
            }
            // lvm参数用
            if (object.containsKey("dataDiskList")) {
                model.setDataDiskList(JSONArray.parseArray(object.getString("dataDiskList"), JSONObject.class));
            }
            // 存储路径(多级英文","拼接)
            if (object.containsKey("folderName")) {
                String folderName = object.getString("folderName");
                if (!folderName.isEmpty()) {
                    String parentVmFolder = "";
                    String vmFolder = "";
                    // 多级
                    if (folderName.contains(",")) {
                        parentVmFolder = folderName.substring(0, folderName.indexOf(","));
                        vmFolder = folderName.substring(folderName.indexOf(",") + 1);
                    }
                    // 单级
                    if (parentVmFolder.isEmpty()) {
                        model.setParentVmFolder(null);
                        model.setVmFolder(folderName);
                    } else {// 多级
                        model.setParentVmFolder(parentVmFolder);
                        model.setVmFolder(vmFolder);
                    }
                }
            }
            // 实例ID
            model.setTempInstId(template.getInstanceId());
            // 数据中心ID
            model.setVdcId(host.getVdcId());
            // 宿主机ID
            model.setHostId(host.getId());
            model.setPassword(object.getString("password"));
            model.setVmHostName(object.getString("vmHostName"));
            model.setTemplatePasswd(template.receivePswd());
            model.setResourceLabel(object.getString("resourceLabel"));
            // 磁盘格式
            model.setDiskType(object.getString("diskType"));
            // 存储策略适配
            model.setProfileId(object.getString("profileId"));
            // 设置vapp
            model.setVappName(object.getString("vappName"));
            model.setVappId(object.getLong("vappId"));
            // 虚拟机标签
            if (!StringUtils.isEmpty(object.getString("labelIds"))) {
                List<Long> labelIds = JSONArray.parseArray(object.getString("labelIds"), Long.class);
                model.setLabelIds(labelIds);
            }
            if (!StringUtils.isEmpty(object.getString("rdmDisks"))) {
                List<JSONObject> rdmDisks = JSONArray.parseArray(object.getString("rdmDisks"), JSONObject.class);
                model.setRdmDisks(rdmDisks);
            }
            return new BocloudResult<>(true, model, "success");
        } catch (Exception e) {
            // 回收IP
            for (Entry<String, IpModel> entry : ipMap.entrySet()) {
                IpModel ip = entry.getValue();
                ipRepository.makeFreeById(ip.getId());
            }
            logger.error("Get error Message:", e);
            return new BocloudResult<>(false, "fail");
        }
    }

    /**
     * 分配虚拟机文件夹
     */
    private BocloudResult assignVmFolder() {
        if (null == context.getTenant() || 0L == context.getTenant()) {
            return new BocloudResult(true, "success");
        }
        // 设置虚拟机文件夹
        BocloudResult<Tenant> tenantResult = smsTenantService.detail(context.getTenant());
        if (tenantResult.isFailed() || null == tenantResult.getData()) {
            return new BocloudResult(false, tenantResult.getMessage());
        }
        Tenant tenant = tenantResult.getData();
        String tenantName = tenant.getName().trim();
        logger.info("查找租户文件夹：{}", tenantName);
        String path = CloudServer.class.getSimpleName() + "_vmfolder_" + tenantName;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(5, TimeUnit.MINUTES), "获取虚拟机文件夹请求超时");
            Long start = System.currentTimeMillis();
            BocloudResult result = serverDriver.getVmFolder(vendor.getUuid(), tenantName, model.getVdcName());
            if (result.isFailed()) {
                return new BocloudResult(false, result.getMessage());
            }
            if (null != context.getProject() && 0L != context.getProject()) {
                BocloudResult<Project> projectResult = smsProjectService.detail(context.getProject());
                if (projectResult.isFailed() || null == projectResult.getData()) {
                    return new BocloudResult(false, projectResult.getMessage());
                }
                Project project = projectResult.getData();
                logger.info("查找项目文件夹：{}", project.getName());
                result = serverDriver.getVmFolder(vendor.getUuid(), tenantName, project.getName().trim(),
                    model.getVdcName());
                if (result.isFailed()) {
                    return new BocloudResult(false, result.getMessage());
                }
            }
            model.setParentVmFolder(tenantName);
            model.setVmFolder(String.valueOf(result.getData()));
            logger.info("寻找或创建虚拟机文件夹耗时：{}毫秒", System.currentTimeMillis() - start);
            return new BocloudResult(true, "success");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<CloudServer> builder(CloudServer cloudServer) {
        // 创建虚拟机
        BocloudResult result = null;
        List<NetcardOperation> operations = model.getOperations();
        // 虚拟机每个网卡所包含的IP地址
        Map<String, Ip> ipMap = Maps.newHashMap();
        List<String> ipList = new ArrayList<>();
        for (NetcardOperation operation : operations) {
            if (null != operation.getIp()) {
                ipMap.put(operation.getIp().getIp(),
                    JSONObject.parseObject(JSONObject.toJSONString(operation.getIp()), Ip.class));
                ipList.add(operation.getIp().getIp());
            }
            if (null != operation.getIpv6()) {
                ipMap.put(operation.getIpv6().getIp(),
                    JSONObject.parseObject(JSONObject.toJSONString(operation.getIpv6()), Ip.class));
            }
        }
        List<Ip> recycleIps = new ArrayList<>(ipMap.values());
        try {
            // 操作记录
            Long userId = context.getTarget();
            String handler = "虚拟机创建";
            ResourceEvent event = null;
            BocloudResult folderResult = this.assignVmFolder();
            if (folderResult.isFailed()) {
                event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
                resourceEventRepository.save(event);
                cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
                return new BocloudResult<>(false, folderResult.getMessage());
            }
            model.setVendorVersion(vendor.getVersion());
            // 修改vcenter虚拟机密码需要启用vmware tools
            String password = model.getPassword();
            if (StringUtils.isEmpty(password)) {
                // 生成随机密码
                password = new PasswordGenerator(10, 4).generateRandomPassword();
                cloudServer.setPswd(password);
            }
            model.setPassword(password);
            // 创建虚拟机
            result = serverDriver.create(vendor.getUuid(), null, model);
            if (result.isSuccess()) {
                event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
                String content = JSONObject.toJSONString(result.getData());
                CloudServer server = JSONObject.parseObject(content, CloudServer.class);
                List<Volume> diskDevices = server.getDiskDevices();
                if (!ListTool.isEmpty(diskDevices)) {
                    for (Volume disk : diskDevices) {
                        disk.preSave(userId, userId, 0L, vendor.getId());
                        disk.setServerId(cloudServer.getId());
                        disk.setCatalog(context.getCatalog());
                        disk.setProjectId(context.getProject());
                        disk.setTenantId(context.getTenant());
                        String device = disk.getDevice();
                        if(StringUtils.isEmpty(device)) {
                        	disk.setDevice(getDevice(disk));
                        }
                        volumeRepository.save(disk);
                    }
                }
                cloudServer.setVappId(model.getVappId());
                cloudServer.setInstanceId(server.getInstanceId());
                cloudServer.setUuid(server.getUuid());
                cloudServer.setToolsInstalled(null != server.getToolsInstalled() && server.getToolsInstalled());
                cloudServer.setToolsRunning(null != server.getToolsRunning() && server.getToolsRunning());
                cloudServer.setDatastores(server.getDatastores());
                cloudServer.setGmtVmCreate(server.getGmtVmCreate());
                cloudServer.setOsCategory(server.getOsCategory());
                cloudServer.setOsName(server.getOsName());
                cloudServer.setManagerIp(server.getManagerIp());
                cloudServer.setCpu(server.getCpu());
                cloudServer.setMemory(server.getMemory());
                cloudServer.setDisk(server.getDisk());
                cloudServer.setCpuHotEnable(server.getCpuHotEnable());
                cloudServer.setMemHotEnable(server.getMemHotEnable());
                cloudServer.setProps(model.getProps());
                cloudServer.setBiosUuid(server.getBiosUuid());
                // 宿主机ID
                cloudServer.setHostId(model.getHostId());
                // 宿主机名称
                cloudServer.setHostName(model.getHostName());

                String state = server.getStatus();
                if ("poweredOn".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
                } else if ("poweredOff".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
                } else if ("suspended".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.SUSPENDED.name());
                } else {
                    cloudServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
                }
                cloudServerRepository.update(cloudServer);
                // 保存标签信息
                List<Long> labelIds = model.getLabelIds();
                if (!ListTool.isEmpty(labelIds)) {
                    List<ServerLabel> serverLabels = Lists.newArrayList();
                    for (Long labelId : labelIds) {
                        serverLabels.add(new ServerLabel(cloudServer.getId(), labelId, "VM", vendor.getId()));
                    }
                    if (!ListTool.isEmpty(serverLabels)) {
                        serverLabelRepository.batchSave(serverLabels);
                    }
                }
                ServerModel finalModel = model;
                final String finalPasswd = password;
                // 宿主机
                Server host = serverRepository.query(model.getHostId());
                // 同步新虚拟机下个对象信息
                syncSubObject(server, host.getVdcId(), vendor.getId(), cloudServer.getId(), server.getStores(),
                    server.getNetworks(), server.getNetcards(), context.getTarget());
                // // 开启一个线程去获取IP地址(已安装vmware tools的虚拟机)
                // if (null != context.getTenant() && 0L != context.getTenant()) {
                //
                // } else {
                // new Thread(() -> {
                // waitTask(cloudServer, server, ipList, ipMap, userId, finalModel, finalPasswd);
                // }).start();
                // }
                waitTask(cloudServer, server, ipList, ipMap, userId, finalModel, finalPasswd);
                // 新加的数据盘,由于前段参数未统一，暂时做容错处理
                List<JSONObject> diskList = model.getDataDiskList();
                if (ListTool.isEmpty(diskList)) {
                    diskList = model.getAddDiskList();
                }
                if (!ListTool.isEmpty(diskList)) {
                    // 执行lvm创建任务
                    BocloudResult lvmResult = lvmService.lvmCreate(cloudServer, vendor, diskList,
                        volumeRepository.listDataDisks(cloudServer.getId()), context);
                    if (lvmResult.isFailed()) {
                        BocloudResult bocloudResult = serverDriver.remove(cloudServer.getInstanceId(),
                            cloudServer.getName(), vendor.getUuid(), null);
                        if (bocloudResult.isSuccess()) {
                            // 回收IP
                            for (Ip ip : recycleIps) {
                                ipRepository.makeFreeById(ip.getId());
                            }
                            cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                            volumeRepository.removeByServerId(cloudServer.getId(), context.getTarget());
                            serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
                            event = new ResourceEvent(cloudServer.getId(), ServerAction.LVMCREATE.name(), "失败", userId,
                                new Date(), "VM", vendor.getId(), context.getCatalog());
                            resourceEventRepository.save(event);
                        }
                        return new BocloudResult<>(false, cloudServer, "虚拟机创建失败，创建LVM发生错误");
                    }
                }
                // 加入到堡垒机
                if (null != cloudServer.getIsAddShterm() && cloudServer.getIsAddShterm()) {
                    addShterm(cloudServer, model.getPassword());
                }
            } else {
                // 回收IP
                for (Ip ip : recycleIps) {
                    ipRepository.makeFreeById(ip.getId());
                }
                event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
                cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
            }
            resourceEventRepository.save(event);
        } catch (Exception e) {
            // 回收IP
            for (Ip ip : recycleIps) {
                ipRepository.makeFreeById(ip.getId());
            }
            cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
            serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
            logger.error("Get error Message:", e);
            return new BocloudResult<>(false, cloudServer, "create fail");
        }
        return result.isSuccess() ? new BocloudResult<>(true, cloudServer, "虚拟机创建成功")
            : new BocloudResult<>(false, cloudServer, result.getMessage());
    }

    private String getDevice(Volume disk) {
    	String device = "";
		try {
			String name = disk.getName();
			if(!StringUtils.isEmpty(name)) {
				name = name.substring(name.length() - 2, name.length());
				device = "/dev/sd" + (char) (Integer.parseInt(name.trim()) + 96);
			}
		} catch(Exception e) {
			logger.error("获取挂载点异常：" + e.getMessage());
		}
		return device;
	}
    
	/**
     * @param ipList
     * @return void
     * @Author: lxy
     * @Description: 把虚拟机加进平台纳管的堡垒机 -- 发送数据到mq
     * @Date 2021/5/13 21:17
     * @Param cloudServer
     * @throws:
     **/
    private void addShterm(CloudServer cloudServer, String password) {
        Encryptor encryptor = new DESEncrptor();
        if (null != cloudServer.getPrivateIps()) {

            List<JSONObject> ips = JSON.parseArray(cloudServer.getPrivateIps(), JSONObject.class);
            ips.stream().filter(json -> json.containsKey("address") && null != json.get("address"))
                .collect(Collectors.toList());
            for (JSONObject json : ips) {
                JSONObject jsonObject = new JSONObject();
                String type =
                    cloudServer.getOsCategory().equalsIgnoreCase("LINUX") ? cloudServer.getOsCategory() : "WINDOWS";
                String username = cloudServer.getOsCategory().equalsIgnoreCase("LINUX") ? "root" : "administrator";
                String passwordDes = encryptor.encrypt(password.trim(), "BocloudCMP");
                jsonObject.put("name", cloudServer.getName());
                jsonObject.put("password", passwordDes);
                jsonObject.put("privateIps", json.get("address"));
                jsonObject.put("username", username);
                jsonObject.put("type", type);
                logger.info("vmware name is : {} , pwd is : {} , pwdDes is : {}", cloudServer.getName(),
                    password.trim(), passwordDes);
                amqpTemplate.convertAndSend("sync.shterm.queue", jsonObject);
                logger.info("send rabbitmq topic is : {} success ，message is ：{}", "sync.shterm.queue",
                    jsonObject.toJSONString());
            }
        }
    }

    /**
     * 等待任务执行结果
     *
     * @param cloudServer
     * @param server
     * @param ipList
     * @param ipMap
     * @param userId
     * @param finalModel
     * @param finalPasswd
     */
    private void waitTask(CloudServer cloudServer, CloudServer server, List<String> ipList, Map<String, Ip> ipMap,
        Long userId, ServerModel finalModel, String finalPasswd) {
        String operate = vendor.getType().toLowerCase() + ".vm";
        String message = "虚拟机【" + cloudServer.getName() + "】获取IP地址失败";
        try {
            if (!StringUtils.isEmpty(model.getVappName())) {
                cloudServer.setAccount(finalModel.getAccount());
                cloudServer.setPswd(finalModel.getTemplatePasswd());
                cloudServer.setMenderId(context.getTarget());
                cloudServerRepository.update(cloudServer);
            } else {
                BocloudResult result1 = serverDriver.getVmIps(server.getInstanceId(), ipList.get(0), vendor.getUuid());
                if (result1.isSuccess()) {
                    ServerModel model =
                        JSONObject.parseObject(JSONObject.toJSONString(result1.getData()), ServerModel.class);
                    cloudServer.setPrivateIps(model.getPrivateIps());
                    // 是否安装了vmware tools
                    cloudServer.setToolsInstalled(true);
                    // 是否运行了vmware tools
                    cloudServer.setToolsRunning(true);
                    message = "虚拟机【" + cloudServer.getName() + "】获取IP地址成功";
                    if (null != context.getCatalog()) {
                        resourceEventPublisher.send(new OperateResult(true, message, operate,
                            MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                    }
                    if (!StringUtils.isEmpty(model.getPrivateIps())) {
                        List<JSONObject> objects = JSONObject.parseArray(model.getPrivateIps(), JSONObject.class);
                        for (JSONObject object : objects) {
                            String address = object.getString("address");
                            if (StringUtils.isEmpty(address)) {
                                continue;
                            }
                            if (ipMap.containsKey(address)) {
                                Ip ip = ipMap.get(address);
                                ip.setCatalog("VM");
                                ip.setTarget(cloudServer.getId());
                                ip.setVendorId(cloudServer.getVendorId());
                                ip.setStatus(IpStatus.used);
                                ipRepository.update(ip);
                                ipMap.remove(address);
                            } else {
                                // 处理IP
                                List<IpPool> pools = ipPoolRepository.listByIpVersion(null);
                                Ip ip = ipRepository.checkExist(address, null, vendor.getId());
                                if (null == ip) {
                                    ip = new Ip(address, null, null, null, vendor.getId(), IDFactory.instance().uuid(),
                                        null, IpStatus.used);
                                    ip.setCatalog("VM");
                                    ip.setTarget(cloudServer.getId());
                                    for (IpPool pool : pools) {
                                        String dns = null;
                                        if (!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(cloudServer.getId());
                                    ip.setStatus(IpStatus.used);
                                    ip.setCatalog("VM");
                                    ip.setVendorId(vendor.getId());
                                    ipRepository.update(ip);
                                }
                            }
                        }
                        // 回收IP
                        for (Entry<String, Ip> entry : ipMap.entrySet()) {
                            ipRepository.makeFreeById(entry.getValue().getId());
                        }
                    }
                    // 保存资源
                    List<String> ips = Lists.newArrayList();
                    if (!StringUtils.isEmpty(model.getPrivateIps())) {
                        List<JSONObject> objects = JSONObject.parseArray(model.getPrivateIps(), JSONObject.class);
                        for (JSONObject object : objects) {
                            if (StringUtils.isEmpty(object.getString("address"))) {
                                continue;
                            }
                            ips.add(object.getString("address"));
                        }
                    }
                    if (!ListTool.isEmpty(ips)) {
                        cloudServer.setManagerIp(ips.get(0));
                    }
                    cloudServerRepository.update(cloudServer);
                    Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                        ResourceCatalog.LOGICAL.name(), cloudServer.getId());
                    if (null == resource) {
                        resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                            cloudServer.getId(), JSONObject.toJSONString(ips), cloudServer.getOsCategory(),
                            vendor.getId());
                        resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant());
                        resource.setInventory(JSONObject.toJSONString(cloudServer));
                        resourceRepository.save(resource);
                    } else {
                        resource.setInventory(JSONObject.toJSONString(cloudServer));
                        resource.setStatus(cloudServer.getStatus());
                        resource.setMenderId(userId);
                        resource.setCreatorId(userId);
                        resource.setGmtModify(new Date());
                        resource.setGmtCreate(new Date());
                        resource.setPrivateIps(JSONObject.toJSONString(ips));
                        resourceRepository.update(resource);
                    }

                    // 模板的密码
                    String templatePasswd = finalModel.getTemplatePasswd();
                    if (!StringUtils.isEmpty(templatePasswd)) {
                        BocloudResult bocloudResult = serverDriver.initVspVmPasswd(server.getInstanceId(),
                            templatePasswd, finalPasswd, vendor.getUuid());
                        if (bocloudResult.isSuccess() && null != bocloudResult.getData()) {
                            ServerModel serverModel = JSONObject
                                .parseObject(JSONObject.toJSONString(bocloudResult.getData()), ServerModel.class);
                            cloudServer.setAccount(serverModel.getAccount());
                            cloudServer.setPswd(serverModel.getPassword());
                            cloudServer.setMenderId(context.getTarget());
                            cloudServerRepository.update(cloudServer);
                        }
                    }
                } else {
                    // 回收IP
                    for (Entry<String, Ip> entry : ipMap.entrySet()) {
                        ipRepository.makeFreeById(entry.getValue().getId());
                    }
                    resourceEventPublisher.send(new OperateResult(false, message, operate,
                        MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
                }
            }
        } catch (Exception e) {
            logger.error("Get error message:", e);
            resourceEventPublisher.send(new OperateResult(false, message, operate,
                MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
        }
    }

    @Override
    public BocloudResult<CloudServer> builderAsTemplate(CloudServer cloudServer) throws Exception {
        BocloudResult folderResult = this.assignVmFolder();
        if (folderResult.isFailed()) {
            return new BocloudResult<>(false, folderResult.getMessage());
        }
        // 创建虚拟机
        BocloudResult result = null;
        try {
            // 创建虚拟机
            result = serverDriver.cloneAsTemplate(vendor.getUuid(), null, model);
            // 操作记录
            Long userId = context.getTarget();
            String handler = ServerAction.CREATE.name();
            ResourceEvent event = null;
            if (result.isSuccess()) {
                event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
                String content = JSONObject.toJSONString(result.getData());
                CloudServer server = JSONObject.parseObject(content, CloudServer.class);
                List<Volume> diskDevices = server.getDiskDevices();
                if (!ListTool.isEmpty(diskDevices)) {
                    for (Volume disk : diskDevices) {
                        disk.preSave(userId, userId, 0L, vendor.getId());
                        disk.setServerId(cloudServer.getId());
                        disk.setVolumeUuid(IDFactory.instance().uuid());
                        disk.setCatalog(context.getCatalog());
                        disk.setProjectId(context.getProject());
                        disk.setTenantId(context.getTenant());
                        volumeRepository.save(disk);
                    }
                }
                cloudServer.setIsTemplate(true);
                cloudServer.setInstanceId(server.getInstanceId());
                cloudServer.setUuid(server.getUuid());
                cloudServer.setToolsInstalled(null == server.getToolsInstalled() ? false : server.getToolsInstalled());
                cloudServer.setToolsRunning(null == server.getToolsRunning() ? false : server.getToolsRunning());
                cloudServer.setDatastores(server.getDatastores());
                cloudServer.setGmtVmCreate(server.getGmtVmCreate());
                cloudServer.setOsCategory(server.getOsCategory());
                cloudServer.setOsName(server.getOsName());
                cloudServer.setCpu(server.getCpu());
                cloudServer.setMemory(server.getMemory());
                cloudServer.setDisk(server.getDisk());
                cloudServer.setCpuHotEnable(server.getCpuHotEnable());
                cloudServer.setMemHotEnable(server.getMemHotEnable());
                cloudServer.setProps(model.getProps());
                cloudServer.setHostId(model.getHostId());
                cloudServer.setHostName(model.getHostName());
                String state = server.getStatus();
                if ("poweredOn".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
                } else if ("poweredOff".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
                } else if ("suspended".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.SUSPENDED.name());
                } else {
                    cloudServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
                }
                cloudServerRepository.update(cloudServer);
                // 宿主机
                Server host = serverRepository.query(model.getHostId());
                // 同步新虚拟机下个对象信息
                syncSubObject(server, host.getVdcId(), vendor.getId(), cloudServer.getId(), server.getStores(),
                    server.getNetworks(), server.getNetcards(), context.getTarget());
                Image image = new Image();
                image.setName(cloudServer.getName());
                image.setStatus("ACTIVE");
                image.setTemplateId(cloudServer.getId());
                image.setSize(cloudServer.getDisk().doubleValue());
                image.setVendorType(vendor.getType());
                image.setImageUuid(cloudServer.getInstanceId());
                image.preSave(context.getTarget(), context.getTarget(), vendor.getId(), 0L, 0L);
                image.setCatalog("VM");
                image.setOsCategory(cloudServer.getOsCategory());
                image.setOsName(cloudServer.getOsName());
                imageRepository.save(image);
            } else {
                event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
                cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                serverLabelRepository.deleteByTarget(cloudServer.getId(), "VM");
            }
            resourceEventRepository.save(event);
            return result.isSuccess() ? new BocloudResult<>(true, cloudServer, "虚拟机克隆模板成功")
                : new BocloudResult<>(false, cloudServer, result.getMessage());
        } catch (Exception e) {
            logger.error("Get error Message：{}", e.getMessage());
            return new BocloudResult<>(false, cloudServer, e.getMessage());
        }
    }

    /**
     * 同步新虚拟机下的各对象信息
     *
     * @param cloudServer
     * @param vdcId
     * @param vendorId
     * @param serverId
     * @param datastores
     * @param networks
     * @param cards
     * @param userId
     * @throws Exception
     */
    private void syncSubObject(CloudServer cloudServer, Long vdcId, Long vendorId, Long serverId,
        List<String> datastores, List<Network> networks, List<NetworkCard> cards, Long userId) throws Exception {
        // 数据中心的存储信息
        Map<String, DataStore> storeMap = new HashMap<>();
        List<DataStore> stores = dataStoreRepository.listByVdc(vdcId);
        for (DataStore store : stores) {
            storeMap.put(store.getStoreVal(), store);
        }
        // 数据中心的网络信息
        Map<String, Network> networkMap = Maps.newHashMap();
        Map<String, String> groupMap = Maps.newHashMap();
        List<Network> oldNetworks = networkRepository.listByVdc(vdcId);
        for (Network network : oldNetworks) {
            networkMap.put(network.getNetworkVal(), network);
        }
        List<Switcher> switchers = switcherRepository.listByVdc(vdcId, "DVSWITCH");
        for (Switcher switcher : switchers) {
            List<PortGroup> groups = portGroupRepository.listBySwitcher(switcher.getId());
            for (PortGroup group : groups) {
                groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
            }
        }
        SyncVmwareUtils utils = new SyncVmwareUtils(dataStoreRepository, serverRepository, networkRepository,
            storeHostRepository, networkCardRepository, portGroupRepository, networkHostRepository);
        // 同步存储
        logger.info("Start to sync store......");
        utils.addStore(vendorId, serverId, userId, "VM", datastores, storeMap);
        logger.info("End to sync store......");
        // 同步网络
        logger.info("Start to sync network......");
        utils.addNetwork(vendorId, serverId, userId, "VM", networks, networkMap, groupMap);
        logger.info("End to sync network......");
        // 同步网卡
        logger.info("Start to sync network card......");
        utils.addCard(vendorId, serverId, userId, "VM", cards, Maps.newHashMap());
        logger.info("End to sync network card......");
    }

    /**
     * @param server
     * @param templatePasswd
     * @param password
     * @return
     */
    @SuppressWarnings("unused")
    private BocloudResult waitForChangePasswd(CloudServer server, String templatePasswd, String password) {
        BocloudResult result = new BocloudResult(false, "密码修改失败");
        try {
            Long startTime = System.currentTimeMillis();
            Long endTime = System.currentTimeMillis();
            // 轮询10分钟
            while (endTime - startTime < 10 * 60 * 1000) {
                // 主机vmware tools启动时间不确定，增加休眠减少轮询次数
                Thread.sleep(10 * 1000);
                result =
                    serverDriver.changeVspVmPasswd(server.getInstanceId(), templatePasswd, password, vendor.getUuid());
                if (result.isSuccess()) {
                    break;
                }
                endTime = System.currentTimeMillis();
            }
        } catch (Exception e) {
            logger.error("VCenter vm password change fail：{}", e.getMessage());
            result = new BocloudResult(false, "密码修改失败");
        }
        return result;
    }

}
