package com.bocloud.ims.service.resource.server;

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

import com.bocloud.ims.service.task.ResourceTaskNotice;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.LocationDriver;
import com.bocloud.cmp.driver.hmc.HmcCommonDriver;
import com.bocloud.cmp.driver.hmc.HmcServerDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.hmc.SyncModel;
import com.bocloud.cmp.model.hmc.sdk.module.AssociatedIPLConfiguration;
import com.bocloud.cmp.model.hmc.sdk.module.ManagedSystem;
import com.bocloud.cmp.model.hmc.sdk.module.ManagedSystemEntry;
import com.bocloud.cmp.model.hmc.sdk.module.ManagedSystemResponse;
import com.bocloud.cmp.model.hmc.sdk.module.PendingPowerOnLogicalPartitionStartPolicy;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.common.Constant;
import com.bocloud.ims.common.enums.HmcJobType;
import com.bocloud.ims.common.enums.HmcServerStatus;
import com.bocloud.ims.common.enums.HmcStatus;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.hmc.HmcIoAdapter;
import com.bocloud.ims.entity.resource.hmc.HmcIplConfig;
import com.bocloud.ims.entity.resource.hmc.HmcPartition;
import com.bocloud.ims.entity.resource.hmc.HmcServer;
import com.bocloud.ims.entity.resource.hmc.HmcSystemCapability;
import com.bocloud.ims.entity.resource.hmc.HmcSystemMemoryConfig;
import com.bocloud.ims.entity.resource.hmc.HmcSystemProcessorConfig;
import com.bocloud.ims.entity.resource.hmc.HmcSystemSharedProcessorPool;
import com.bocloud.ims.entity.resource.hmc.params.HmcServerCreateParams;
import com.bocloud.ims.entity.resource.hmc.params.HmcServerUpdateParams;
import com.bocloud.ims.interfaces.resource.ServerService;
import com.bocloud.ims.interfaces.resource.SyncService;
import com.bocloud.ims.interfaces.resource.hmc.HmcNimService;
import com.bocloud.ims.interfaces.resource.hmc.HmcPartitionService;
import com.bocloud.ims.interfaces.resource.hmc.HmcServerService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.hmc.HmcIoAdapterRepository;
import com.bocloud.ims.repository.resource.hmc.HmcIplConfigRepository;
import com.bocloud.ims.repository.resource.hmc.HmcPartitionRepository;
import com.bocloud.ims.repository.resource.hmc.HmcServerRepository;
import com.bocloud.ims.repository.resource.hmc.HmcSystemCapabilityRepository;
import com.bocloud.ims.repository.resource.hmc.HmcSystemMemoryConfigRepository;
import com.bocloud.ims.repository.resource.hmc.HmcSystemProcessorConfigRepository;
import com.bocloud.ims.repository.resource.hmc.HmcSystemSharedProcessorPoolRepository;
import com.bocloud.ims.repository.resource.hmc.HmcVirtualSwitchRepository;
import com.bocloud.ims.service.resource.hmc.HmcDatabaseHelper;
import com.bocloud.ims.service.transporter.vendor.HmcTransporter;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;

/**
 * HMC服务器服务
 *
 * @author sxp
 * @since May 22, 2018
 */
@Service("hmcServerService")
public class HmcServerServiceImpl extends ServerServiceImpl implements HmcServerService, ServerService {
    private static Logger logger = LoggerFactory.getLogger(HmcServerServiceImpl.class);
    private static final String OPERATE_RESULT_TYPE = "hmc.sync";
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private LocationDriver locationDriver;
    @Autowired
    private HmcCommonDriver commonDriver;
    @Autowired
    private HmcServerDriver serverDriver;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private HmcServerRepository hmcServerRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private HmcSystemCapabilityRepository capabilityRepository;
    @Autowired
    private HmcSystemProcessorConfigRepository processorConfigRepository;
    @Autowired
    private HmcSystemMemoryConfigRepository memoryConfigRepository;
    @Autowired
    private HmcIoAdapterRepository ioAdapterRepository;
    @Autowired
    private HmcIplConfigRepository iplConfigRepository;
    @Autowired
    private HmcPartitionService hmcPartitionService;
    @Autowired
    private HmcPartitionRepository hmcPartitionRepository;
    @Autowired
    private HmcSystemCapabilityRepository hmcSystemCapabilityRepository;
    @Autowired
    private HmcSystemMemoryConfigRepository hmcSystemMemoryConfigRepository;
    @Autowired
    private HmcSystemProcessorConfigRepository hmcSystemProcessorConfigRepository;
    @Autowired
    private HmcDatabaseHelper hmcDatabaseHelper;
    @Autowired
    private HmcVirtualSwitchRepository hmcVirtualSwitchRepository;
    @Autowired
    private HmcTransporter hmcTransporter;
    @Autowired
    private SyncService syncService;
    @Autowired
    private HmcNimService nimService;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private HmcSystemSharedProcessorPoolRepository sharedProcessorPoolRepository;
    @Autowired
    @Qualifier("ServerService")
    private ServerService serverService;
    @Autowired
    private ResourceTaskNotice resourceTaskNotice;

