package cn.iocoder.yudao.module.system.service.information;

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.config.poperties.ZnConfigConstant;
import cn.iocoder.yudao.module.system.constant.device.DeviceChcheConstant;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.DeviceInformationDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.MapBindDeviceInfoDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.StatisticsInformationDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationRespVO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.log.vo.UserOperationLogSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.config.CommonConfigDO;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseTakePointBindingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.dal.mysql.information.DeviceInformationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import cn.iocoder.yudao.module.system.enums.common.ZeroOneEnum;
import cn.iocoder.yudao.module.system.enums.device.DeviceAttributeEnum;
import cn.iocoder.yudao.module.system.enums.device.DeviceStatusEnum;
import cn.iocoder.yudao.module.system.enums.device.DeviceTypeEnum;
import cn.iocoder.yudao.module.system.enums.device.PictureConfigEnum;
import cn.iocoder.yudao.module.system.service.config.CommonConfigService;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.houselocation.WareHouseTakePointBindingService;
import cn.iocoder.yudao.module.system.service.houselocation.WareHouseTakePointService;
import cn.iocoder.yudao.module.system.service.log.UserOperationLogService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.aes.AESEncryptionUtil;
import cn.iocoder.yudao.module.system.util.modbus3.ModbusUtils;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 设备信息 Service 实现类
 *
 * @author 陈宾顺
 */
@Service
@Validated
@Slf4j
public class DeviceInformationServiceImpl extends ServiceImpl<DeviceInformationMapper, DeviceInformationDO> implements DeviceInformationService {

    @Resource
    private DeviceInformationMapper informationMapper;

    @Resource
    private DictDataService dictDataService;

    @Resource
    private PositionMapMapper positionMapMapper;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UserOperationLogService userOperationLogService;

    @Resource
    private RobotWarnMsgService warnMsgService;

    @Resource
    private CommonConfigService configService;

    @Resource
    private PositionMapItemService positionMapItemService;

    @Autowired
    private ZnConfigConstant znConfigConstant;

    @Resource
    private WareHouseTakePointBindingService houseTakePointBindingService;

    @Resource
    private WareHouseTakePointService houseTakePointService;