    /**
     * hmc平台新增受管系统
     *
     * @author sxp
     * @since Jun 19, 2018
     */
    @Override
    public BocloudResult create(HmcServerCreateParams params, RequestContext context) {
        try {
            Long vendorId = params.getVendorId();
            String hostIp = params.getHostIp();
            String password = params.getPassword();

            if (vendorId == null) {
                return new BocloudResult(false, "新增失败：云平台唯一标识不能为空");
            }
            if (StringUtils.isEmpty(hostIp)) {
                return new BocloudResult(false, "新增失败：受管服务器的IP地址不能为空");
            }
            if (StringUtils.isEmpty(password)) {
                return new BocloudResult(false, "新增失败：连接密码不能为空");
            }
            if (hmcServerRepository.serverHostIsExisted(hostIp, vendorId)) {
                return new BocloudResult(false, "新增失败：这个服务器已经添加了");
            }

            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + vendorId + "]的云平台不存在");
            }

            BocloudResult result = serverDriver.queryManagementConsoleUuid(vendor.getUuid());
            if (result.isFailed()) {
                return result;
            }
            String consoleUuid = (String) result.getData();

            result = serverDriver.addManagedSystem(vendor.getUuid(), consoleUuid, hostIp, password);
            if (result.isFailed()) {
                return result;
            }

            JSONObject jobJson = (JSONObject) result.getData();
            String jobId = jobJson.getString(Constant.HMC_JOB_ID);
            if (StringUtils.isEmpty(jobId)) {
                return new BocloudResult(false, "新增失败：生成的任务ID是空");
            }

            String description = "向HMC平台新增服务器[" + hostIp + "]";
            HmcServer server = new HmcServer();
            server.setPrimaryIpAddress(hostIp);
            server.setName(hostIp);
            server.preSave(context.getTarget(), context.getTarget(), vendorId);

            server.setStatus(HmcStatus.SERVER.CREATING.getName());
            hmcServerRepository.save(server);
            // asynGetJobStatus(server, driver, jobId, description, userId,
            // HmcJobType.AddManagedSystem);

            // 启动一个线程去添加一个新的服务器
            taskExecutor.submit(() -> {
                logger.info("{}的jobId为{}", description, jobId);
                Object data = MapTools.simpleMap("vendorId", server.getVendorId());
                OperateResult operateResult = new OperateResult(true, "success", OPERATE_RESULT_TYPE, data,
                        OperateResult.OperateCategory.ResourceEvent, context);

                try {
                    BocloudResult statusResult = commonDriver.getJobStatus(vendor.getUuid(), jobId);

                    String uuid = null;
                    if (statusResult.isFailed()) {
                        // 执行添加任务的Job失败, 清除这个服务器
                        operateResult.setSuccess(false);
                        operateResult.setMessage(description + ":" + statusResult.getMessage());
                        hmcServerRepository.remove(server.getId(), context.getTarget());
                        resourceEventPublisher.send(operateResult);
                        return;
                    }

                    // 获取这个服务器的状态，以确定是否添加成功
                    int time = 0;
                    while (time < 6) {
                        // 去获取这个服务器的uuid
                        uuid = getServerUuid(vendor.getUuid(), server.getPrimaryIpAddress());
                        if (null == uuid) {
                            TimeUnit.SECONDS.sleep(10);
                            time += 1;
                            continue;
                        }

                        // 这个服务的uuid会变，如果无法取得服务器状态，再去重新取一下uuid
                        BocloudResult bocloudResult = serverDriver.queryManagedSystemState(vendor.getUuid(), uuid);
                        if (bocloudResult.isFailed()) {
                            continue;
                        }
                        // check server status.
                        String status = (String) bocloudResult.getData();
                        if ("failed authentication".equals(status)) {
                            logger.error("the added server is incorrectly password");
                            operateResult.setSuccess(false);
                            operateResult.setMessage(description + ":密码不正确");
                            // 从db和hmc上清除这个服务器
                            server.setUuid(uuid);
                            cleanServer(server, vendor.getUuid(), context);
                            resourceEventPublisher.send(operateResult);
                            return;
                        } else if ("operating".equals(status)) {
                            logger.info("the server is added successful");
                            break;
                        }
                        logger.info("the server {} is connecting", uuid);
                        TimeUnit.SECONDS.sleep(10);
                        time += 1;
                    }

                    if (null == uuid) {
                        operateResult.setSuccess(false);
                        operateResult.setMessage(description + ":添加失败");
                        hmcServerRepository.remove(server.getId(), context.getTarget());
                        resourceEventPublisher.send(operateResult);
                        return;
                    }

                    // 更新服务的属性
                    BocloudResult bocloudResult = serverDriver.queryManagedSystemAttribute(vendor.getUuid(), uuid);
                    ManagedSystemEntry entry = (ManagedSystemEntry) bocloudResult.getData();
                    hmcDatabaseHelper.updateHmcServerEntity(server, entry);
                    hmcServerRepository.update(server);

                    // 如果依然没有连接上，请用户检查ip是否正确
                    if ("no connection".equals(server.getStatus())) {
                        operateResult.setSuccess(false);
                        operateResult.setMessage(description + ":无法连接，请检查IP地址是否正确！");
                    } else {
                        // 同步这个服务器下的分区信息, TODO: 目前还是整体同步，以后要改更新只同步这个服务器数据
                        // result = updateAndSyncServer(server, userId);
                        syncService.sync(server.getVendorId(), context, false);
                        if (bocloudResult.isSuccess()) {
                            operateResult.setSuccess(true);
                            operateResult.setMessage(description + ":添加成功！");
                        } else {
                            operateResult.setSuccess(false);
                            operateResult.setMessage(description + ":添加成功,但是数据同步失败！");
                        }
                    }
                } catch (Exception e) {
                    logger.error("查询" + description + "任务执行状态出现异常", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage("查询" + description + "任务执行状态出现异常：" + e.getMessage());
                }

                resourceEventPublisher.send(operateResult);
            });

            return result;
        } catch (Exception e) {
            logger.error("Add ManagedSystem to HMC fail:", e);
            return new BocloudResult(false, "新增失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult update(HmcServerUpdateParams params, RequestContext context) {
        try {
            Long id = params.getId();
            if (id == null) {
                return new BocloudResult(false, "需要参数id");
            }
            // 名称
            String name = params.getName();
            // 在所有逻辑分区断电后对系统断电
            Boolean poweroffAllLparShutdown = params.getPoweroffAllLparShutdown();
            // 分区启动策略
            String pendingPoweronLparStartPolicy = params.getPendingPoweronLparStartPolicy();
            // 供电端
            String pendingPowerOnSide = params.getPendingPowerOnSide();
            // 键锁位置
            String pendingSystemKeylock = params.getPendingSystemKeylock();

            HmcServer hmcServer = hmcServerRepository.getServerById(id);
            if (hmcServer == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的主机不存在");
            }
            String oleName = hmcServer.getName();
            HmcIplConfig hmcIplConfig = iplConfigRepository.getByServerId(id);
            if (hmcIplConfig == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的主机通电参数不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(hmcServer.getVendorId());
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + hmcServer.getVendorId() + "]的平台不存在");
            }

            taskExecutor.submit(() -> {
                Object data = MapTools.simpleMap("vendorId", hmcServer.getVendorId());
                OperateResult operateResult = new OperateResult(true, "success", OPERATE_RESULT_TYPE,
                        data, OperateResult.OperateCategory.ResourceEvent, context);
                try {
                    // 更新主机状态为更新中
                    String oldStatus = hmcServer.getStatus();
                    hmcServer.setStatus(HmcStatus.SERVER.UPDATING.getName());
                    hmcServerRepository.update(hmcServer);

                    // 织造参数
                    ManagedSystem managedSystem = new ManagedSystem();
                    if (StringUtils.isNotEmpty(name)) {
                        managedSystem.setSystemName(name);
                    }
                    managedSystem.setAssociatedIPLConfiguration(new AssociatedIPLConfiguration());
                    if (null != poweroffAllLparShutdown) {
                        managedSystem.getAssociatedIPLConfiguration().
                                setPowerOffWhenLastLogicalPartitionIsShutdown(poweroffAllLparShutdown.toString());
                    }
                    if (StringUtils.isNotEmpty(pendingPoweronLparStartPolicy)) {
                        managedSystem.getAssociatedIPLConfiguration().
                                setPendingPowerOnLogicalPartitionStartPolicy(
                                        new PendingPowerOnLogicalPartitionStartPolicy()
                                );
                        managedSystem.getAssociatedIPLConfiguration().
                                getPendingPowerOnLogicalPartitionStartPolicy().setValue(pendingPoweronLparStartPolicy);
                    }
                    if (StringUtils.isNotEmpty(pendingPowerOnSide)) {
                        managedSystem.getAssociatedIPLConfiguration().
                                setPendingPowerOnSide(pendingPowerOnSide);
                    }
                    if (StringUtils.isNotEmpty(pendingSystemKeylock)) {
                        managedSystem.getAssociatedIPLConfiguration().
                                setPendingSystemKeylock(pendingSystemKeylock);
                    }
                    // 调用Driver
                    BocloudResult bocloudResult = serverDriver.update(vendor.getUuid(), hmcServer.getUuid(), managedSystem);
                    if (bocloudResult.isFailed()) {
                        logger.error("更新主机[" + oleName + "]信息失败：" + bocloudResult.getMessage());
                        operateResult.setSuccess(false);
                        operateResult.setMessage("更新主机[" + oleName + "]信息失败：" + bocloudResult.getMessage());
                        resourceEventPublisher.send(operateResult);
                        return;
                    }

                    hmcServer.setStatus(oldStatus);
                    hmcServer.setName(name);
                    hmcServerRepository.update(hmcServer);

                    hmcIplConfig.setPoweroffAllLparShutdown(poweroffAllLparShutdown);
                    hmcIplConfig.setPendingPowerOnSide(pendingPowerOnSide);
                    hmcIplConfig.setPendingSystemKeylock(pendingSystemKeylock);
                    hmcIplConfig.setPendingPoweronLparStartPolicy(pendingPoweronLparStartPolicy);
                    iplConfigRepository.updateEntity(hmcIplConfig);

                    operateResult.setSuccess(true);
                    operateResult.setMessage("更新主机[" + oleName + "]信息成功");
                    resourceEventPublisher.send(operateResult);
                    return;
                } catch (Exception e) {
                    logger.error("更新主机[" + oleName + "]信息失败：", e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage("更新主机[" + oleName + "]信息失败：" + e.getMessage());
                    resourceEventPublisher.send(operateResult);
                    return;
                }
            });
            return new BocloudResult(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("Update ManagedSystem to HMC fail:", e);
            return new BocloudResult(false, "修改失败：" + e.getMessage());
        }
    }

    // 获取这个服务器的uuid
    private String getServerUuid(String vendorUuid, String serverIp) {
        BocloudResult getResult = serverDriver.get(vendorUuid);
        if (getResult.isFailed()) {
            return null;
        }
        if (null == getResult.getData()) {
            return null;
        }

        ManagedSystemResponse response = (ManagedSystemResponse) getResult.getData();
        for (ManagedSystemEntry entry : response.getEntries()) {
            if (serverIp.equals(entry.getContent().getManagedSystem().getPrimaryIPAddress())) {
                return entry.getId();
            }
        }

        return null;
    }

    // 这个函数仅仅去清除创建时的sever数据，所以没有其它的关联数据需要删除
    private Boolean cleanServer(HmcServer server, String vendorUuid, RequestContext context) {
        try {
            // 清除cmp平台上的服务器数据
            hmcServerRepository.remove(server.getId(), context.getTarget());

            // 如果server没有uuid，这意味着它还没有在hmc平台上创建成功，所以不用清除
            if (null != server.getUuid()) {
                BocloudResult result = serverDriver.removeConnection(vendorUuid, server.getUuid());
                if (result.isFailed()) {
                    logger.error("Failed to clean the server {} from HMC", server.getPrimaryIpAddress());
                    return false;
                }

                JSONObject jobJson = (JSONObject) result.getData();
                String jobId = jobJson.getString(Constant.HMC_JOB_ID);
                BocloudResult statusResult = commonDriver.getJobStatus(vendorUuid, jobId, 1 * 60L);

                if (statusResult.isFailed()) {
                    logger.error("Failed to clean the server {} from HMC, error {}", server.getPrimaryIpAddress(),
                            statusResult.getMessage());
                    return false;
                }

                // 如果1分钟内获取不到这个服务器的uuid，我们就认为它已经被删除
                int time = 0;
                while (time < 6) {
                    TimeUnit.SECONDS.sleep(10);
                    String uuid = getServerUuid(vendorUuid, server.getPrimaryIpAddress());
                    if (null == uuid) {
                        logger.info("Clean the server {} from HMC successful", server.getPrimaryIpAddress());
                        return true;
                    }
                    time += 1;
                }
            }
        } catch (Exception e) {
            logger.warn("删除HMC平台关联的数据时出现异常:", e);
        }

        logger.error("Failed to clean the server {} from HMC", server.getPrimaryIpAddress());
        return false;
    }

    /**
     * hmc平台删除受管系统连接
     *
     * @author sxp
     * @since Jun 19, 2018
     */
    @Override
    public BocloudResult removeConnection(Long id, RequestContext context) {
        try {
            HmcServer server = hmcServerRepository.getServerById(id);
            if (server == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的HMC服务器不存在");
            }

            String serverUuid = server.getUuid();
            if (StringUtils.isEmpty(serverUuid)) {
                return new BocloudResult(false, "当前HMC服务器的不存在");
            }

            Long vendorId = server.getVendorId();
            String name = server.getName();
            if (StringUtils.isEmpty(serverUuid)) {
                name = "当前服务器";
            }

            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + vendorId + "]的云平台不存在");
            }

            BocloudResult result = serverDriver.removeConnection(vendor.getUuid(), serverUuid);
            if (result.isFailed()) {
                return result;
            }

            JSONObject jobJson = (JSONObject) result.getData();
            String jobId = jobJson.getString(Constant.HMC_JOB_ID);
            if (StringUtils.isEmpty(jobId)) {
                return new BocloudResult(false, "HMC平台删除服务器失败：生成的任务ID是空");
            }

            String description = "HMC平台删除服务器[" + name + "]";
            server.setStatus(HmcStatus.SERVER.REMOVE_CONNECTING.getName());
            asynGetJobStatus(server, vendor.getUuid(), jobId, description, context, HmcJobType.RemoveManagedSystemConnection);

            return result;
        } catch (Exception e) {
            logger.error("Remove ManagedSystem Connection from HMC fail:", e);
            return new BocloudResult(false, "删除失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<GridBean> list(Pager pager) {
        List<HmcServer> list;
        List<SimpleBean> beans;
        GridBean gridBean;
        try {
            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();

            int total = this.hmcServerRepository.count(params);
            if (simple) {
                beans = this.hmcServerRepository.list(params, sorter);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = this.hmcServerRepository.list(page, rows, params, sorter);
                // add memory, processor and capability data
                for (HmcServer server : list) {
                    HmcSystemProcessorConfig processorConfig = hmcSystemProcessorConfigRepository
                            .getByServerId(server.getId());
                    server.setHmcSystemProcessorConfig(processorConfig);
                    HmcSystemMemoryConfig memoryConfig = hmcSystemMemoryConfigRepository.getByServerId(server.getId());
                    server.setHmcSystemMemoryConfig(memoryConfig);
                    HmcSystemCapability capability = hmcSystemCapabilityRepository.getByServerId(server.getId());
                    server.setHmcSystemCapability(capability);
                }
                gridBean = GridHelper.getBean(page, rows, total, list);
            }
            return new BocloudResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query HMC server list fail:", e);
            return new BocloudResult(false, "查询失败," + e.getMessage(), null, null);
        }
    }

    @Override
    public BocloudResult detail(Long id) {
        try {
            // 基本信息(常规)
            HmcServer server = this.hmcServerRepository.getServerById(id);
            if (server == null) {
                logger.warn("HMC服务器 does not exist!");
                return new BocloudResult(false, null, "不存在");
            }
            String machineType = server.getMachineType();
            String model = server.getModel();
            server.setMachineTypeAndModel(machineType + "-" + model);
            HmcPartition partition = hmcPartitionRepository.getServicePartitionByServerId(id);
            server.setServicePartition(partition);

            // 功能
            HmcSystemCapability capability = capabilityRepository.getByServerId(server.getId());

            // 处理器
            HmcSystemProcessorConfig cpuConfig = processorConfigRepository.getByServerId(server.getId());
            if (null != cpuConfig) {
                cpuConfig.calculateAssignedSystemProcessorUnit();
                if (null != capability) {
                    cpuConfig.setSharedProcessorPoolCapable(capability.getSharedProcessorPoolCapable());
                }
            }

            // 内存
            HmcSystemMemoryConfig memoryConfig = memoryConfigRepository.getByServerId(server.getId());
            if (null != memoryConfig) {
                memoryConfig.calculateAssignedSystemMemory();
                memoryConfig.calculateMemoryGB();
                if (null != capability) {
                    memoryConfig.setActiveMemorySharingCapable(capability.getActiveMemorySharingCapable());
                }
            }
            // I/O
            List<Param> params = new ArrayList<>(1);
            params.add(new Param(MapTools.simpleMap("hmcServerId", id), Sign.EQ));
            List<HmcIoAdapter> adapters = ioAdapterRepository.list(1, Integer.MAX_VALUE, params, null);

            // 供电参数
            HmcIplConfig iplConfig = iplConfigRepository.getByServerId(server.getId());

            // 高级
            Map<String, Object> advanceMap = new HashMap<>();
            if (null != memoryConfig) {
                advanceMap.put("currentAvailableHugePages", memoryConfig.getCurrentAvailableHugePages());
                advanceMap.put("configurableHugePages", memoryConfig.getConfigurableHugePages());
                Long hugePageSize = memoryConfig.getHugePageSize();
                advanceMap.put("hugePageSize", hugePageSize);
                if (hugePageSize != null) {
                    advanceMap.put("hugePageSizeGB", Math.round((double) hugePageSize / 1024 * 100) / 100D);
                }
                advanceMap.put("maximumHugePages", memoryConfig.getMaximumHugePages());
                advanceMap.put("requestedHugePages", memoryConfig.getRequestedHugePages());
                advanceMap.put("totalBarrierSynchronizationRegisterArrays",
                        memoryConfig.getTotalBarrierSynchronizationRegisterArrays());
                advanceMap.put("barrierSynchronizationRegisterArraySize",
                        memoryConfig.getBarrierSynchronizationRegisterArraySize());
                advanceMap.put("availableBarrierSynchronizationRegisterArrays",
                        memoryConfig.getAvailableBarrierSynchronizationRegisterArrays());
            }
            // 主机的共享存储池
            List<HmcSystemSharedProcessorPool> sharedProcessorPools = sharedProcessorPoolRepository.listByServerId(server.getId());
            sharedProcessorPools = sharedProcessorPools.stream().filter(hmcSystemSharedProcessorPool -> hmcSystemSharedProcessorPool.getAssignedPartitions() > 0 || hmcSystemSharedProcessorPool.getAvailableProcUnits() > 0).collect(Collectors.toList());
            Map<String, Object> result = new HashMap<>();
            result.put("general", server);
            result.put("processor", cpuConfig);
            result.put("memory", memoryConfig);
            result.put("io", adapters);
            result.put("ipl", iplConfig);
            result.put("capability", capability);
            result.put("advanced", advanceMap);
            result.put("sharedProcessorPool", sharedProcessorPools);
            return new BocloudResult(true, result, "查询成功");
        } catch (Exception e) {
            logger.error("Query HMC server detail fail:", e);
            return new BocloudResult(false, "查询失败", null, null);
        }
    }

    /**
     * HMC服务器开机
     *
     * @param id HMC服务器ID
     * @return 操作结果
     * @author sxp
     * @since Jun 12, 2018
     */
    @Override
    public BocloudResult powerOn(Long id, RequestContext context) {
        try {
            HmcServer server = hmcServerRepository.getServerById(id);
            if (server == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的HMC服务器不存在");
            }
            String status = server.getStatus();
            if (!HmcServerStatus.PowerOff.getStatus().equals(status)) {
                return new BocloudResult(false, "当前HMC服务器不是[断电]状态，不能执行开机操作");
            }

            String serverUuid = server.getUuid();
            if (StringUtils.isEmpty(serverUuid)) {
                return new BocloudResult(false, "当前HMC服务器对应的uuid为空");
            }

            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + server.getVendorId() + "]的云平台不存在");
            }

            BocloudResult result = serverDriver.powerOn(vendor.getUuid(), serverUuid);
            if (result.isFailed()) {
                return new BocloudResult(false, "HMC服务器开机失败:" + result.getMessage());
            }

            JSONObject jobJson = (JSONObject) result.getData();
            String jobId = jobJson.getString(Constant.HMC_JOB_ID);
            if (StringUtils.isEmpty(jobId)) {
                return new BocloudResult(false, "HMC服务器开机失败：生成的任务ID是空");
            }

            // 更新server表中该主机的状态为开机中
            Server cmpServer = serverRepository.getByResourceId(server.getUuid());
            if (cmpServer != null) {
                cmpServer.setStatus(BocloudStatus.Server.STARTING.name());
                cmpServer.setPowerState(BocloudStatus.Power.STARTING.name());
                serverRepository.update(cmpServer);
                //发送消息给cop
                resourceTaskNotice.sendPhysicalMessage(cmpServer, ResourceTaskNotice.Action.UPDATE);
            }

            String description = "HMC服务器[" + server.getName() + "]开机";
            server.setStatus(HmcStatus.SERVER.POWERONING.getName());
            asynGetJobStatus(server, vendor.getUuid(), jobId, description, context, HmcJobType.PowerOnManagedSystem);

            return result;
        } catch (Exception e) {
            logger.error("HMC server powerOn fail:", e);
            return new BocloudResult(false, "HMC服务器开机失败:" + e.getMessage());
        }
    }