    @Override
    public Long createInformation(DeviceInformationSaveReqVO createReqVO) {
        // -- 先判断库里是否有相通的mac地址数据
        long count = this.count(new LambdaQueryWrapper<DeviceInformationDO>().eq(DeviceInformationDO::getMacAddress, createReqVO.getMacAddress()));
        if (count > 0L) {
            throw exception(INFORMATION_MAC_EXIST);
        }

        //默认图片
        if (PictureConfigEnum.DEFAULT.getType().equals(createReqVO.getPictureConfig())) {
            List<DictDataDO> deviceType = dictDataService.getDictDataListByDictType("device_type");
            DictDataDO dictDataDO = deviceType.stream()
                    .filter(v -> Integer.valueOf(v.getValue()).equals(createReqVO.getDeviceType()))
                    .findFirst()
                    .orElse(new DictDataDO());
            createReqVO.setUrl(dictDataDO.getRemark());
        }

        List<WareHouseTakePointBindingDO> list = new ArrayList<>();
        if (DeviceTypeEnum.CAMERA.getType().equals(createReqVO.getDeviceType())) {
            try {
                createReqVO.setCameraCode(AESEncryptionUtil.getEncrypt(createReqVO.getCameraCode(), znConfigConstant.getCameraSecretKey()));
            } catch (Exception ignored) {
            }
        }else if (DeviceTypeEnum.FLIP.getType().equals(createReqVO.getDeviceType())) {
            if (ObjectUtil.isEmpty(createReqVO.getTakePointId())) {
                throw exception(INFORMATION_FLIP_BINDING);
            }
            if (ObjectUtil.isEmpty(createReqVO.getCheckPointIds())) {
                throw exception(INFORMATION_FLIP_NEED_BINDING_CHECK);
            }

        }

        // 插入
        DeviceInformationDO information = BeanUtils.toBean(createReqVO, DeviceInformationDO.class);
        information.setDeviceStatus(1);
        informationMapper.insert(information);


        for (Long takePointId : createReqVO.getCheckPointIds()) {
            WareHouseTakePointBindingDO data = new WareHouseTakePointBindingDO();
            data.setBindingId(information.getId());
            data.setBindingType(ZeroOneEnum.ZERO.getType());
            data.setTakePointId(takePointId);
            list.add(data);
        }

        houseTakePointBindingService.createHouseTakePointBindings(list);
        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction("新增设备 " + createReqVO.getDeviceNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
        // 返回
        return information.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateInformation(DeviceInformationSaveReqVO updateReqVO) {
        // 校验存在
        validateInformationExists(updateReqVO.getId());
        //默认图片
        if (PictureConfigEnum.DEFAULT.getType().equals(updateReqVO.getPictureConfig())) {
            List<DictDataDO> deviceType = dictDataService.getDictDataListByDictType("device_type");
            DictDataDO dictDataDO = deviceType.stream()
                    .filter(v -> Integer.valueOf(v.getValue()).equals(updateReqVO.getDeviceType()))
                    .findFirst()
                    .orElse(new DictDataDO());
            updateReqVO.setUrl(dictDataDO.getRemark());
        }
        // 更新
        if (DeviceTypeEnum.CAMERA.getType().equals(updateReqVO.getDeviceType())) {
            try {
                updateReqVO.setCameraCode(AESEncryptionUtil.getEncrypt(updateReqVO.getCameraCode(), znConfigConstant.getCameraSecretKey()));
            } catch (Exception ignored) {
            }
        }

        DeviceInformationDO updateObj = BeanUtils.toBean(updateReqVO, DeviceInformationDO.class);
        informationMapper.updateById(updateObj);

        if (ObjectUtil.isNotEmpty(updateObj.getPositionMapItemId())) {
            PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(updateObj.getPositionMapItemId());
            String dataJson = positionMapItem.getDataJson();
            /*DeviceInformationDataJsonDTO data = JSON.parseObject(dataJson, DeviceInformationDataJsonDTO.class);
            data.setDeviceType(updateObj.getDeviceType());
            data.setDeviceNo(updateObj.getDeviceNo());
            data.setMapImageUrl(updateObj.getMapImageUrl());*/

            Gson gson = new Gson();
            Map<Object, Object> map = new HashMap();
            map = gson.fromJson(dataJson, map.getClass());
            map.put("deviceType", updateObj.getDeviceType());
            map.put("deviceNo", updateObj.getDeviceNo());
            map.put("mapImageUrl", updateObj.getMapImageUrl());

            positionMapItem.setDataJson(JSON.toJSONString(map));
            positionMapItemService.updateById(positionMapItem);
        }

        List<WareHouseTakePointBindingDO> list = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(updateReqVO.getCheckPointIds())) {
            for (Long takePointId : updateReqVO.getCheckPointIds()) {
                WareHouseTakePointBindingDO data = new WareHouseTakePointBindingDO();
                data.setBindingId(updateReqVO.getId());
                data.setBindingType(ZeroOneEnum.ZERO.getType());
                data.setTakePointId(takePointId);
                list.add(data);
            }
        }
        houseTakePointBindingService.deleteByBindingId(updateReqVO.getId());
        houseTakePointBindingService.createHouseTakePointBindings(list);
        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction("更新设备信息 " + updateReqVO.getDeviceNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        userOperationLogService.createUserOperationLog(operationLog);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteInformation(Long id) {
        // 校验存在
        validateInformationExists(id);
        DeviceInformationDO deviceInformationDO = informationMapper.selectById(id);
        if (ObjectUtil.isNotEmpty(deviceInformationDO.getPositionMapItemId())) {
            throw exception(INFORMATION_BIND_MAP);
        }

        UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
                .operateAction("删除设备 " + deviceInformationDO.getDeviceNo())
                .nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
        // 删除
        informationMapper.deleteById(id);

        userOperationLogService.createUserOperationLog(operationLog);
    }

    private void validateInformationExists(Long id) {
        if (informationMapper.selectById(id) == null) {
            throw exception(INFORMATION_NOT_EXISTS);
        }
    }

    @Override
    public DeviceInformationRespVO getInformation(Long id) {
        // 校验存在
        validateInformationExists(id);
        DeviceInformationDO deviceInformationDO = informationMapper.selectById(id);
        String deviceKey = DeviceChcheConstant.DEVICE_LAST_TIME + deviceInformationDO.getMacAddress();
        Object object = redisUtil.get(deviceKey);
        DeviceInformationRespVO device = BeanUtils.toBean(deviceInformationDO, DeviceInformationRespVO.class);

        if (DeviceTypeEnum.FLIP.getType().equals(deviceInformationDO.getDeviceType())) {
//            WareHouseTakePointDO takeWareHouseTakePointDO = houseTakePointService.getById(deviceInformationDO.getTakePointId());
            device.setTakePointId(deviceInformationDO.getTakePointId());
            List<WareHouseTakePointBindingDO> bindingDOS = houseTakePointBindingService.getByBindingId(id);
            if (ObjectUtil.isNotEmpty(bindingDOS)) {
                List<Long> pointIds = bindingDOS.stream().map(WareHouseTakePointBindingDO::getTakePointId).collect(Collectors.toList());
                /*WareHouseTakePointSaveReqVO reqVO = new WareHouseTakePointSaveReqVO();
                reqVO.setIds(pointIds);
                List<WareHouseTakePointDO> houseTakePointList = houseTakePointService.getHouseTakePointList(reqVO);
                device.setCheckPointBindingList(houseTakePointList);*/
                device.setCheckPointIds(pointIds);
            }
        }

        if (ObjectUtil.isEmpty(object)) {
            deviceInformationDO.setDeviceStatus(DeviceStatusEnum.OFF_LINE.getType());
            return device;
        }
        try {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime curTimeLDT = LocalDateTime.parse((String) object, df);
            deviceInformationDO.setDeviceLastTime(curTimeLDT);
            deviceInformationDO.setDeviceStatus(DeviceStatusEnum.ON_LINE.getType());
        } catch (Exception e) {
            log.info("查询设备最后通讯时间异常 :{}", e.getMessage());
        }
        return device;
    }

    @Override
    public PageResult<DeviceInformationDO> getInformationPage(DeviceInformationPageReqVO pageReqVO) {
        return informationMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchEditOrDel(List<List<DeviceInformationDO>> list) {
        //批量添加、修改、删除
        List<DeviceInformationDO> editList = new ArrayList<>();
        if (isNotEmpty(list.get(0)) || isNotEmpty(list.get(1))) {
            editList.addAll(list.get(0));
            editList.addAll(list.get(1));
        }
        if (isNotEmpty(list.get(2))) {
            list.get(2).forEach(a -> {
                a.setPositionMapItemId(null);
                a.setPositionMapId(null);
            });
            editList.addAll(list.get(2));
        }
        if (isNotEmpty(editList)) {
            informationMapper.updateBatch(editList);
        }
    }

    @Override
    public List<DeviceInformationDO> getByMapId(Long positionMapId) {
        return informationMapper.selectList(new LambdaQueryWrapperX<DeviceInformationDO>()
                .eq(DeviceInformationDO::getPositionMapId, positionMapId));
    }

    @Override
    public List<DeviceInformationDO> getList(DeviceInformationDTO dto) {
        return informationMapper.selectList(new LambdaQueryWrapper<DeviceInformationDO>()
                .isNull(dto.getUnboundFlag() != null && dto.getUnboundFlag() == 1, DeviceInformationDO::getPositionMapId)
                .eq(dto.getPositionMapId() != null, DeviceInformationDO::getPositionMapId, dto.getPositionMapId())
                .eq(dto.getDeviceType() != null, DeviceInformationDO::getDeviceType, dto.getDeviceType())
                .in(dto.getDeviceTypes() != null, DeviceInformationDO::getDeviceType, dto.getDeviceTypes())
                .eq(dto.getDeviceStatus() != null, DeviceInformationDO::getDeviceStatus, dto.getDeviceStatus())
                .eq(dto.getDeviceEnable() != null, DeviceInformationDO::getDeviceEnable, dto.getDeviceEnable())
        );
    }

    /**
     * 获得设备信息分类列表
     *
     * @return
     */
    @Override
    public Map<Integer, List<DeviceInformationDO>> classification() {
        List<DeviceInformationDO> deviceInformationDOS = informationMapper.selectList(new LambdaQueryWrapper<DeviceInformationDO>());
        if (ObjectUtil.isEmpty(deviceInformationDOS)) {
            return new HashMap<>();
        }

        // todo 需要设置设备通讯的时间
        for (DeviceInformationDO deviceInformationDO : deviceInformationDOS) {
            String deviceKey = DeviceChcheConstant.DEVICE_LAST_TIME + deviceInformationDO.getMacAddress();
            Object object = redisUtil.get(deviceKey);
            if (ObjectUtil.isEmpty(object)) {
                deviceInformationDO.setDeviceStatus(DeviceStatusEnum.OFF_LINE.getType());
                continue;
            }
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime curTimeLDT = LocalDateTime.parse((String) object, df);
                deviceInformationDO.setDeviceLastTime(curTimeLDT);
                deviceInformationDO.setDeviceStatus(DeviceStatusEnum.ON_LINE.getType());
            } catch (Exception e) {
                log.info("查询设备最后通讯时间异常 :{}", e.getMessage());
            }
        }

        Map<Integer, List<DeviceInformationDO>> collect =
                deviceInformationDOS.stream()
                        .collect(Collectors.groupingBy(DeviceInformationDO::getDeviceType));

        /*ArrayList<Map.Entry<Integer, List<DeviceInformationDO>>> list = new ArrayList<Map.Entry<Integer, List<DeviceInformationDO>>>(collect.entrySet());
        Collections.sort(list, Comparator.comparing(Map.Entry::getKey));*/

        return collect;
    }

    /**
     * 统计设备
     *
     * @return
     */
    @Override
    public List<StatisticsInformationDTO> getDeviceNumber() {
        List<DeviceInformationDO> deviceInformationDOS = informationMapper.selectList(new LambdaQueryWrapper<DeviceInformationDO>());
        if (ObjectUtil.isEmpty(deviceInformationDOS)) {
            return new ArrayList<>();
        }

        List<StatisticsInformationDTO> list = deviceInformationDOS.stream()
                .filter(v -> ObjectUtil.isNotEmpty(v.getDeviceType()))
                .collect(Collectors.groupingBy(DeviceInformationDO::getDeviceType))
                .entrySet().stream()
                .map(v -> {
                    Integer key = v.getKey();
                    int number = v.getValue().size();
                    StatisticsInformationDTO statisticsInformationDTO = new StatisticsInformationDTO();
                    statisticsInformationDTO.setDeviceType(key);
                    statisticsInformationDTO.setNumber(number);
                    return statisticsInformationDTO;
                }).collect(Collectors.toList());

        return list;
    }

    @Override
    public List<DeviceInformationRespVO> getInformationList(DeviceInformationPageReqVO dto) {

        List<DeviceInformationDO> deviceInformationDOS = informationMapper.selectList(new LambdaQueryWrapper<DeviceInformationDO>()
                .like(dto.getDeviceNo() != null, DeviceInformationDO::getDeviceNo, dto.getDeviceNo())
                .eq(dto.getDeviceType() != null, DeviceInformationDO::getDeviceType, dto.getDeviceType())
        );

        if (ObjectUtil.isEmpty(deviceInformationDOS)) {
            return new ArrayList<>();
        }

        List<PositionMapDO> positionMapDOS = positionMapMapper.selectList(new LambdaQueryWrapperX<PositionMapDO>());
        Map<Long, PositionMapDO> positionMap =
                positionMapDOS.stream().collect(Collectors.toMap(v -> v.getId(), Function.identity()));

        List<DeviceInformationRespVO> beans = BeanUtils.toBean(deviceInformationDOS, DeviceInformationRespVO.class);
        // todo 需要设置设备通讯的时间
        for (DeviceInformationRespVO deviceInformationDO : beans) {

            PositionMapDO positionMapDO = positionMap.get(deviceInformationDO.getPositionMapId());
            if (ObjectUtil.isNotEmpty(deviceInformationDO.getPositionMapId())
                    && ObjectUtil.isNotEmpty(positionMapDO)) {
                deviceInformationDO.setFloor(positionMapDO.getFloor() + "");
                deviceInformationDO.setArea(positionMapDO.getArea());
                String map = positionMapDO.getFloor() + "层-" + positionMapDO.getArea();
                String deviceLocation = ObjectUtil.isEmpty(deviceInformationDO.getDeviceLocation()) ? map : map + deviceInformationDO.getDeviceLocation();
                deviceInformationDO.setDeviceLocation(deviceLocation);
            }

            String deviceKey = DeviceChcheConstant.DEVICE_LAST_TIME + deviceInformationDO.getMacAddress();
            Object object = redisUtil.get(deviceKey);
            if (ObjectUtil.isEmpty(object)) {
                deviceInformationDO.setDeviceStatus(DeviceStatusEnum.OFF_LINE.getType());
                continue;
            }
            try {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime curTimeLDT = LocalDateTime.parse((String) object, df);
                deviceInformationDO.setDeviceLastTime(curTimeLDT);
                deviceInformationDO.setDeviceStatus(DeviceStatusEnum.ON_LINE.getType());
            } catch (Exception e) {
                log.info("查询设备最后通讯时间异常 :{}", e.getMessage());
            }
        }

        return beans;
    }

    @Override
    public List<DeviceInformationDO> getDeviceInfoBindByMapId(Long positionMapId) {
        return informationMapper.selectList(new LambdaQueryWrapperX<DeviceInformationDO>()
                .eq(DeviceInformationDO::getPositionMapId, positionMapId)
                .isNotNull(DeviceInformationDO::getPositionMapItemId));
    }

    /**
     * 充电任务，让设备伸出
     *
     * @param deviceNo
     */
    @Override
    @Async
    public void chargeDeviceExtend(String deviceNo) {
        DeviceInformationDO deviceInformationDO = informationMapper.selectOne(new LambdaQueryWrapperX<DeviceInformationDO>()
                .eq(DeviceInformationDO::getDeviceNo, deviceNo));
        if (ObjectUtil.isEmpty(deviceInformationDO)) {
            log.info("查不到此充电设备 :{}", deviceNo);
            return;
        }
        if (DeviceAttributeEnum.HAND_MOVEMENT.getType().equals(deviceInformationDO.getDeviceAttribute())) {
            log.info("手动充电设备,不需要伸出 :{}", deviceNo);
            return;
        }
        if (!DeviceTypeEnum.CHARGING_STATION.getType().equals(deviceInformationDO.getDeviceType())) {
            log.info("非充电设备,不能伸出 :{}", deviceNo);
            return;
        }
        if (ObjectUtil.isEmpty(deviceInformationDO.getDeviceIp()) || ObjectUtil.isEmpty(deviceInformationDO.getDevicePort())) {
            log.info("没有设备IP、端口不能伸出 :{}", deviceNo);
            warnMsgService.addWarnMsg(deviceNo + " 没有设备IP和端口");
            return;
        }
        log.info("设备伸出 :{}", deviceNo);
        extend(deviceInformationDO.getDeviceIp(), Integer.parseInt(deviceInformationDO.getDevicePort()), deviceNo);
    }

    /**
     * 充电任务，缩
     *
     * @param deviceNo
     */
    @Override
    @Async
    public void chargeDeviceShrink(String deviceNo) {
        DeviceInformationDO deviceInformationDO = informationMapper.selectOne(new LambdaQueryWrapperX<DeviceInformationDO>()
                .eq(DeviceInformationDO::getDeviceNo, deviceNo));
        if (DeviceAttributeEnum.HAND_MOVEMENT.getType().equals(deviceInformationDO.getDeviceAttribute())) {
            log.info("手动充电设备,不需要缩 :{}", deviceNo);
            return;
        }
        if (!DeviceTypeEnum.CHARGING_STATION.getType().equals(deviceInformationDO.getDeviceType())) {
            log.info("非充电设备,不能缩回 :{}", deviceNo);
            return;
        }
        if (ObjectUtil.isEmpty(deviceInformationDO.getDeviceIp()) || ObjectUtil.isEmpty(deviceInformationDO.getDevicePort())) {
            log.info("没有设备IP、端口不能缩回 :{}", deviceNo);
            return;
        }
        log.info("设备缩回 :{}", deviceNo);
        shrink(deviceInformationDO.getDeviceIp(), Integer.parseInt(deviceInformationDO.getDevicePort()), deviceNo);
    }

    @Override
    public String getMapImageUrl(Integer deviceType) {
        Integer configType = DeviceTypeEnum.getConfigType(deviceType);
        if (ObjectUtil.isEmpty(configType)) {
            return "";
        }
        CommonConfigDO config = configService.getConfig(configType.longValue());
        if (ObjectUtil.isEmpty(config)) {
            return "";
        }
        return config.getConfigStr();
    }

    @Override
    public void deleteDeviceByMapId(Long mapId) {
        informationMapper.deleteDeviceByMapId(mapId);
    }

    @Override
    public String getCameraCode(Long id) throws Exception {
        DeviceInformationDO deviceInformationDO = informationMapper.selectById(id);
        if (ObjectUtil.isEmpty(deviceInformationDO.getCameraCode()) || !DeviceTypeEnum.CAMERA.getType().equals(deviceInformationDO.getDeviceType())) {
            return "";
        }

        return AESEncryptionUtil.decrypt(deviceInformationDO.getCameraCode(), znConfigConstant.getCameraSecretKey());
    }

    public void shrink(String ip, int port, String deviceNo) {
        boolean success = true;
        short[] shrinkArr = {0};
        for (int i = 0; i < 3; i++) {
            ModbusMaster asciiMaster = null;
            try {
                asciiMaster = ModbusUtils.getMaster(ip, port);
                ModbusUtils.writeHoldingRegisters(asciiMaster, 1, 0, shrinkArr);
            } catch (ModbusInitException | ModbusTransportException e) {
                log.info("充电设备缩回时,出现异常 :{}", ip);
                warnMsgService.addWarnMsg(deviceNo + " 充电设备缩回失败");
                success = false;
            } finally {
                if (ObjectUtil.isNotEmpty(asciiMaster)) {
                    asciiMaster.destroy();
                }
            }

            if (success) {
                return;
            }
        }
    }

    /**
     * 控制设备伸缩
     *
     * @param ip
     * @param port
     */
    public void extend(String ip, int port, String deviceNo) {
        boolean success = true;
        short[] extendArr = {1};
        short[] shrinkArr = {0};
        for (int i = 0; i < 3; i++) {
            ModbusMaster asciiMaster = null;
            try {
                asciiMaster = ModbusUtils.getMaster(ip, port);
                ModbusUtils.writeHoldingRegisters(asciiMaster, 1, 0, shrinkArr);
                Thread.sleep(2500);
                ModbusUtils.writeHoldingRegisters(asciiMaster, 1, 0, extendArr);
            } catch (ModbusInitException | ModbusTransportException | InterruptedException e) {
                log.info("充电设备伸出时,出现异常 :{}", ip);
                warnMsgService.addWarnMsg(deviceNo + " 充电设备伸出失败");
                success = false;
            } finally {
                if (ObjectUtil.isNotEmpty(asciiMaster)) {
                    asciiMaster.destroy();
                }
            }

            if (success) {
                return;
            }
        }
    }

    @Override
    public void mapBindDeviceInfo(MapBindDeviceInfoDTO dto) {
        DeviceInformationDO deviceInformationDO = informationMapper.selectById(dto.getDeviceInfoId());
        if (dto.getType() == 1) {
            deviceInformationDO.setPositionMapId(dto.getPositionMapId());
        } else {
            deviceInformationDO.setPositionMapId(null);
            deviceInformationDO.setPositionMapItemId(null);
        }
        informationMapper.updateById(deviceInformationDO);
    }
}