    /**
     * 异步查询任务执行状态
     *
     * @author sxp
     * @since Jun 12, 2018
     */
    private void asynGetJobStatus(HmcServer server, String vendorUuid, String jobId, String description,
                                  RequestContext context, HmcJobType type) {

        taskExecutor.submit(() -> {
            logger.info("{}的jobId为{}", description, jobId);
            Object data = MapTools.simpleMap("vendorId", server.getVendorId());
            OperateResult operateResult = new OperateResult(true, "success", OPERATE_RESULT_TYPE, data,
                    OperateResult.OperateCategory.ResourceEvent, context);

            try {
                // 设置服务器新的状态(添加一个新的服务器连接时不需要更新状态)
                if (type != HmcJobType.AddManagedSystem) {
                    hmcServerRepository.update(server);
                }

                BocloudResult statusResult = commonDriver.getJobStatus(vendorUuid, jobId);

                if (statusResult.isSuccess()) {
                    operateResult.setSuccess(true);
                    operateResult.setMessage(description + "任务执行完成");

                    if (type == HmcJobType.PowerOffManagedSystem || type == HmcJobType.RestartManagedSystem) {
                        List<HmcPartition> lpars = hmcPartitionRepository.listByServerId(server.getId());
                        for (HmcPartition lpar : lpars) {
                            if (HmcStatus.PARTITION.INSTALLING.getName().equals(lpar.getStatus())) {
                                // 关机/重启成功逻辑分区所在的服务器，装机任务取消，设置为取消装机结果
                                logger.warn("分区{}取消AIX安装", lpar.getName());
                                nimService.cancel(lpar.getId(), context);
                            }
                        }
                    }
                } else {
                    operateResult.setSuccess(false);
                    operateResult.setMessage(description + ":" + statusResult.getMessage());
                }

                if (type == HmcJobType.PowerOnManagedSystem || type == HmcJobType.PowerOffManagedSystem
                        || type == HmcJobType.RestartManagedSystem) {
                    // 不管任务成功失败，状态都有可能改变
                    updateStatus(server, vendorUuid, description, operateResult);
                } else if (type == HmcJobType.RemoveManagedSystemConnection) {
                    // 如果2分钟内获取不到这个服务器的uuid，我们就认为它已经被删除
                    int time = 0;
                    operateResult.setSuccess(false);
                    operateResult.setMessage(description + ":任务执行失败");
                    while (time < 12) {
                        TimeUnit.SECONDS.sleep(10);
                        String uuid = getServerUuid(vendorUuid, server.getPrimaryIpAddress());
                        if (null == uuid) {
                            operateResult.setSuccess(true);
                            operateResult.setMessage(description + ":任务执行成功");
                            break;
                        }
                        time += 1;
                    }
                    removeHmcAssociatedData(server, context);
                }
            } catch (Exception e) {
                logger.error("查询" + description + "任务执行状态出现异常", e);
                operateResult.setSuccess(false);
                operateResult.setMessage("查询" + description + "任务执行状态出现异常:" + e.getMessage());
            }

            resourceEventPublisher.send(operateResult);
        });

    }

    private void updateStatus(HmcServer server, String vendorUuid, String description, OperateResult operateResult)
            throws Exception {
        String serverUuid = server.getUuid();
        // 去获取服务器的属性，并查看服务器的参考码，如果服务器是在正在连接的状态，等待这个连接完成
        // 目前的等待时间是10分钟，每10秒查看一次。
        int time = 0;
        while (time < 60) {
            BocloudResult result = serverDriver.queryManagedSystemState(vendorUuid, serverUuid);
            if (result.isFailed()) {
                operateResult.setSuccess(false);
                operateResult.setMessage(description + "任务执行成功，但是获取服务器的状态出错：" + result.getMessage());
                return;
            }
            // check server status.
            String status = (String) result.getData();
            if ("failed authentication".equals(status)) {
                logger.error("the added server is incorrectly password");
                break;
            } else if ("operating".equals(status)) {
                logger.info("the server is added successful");
                break;
            } else if ("power off".equals(status)) {
                logger.info("the server is powered off");
                break;
            }

            logger.info("the server {} is connecting", serverUuid);
            TimeUnit.SECONDS.sleep(10);
            time += 1;
        }

        // 更新服务的属性
        BocloudResult result = serverDriver.queryManagedSystemAttribute(vendorUuid, serverUuid);
        if (result.isSuccess()) {
            ManagedSystemEntry entry = (ManagedSystemEntry) result.getData();
            hmcDatabaseHelper.updateHmcServerEntity(server, entry);
            hmcServerRepository.update(server);

            // 更新cmp中server的状态
            Server cmpServer = serverRepository.getByResourceId(server.getUuid());
            if (cmpServer != null) {
                if (HmcServerStatus.Operating.getStatus().equals(entry.getContent().getManagedSystem().getState())) {
                    cmpServer.setStatus(BocloudStatus.Server.RUNNING.name());
                    cmpServer.setPowerState(BocloudStatus.Power.RUNNING.name());
                } else if (HmcServerStatus.PowerOff.getStatus().equals(entry.getContent().getManagedSystem().getState())) {
                    cmpServer.setStatus(BocloudStatus.Server.STOPPED.name());
                    cmpServer.setPowerState(BocloudStatus.Power.STOPPED.name());
                } else if (HmcServerStatus.Initializing.getStatus().equals(entry.getContent().getManagedSystem().getState())) {
                    cmpServer.setStatus(BocloudStatus.Server.ACTIVING.name());
                    cmpServer.setPowerState(BocloudStatus.Power.STARTING.name());
                } else if (HmcServerStatus.NO_CONNECTION.getStatus().equals(entry.getContent().getManagedSystem().getState())) {
                    cmpServer.setStatus(BocloudStatus.Server.INACCESSIBLE.name());
                    cmpServer.setPowerState(BocloudStatus.Power.STOPPED.name());
                } else {
                    cmpServer.setStatus(BocloudStatus.Server.UNKNOWN.name());
                    cmpServer.setPowerState(BocloudStatus.Power.STOPPED.name());
                }
                serverRepository.update(cmpServer);
                //发送消息给cop
                resourceTaskNotice.sendPhysicalMessage(cmpServer, ResourceTaskNotice.Action.UPDATE);
            }
        }

        // 服务器开关机后，隶属于该服务器的逻辑分区状态也会发生变化
        Long serverId = server.getId();
        List<HmcPartition> lpars = hmcPartitionRepository.listByServerId(serverId);

        if (lpars != null) {
            String descr = description + "之后更新关联逻辑分区的状态";
            OperateResult lparOpResult = new OperateResult();
            lparOpResult.setSuccess(true);
            int failCount = 0;

            for (HmcPartition lpar : lpars) {
                hmcPartitionService.updateStatus(lpar, vendorUuid, descr, lparOpResult);
                if (lparOpResult.isFailed()) {
                    failCount++;
                }
            }

            if (failCount > 0) {
                operateResult.setMessage(description + "任务执行" + (operateResult.isSuccess() ? "成功，但是" : "失败，并且") + "更新关联逻辑分区的状态时存在" + failCount + "个逻辑分区状态未更新成功。");
            }
        }
    }

    /**
     * HMC服务器关机
     *
     * @param id HMC服务器ID
     * @return 操作结果
     * @author sxp
     * @since Jun 12, 2018
     */
    @Override
    public BocloudResult powerOff(Long id, RequestContext context) {
        try {
            HmcServer server = hmcServerRepository.getServerById(id);
            if (server == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的HMC服务器不存在");
            }
            String status = server.getStatus();
            if (HmcServerStatus.PowerOff.getStatus().equals(status)) {
                return new BocloudResult(false, "当前HMC服务器是[断电]状态，不能执行关机操作");
            }

            String serverUuid = server.getUuid();
            if (StringUtils.isEmpty(serverUuid)) {
                return new BocloudResult(false, "当前HMC服务器对应的uuid为空");
            }

            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + server.getVendorId() + "]的云平台不存在");
            }

            BocloudResult result = serverDriver.powerOff(vendor.getUuid(), serverUuid);
            if (result.isFailed()) {
                return new BocloudResult(false, "HMC服务器关机失败:" + result.getMessage());
            }
            JSONObject jobJson = (JSONObject) result.getData();
            String jobId = jobJson.getString(Constant.HMC_JOB_ID);
            if (StringUtils.isEmpty(jobId)) {
                return new BocloudResult(false, "HMC服务器关机失败：生成的任务ID是空");
            }

            // 更新server表中该主机的状态为关机中
            Server cmpServer = serverRepository.getByResourceId(server.getUuid());
            if (cmpServer != null) {
                cmpServer.setStatus(BocloudStatus.Server.STOPPING.name());
                cmpServer.setPowerState(BocloudStatus.Power.STOPPING.name());
                serverRepository.update(cmpServer);
                //发送消息给cop
                resourceTaskNotice.sendPhysicalMessage(cmpServer, ResourceTaskNotice.Action.UPDATE);
            }

            String description = "HMC服务器[" + server.getName() + "]关机";
            server.setStatus(HmcStatus.SERVER.POWEROFFING.getName());
            asynGetJobStatus(server, vendor.getUuid(), jobId, description, context, HmcJobType.PowerOffManagedSystem);

            return result;
        } catch (Exception e) {
            logger.error("HMC server powerOff fail:", e);
            return new BocloudResult(false, "HMC服务器关机失败:" + e.getMessage());
        }
    }

    /**
     * HMC服务器重置连接
     *
     * @param id HMC服务器ID
     * @return 操作结果
     */
    @Override
    public BocloudResult resetConnection(Long id, RequestContext context) {
        try {
            HmcServer server = hmcServerRepository.getServerById(id);
            if (server == null) {
                return new BocloudResult(false, "唯一标识为[" + id + "]的HMC服务器不存在");
            }

            String serverUuid = server.getUuid();
            if (StringUtils.isEmpty(serverUuid)) {
                return new BocloudResult(false, "当前HMC服务器对应的uuid为空");
            }

            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
            if (vendor == null) {
                return new BocloudResult(false, "唯一标识为[" + server.getVendorId() + "]的云平台不存在");
            }

            BocloudResult result = serverDriver.resetConnection(vendor.getUuid(), serverUuid);
            if (result.isFailed()) {
                return new BocloudResult(false, "HMC服务器重置连接失败:" + result.getMessage());
            }
            JSONObject jobJson = (JSONObject) result.getData();
            String jobId = jobJson.getString(Constant.HMC_JOB_ID);
            if (StringUtils.isEmpty(jobId)) {
                return new BocloudResult(false, "HMC服务器重置连接失败：生成的任务ID是空");
            }

            String description = "HMC服务器[" + server.getName() + "]重置连接";
            server.setStatus(HmcStatus.SERVER.RESET_CONNECTING.getName());
            asynGetJobStatus(server, vendor.getUuid(), jobId, description, context, HmcJobType.RestartManagedSystem);

            return result;
        } catch (Exception e) {
            logger.error("HMC server resetConnection fail:", e);
            return new BocloudResult(false, "HMC服务器重置连接失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult syncServer(HmcServer server, RequestContext context) {
        try {
            return updateAndSyncServer(server, context);
        } catch (Exception e) {
            logger.error("HMC server sync fail:", e);
            return new BocloudResult(false, "HMC服务器同步失败:" + e.getMessage());
        }
    }

    private BocloudResult updateAndSyncServer(HmcServer server, RequestContext context) throws Exception {
        CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
        if (vendor == null) {
            return new BocloudResult(false, "唯一标识为[" + server.getVendorId() + "]的云平台不存在");
        }

        BocloudResult result = locationDriver.getManagedSystemSyncInfo(vendor.getUuid(), server.getUuid());
        if (result.isFailed()) {
            logger.error("HMC server sync fail:", result.getErrorMsg());
            return new BocloudResult(false, "HMC服务器同步失败:" + result.getErrorMsg());
        }

        SyncModel syncModel = (SyncModel) result.getData();
        return hmcTransporter.syncServer(server, syncModel, context.getTarget());
    }

    /**
     * 删除HMC平台关联的数据
     *
     * @author sxp
     *
     * @since Jun 19, 2018
     */
    private void removeHmcAssociatedData(HmcServer server, RequestContext context) throws Exception {
        Long serverId;
        Long parId;
        List<HmcPartition> hmcPartitions;
        serverId = server.getId();

        try {
            // 删除服务器属性数据
            hmcDatabaseHelper.removeServerAttributer(serverId);

            // 删除分区信息
            hmcPartitions = hmcPartitionRepository.listByServerId(serverId);
            if (hmcPartitions != null) {
                for (HmcPartition par : hmcPartitions) {
                    parId = par.getId();
                    if ("Virtual IO Server".equals(par.getPartitionType())) {
                        // 删除虚拟存储信息
                        hmcDatabaseHelper.removeVirtualStorage(par.getId());
                        // 删除物理存储信息
                        hmcDatabaseHelper.removePhysicalStorage(par.getId());
                    }
                    hmcDatabaseHelper.removePartition(parId, context.getTarget());
                }
            }

            // 删除主机以太网
            hmcDatabaseHelper.deleteHostEthernetAdapter(serverId);

            // 删除虚拟交换机
            hmcVirtualSwitchRepository.removeByServerId(serverId, context.getTarget());

            hmcServerRepository.remove(serverId, context.getTarget());

            resourceRepository.remove(serverId, ResourceCategory.Computer.name(), "MIDRANGE", context.getTarget());
        } catch (Exception e) {
            logger.warn("删除HMC平台关联的数据时出现异常:", e);
        }
    }

    @Override
    public BocloudResult start(Long id, RequestContext context) {
        String path = Server.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Server server = this.serverRepository.getServerBean(id);
            if (null == server) {
                logger.warn("Server data does not exist!");
                return new BocloudResult(false, server, "该服务器不存在");
            }
            CloudProvider type = serverService.getCloudVendorType(server);
            if (type == CloudProvider.HMC) {
                HmcServer hmcServer = hmcServerRepository.getServerByUuid(server.getResourceId());
                if (hmcServer == null) {
                    return new BocloudResult(false, server, "未找到UUID为[" + server.getResourceId() + "]的POWERVC主机");
                }
                return powerOn(hmcServer.getId(), context);
            }
            return new BocloudResult(false, "平台类型" + type.name() + "错误!");
        } catch (Exception e) {
            logger.error("Start server fail:", e);
            return new BocloudResult(false, "启动失败");
        }
    }

    @Override
    public BocloudResult stop(Long id, RequestContext context) {
        String path = Server.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Server server = this.serverRepository.getServerBean(id);
            if (null == server) {
                logger.warn("Server data does not exist!");
                return new BocloudResult(false, server, "该服务器不存在");
            }
            CloudProvider type = serverService.getCloudVendorType(server);
            if (type == CloudProvider.HMC) {
                HmcServer hmcServer = hmcServerRepository.getServerByUuid(server.getResourceId());
                if (hmcServer == null) {
                    return new BocloudResult(false, server, "未找到UUID为[" + server.getResourceId() + "]的POWERVC主机");
                }
                return powerOff(hmcServer.getId(), context);
            }
            return new BocloudResult(false, "平台类型" + type.name() + "错误!");
        } catch (Exception e) {
            logger.error("Stop server fail:", e);
            return new BocloudResult(false, "关闭失败");
        }
    }
}
