package com.tykj.dev.device.packing.service.impl;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.tykj.dev.blockcha.subject.entity.BcHash;
import com.tykj.dev.blockcha.subject.service.BlockChainUtil;
import com.tykj.dev.config.TaskBeanConfig;
import com.tykj.dev.config.cache.ConfigCache;
import com.tykj.dev.device.library.repository.DeviceLibraryDao;
import com.tykj.dev.device.library.service.DeviceLibraryService;
import com.tykj.dev.device.library.subject.domin.DeviceLibrary;
import com.tykj.dev.device.library.subject.vo.Script;
import com.tykj.dev.device.packing.repository.PackingLibraryDao;
import com.tykj.dev.device.packing.service.PackingLibraryService;
import com.tykj.dev.device.packing.service.PackingLogService;
import com.tykj.dev.device.packing.subject.domin.PackingLibrary;
import com.tykj.dev.device.packing.subject.domin.PackingLog;
import com.tykj.dev.device.packing.subject.vo.AllotSeqs;
import com.tykj.dev.device.packing.subject.vo.PackingLibrarySelectVo;
import com.tykj.dev.device.packing.subject.vo.SelectPack;
import com.tykj.dev.device.user.read.service.MessageService;
import com.tykj.dev.device.user.read.subject.bto.MessageBto;
import com.tykj.dev.device.user.subject.service.UserPublicService;
import com.tykj.dev.device.user.util.UserUtils;
import com.tykj.dev.misc.exception.ApiException;
import com.tykj.dev.misc.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.persistence.Transient;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author dengdiyi
 */
@Service
public class PackingLibraryServiceImpl implements PackingLibraryService {

    @Autowired
    private PackingLibraryDao packingLibraryDao;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private BlockChainUtil blockChainUtil;

    @Autowired
    private DeviceLibraryService deviceLibraryService;

    @Autowired
    private DeviceLibraryDao deviceLibraryDao;

    @Autowired
    private ConfigCache configCache;

    @Autowired
    private PackingLogService packingLogService;

    @Autowired
    private UserPublicService userPublicService;

    @Autowired
    private MessageService messageService;

    @Override
    public PackingLibrary addEntity(PackingLibrary packingLibraryEntity) {
        PackingLibrary packingLibrary = packingLibraryDao.save(packingLibraryEntity);
        CompletableFuture.runAsync(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            PackingLibrary packingLibrary1 = getOne(packingLibrary.getId());
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(getOne(packingLibrary.getId())));
            String recordId = bcText.getData().getRecordID();
            packingLibrary1.setRecordId(recordId);
            packingLibraryDao.save(packingLibrary1);
        });
        return packingLibrary;
    }

    /**
     * @param packingLibraries 列装异步上链
     */
    @Override
    @Async
    public void sendHash(List<PackingLibrary> packingLibraries) {
        packingLibraries.forEach(packingLibrary -> {
            BcHash bcText = blockChainUtil.sendHash(1000, JacksonUtil.toJSon(packingLibrary));
            String recordId = bcText.getData().getRecordID();
            packingLibrary.setRecordId(recordId);
            update(packingLibrary);
        });
    }

    @Override
    public Page<PackingLibrary> getPage(PackingLibrarySelectVo packingLibrarySelectVo, Pageable pageable) {
        return packingLibraryDao.findAll(getSelectSpecification5(packingLibrarySelectVo), pageable);
    }

    @Override
    public List<PackingLibrary> getInvalidPage(PackingLibrarySelectVo packingLibrarySelectVo, Pageable pageable) {
        List<PackingLibrary> packingLibraryEntities = packingLibraryDao.findAll(getSelectSpecification2(packingLibrarySelectVo),pageable.getSort());
        packingLibraryEntities.forEach(PackingLibrary::setConfigName);
        //返回父子结构
        Map<Integer, PackingLibrary> nodeCollect =
                packingLibraryEntities.stream().collect(Collectors.toMap(PackingLibrary::getId, packingLibrary -> packingLibrary));
        return GetTreeUtils.parseTreeFromDown(
                packingLibraryEntities,
                PackingLibrary::getId,
                packingLibrary -> Optional.ofNullable(nodeCollect.get(packingLibrary.getPartParentId())),
                PackingLibrary::addChildNode
        );
    }

    @Override
    public List<PackingLibrary> getList(PackingLibrarySelectVo packingLibrarySelectVo) {
        List<PackingLibrary> packingLibraryEntities = packingLibraryDao.findAll(getSelectSpecification(packingLibrarySelectVo));
        packingLibraryEntities.forEach(PackingLibrary::setConfigName);
        //返回父子结构
        Map<Integer, PackingLibrary> nodeCollect =
                packingLibraryEntities.stream().collect(Collectors.toMap(PackingLibrary::getId, packingLibraryEntity -> packingLibraryEntity));
        return GetTreeUtils.parseTreeFromDown(
                packingLibraryEntities,
                PackingLibrary::getId,
                packingLibraryEntity -> Optional.ofNullable(nodeCollect.get(packingLibraryEntity.getPartParentId())),
                PackingLibrary::addChildNode
        );
    }

    @Override
    public List<Integer> getTypeList() {
        List<PackingLibrary> list = packingLibraryDao.findAll();
        Set<Integer> s = new HashSet<>();
        for (PackingLibrary d : list) {
            s.add(d.getType());
        }
        return new ArrayList<>(s);
    }

    @Override
    public List<String> getModelList() {
        List<PackingLibrary> list = packingLibraryDao.findAllByIsRootAndPackingStatus(1,2);
        Set<String> s = new HashSet<>();
        for (PackingLibrary d : list) {
            s.add(d.getModel());
        }
        return new ArrayList<>(s);
    }

    @Override
    public List<PackingLibrary> selectAllPart(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("isPart", 1);
        predicateBuilder.eq("partParentId", id);
        return packingLibraryDao.findAll(predicateBuilder.build());
    }

    @Override
    public PackingLibrary update(PackingLibrary packingLibraryEntity) {
        PackingLibrary packingLibrary = packingLibraryDao.save(packingLibraryEntity);
        CompletableFuture.runAsync(()-> blockChainUtil.appendHash(JacksonUtil.toJSon(packingLibrary),packingLibrary.getRecordId()), TaskBeanConfig.getThreadPoolTaskScheduler());
        return packingLibrary;
    }

    @Override
    public PackingLibrary getOne(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        } else {
            return byId.get().setConfigName();
        }
    }

    @Override
    public List<PackingLibrary> getPackingDetail(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        } else {
            //添加主件
            List<PackingLibrary> libraryEntities = new ArrayList<>();
            libraryEntities.add(byId.get().setConfigName());
            //添加配件信息
            List<PackingLibrary> p = packingLibraryDao.findAll(getSelectSpecification3(id));
            p.forEach(PackingLibrary::setConfigName);
            libraryEntities.addAll(p);
            return libraryEntities;
        }
    }

    @Override
    public List<PackingLibrary> getInvalidDetail(Integer id) {
        Optional<PackingLibrary> byId = packingLibraryDao.findById(id);
        if (!byId.isPresent()) {
            throw new ApiException(ResultUtil.failed("id不存在"));
        } else {
            //添加主件
            List<PackingLibrary> libraryEntities = new ArrayList<>();
            libraryEntities.add(byId.get().setConfigName());
            //添加配件信息
            List<PackingLibrary> p = packingLibraryDao.findAll(getSelectSpecification4(id));
            p.forEach(PackingLibrary::setConfigName);
            libraryEntities.addAll(p);
            return libraryEntities;
        }
    }

    @Override
    public void delete(Integer id) {
        PackingLibrary packingLibrary = getOne(id);
        packingLibrary.setPackingStatus(4);
//        packingLibrary.setExitTime(Timestamp.from(new Date().toInstant()));
        if (packingLibrary.getIsRoot()==1) {
            packingLibrary.setShowOrder(9999);
        }
        update(packingLibrary);
        //添加列装日志
        PackingLog packingLog = new PackingLog();
        packingLog.setRemark("手动删除列装");
        packingLog.setPackingId(id);
        packingLogService.add(packingLog);
    }

    /**
     * @param selectPack 列装查询vo
     *                   获取父子结构列装列表
     */
    @Override
    public List<PackingLibrary> getInsertList(SelectPack selectPack) {
        final String model = selectPack.getModel();
        final String content = selectPack.getContent();
        final String name = selectPack.getName();
        final Integer status = selectPack.getStatus();
        final Integer secretLevel = selectPack.getSecretLevel();
        List<PackingLibrary> packingLibraryEntities = packingLibraryDao.findAll(getSelectSpecification6()).stream().sorted(Comparator.comparing(PackingLibrary::getName)).collect(Collectors.toList());
//                .stream().filter(packingLibrary -> {
//            boolean isSameModel = model == null || packingLibrary.getModel().equals(model);
//            boolean isSameName = name == null || packingLibrary.getName().equals(name);
//            boolean isSameStatus = status == null || packingLibrary.getStatus().equals(status);
//            boolean isSameSecretLevel = secretLevel == null || packingLibrary.getSecretLevel().equals(secretLevel);
//            boolean isContainContent = content == null
//                    || packingLibrary.getModel().contains(content)
//                    || configCache.getInvisibleRangeMap().get(packingLibrary.getInvisibleRange()).contains(content)
//                    || configCache.getSecretLevelMap().get(packingLibrary.getSecretLevel()).contains(content);
//            return isSameModel && isSameName && isSameStatus && isSameSecretLevel && isContainContent;
//        }).collect(Collectors.toList());
        packingLibraryEntities.forEach(PackingLibrary::setConfigName);
        //返回父子结构
        Map<Integer, PackingLibrary> nodeCollect =
                packingLibraryEntities.stream().collect(Collectors.toMap(PackingLibrary::getId, packingLibrary -> packingLibrary));
        return GetTreeUtils.parseTreeFromDown(
                packingLibraryEntities,
                PackingLibrary::getId,
                packingLibrary -> Optional.ofNullable(nodeCollect.get(packingLibrary.getPartParentId())),
                PackingLibrary::addChildNode
        ).stream().filter(packingLibrary -> {
            boolean isSameModel = model == null || packingLibrary.getModel().equals(model);
            boolean isSameName = name == null || packingLibrary.getName().equals(name);
            boolean isSameStatus = status == null || packingLibrary.getStatus().equals(status);
            boolean isSameSecretLevel = secretLevel == null || packingLibrary.getSecretLevel().equals(secretLevel);
            boolean isContainContent = content == null
                    || packingLibrary.getModel().contains(content)
                    || configCache.getInvisibleRangeMap().get(packingLibrary.getInvisibleRange()).contains(content)
                    || configCache.getSecretLevelMap().get(packingLibrary.getSecretLevel()).contains(content);
            return isSameModel && isSameName && isSameStatus && isSameSecretLevel && isContainContent;
        }).sorted(Comparator.comparing(PackingLibrary::getShowOrder,Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList());
    }

    /**
     * @param id 列装主键id
     *           通过id逻辑删除该列装以及所有子列装
     */
    @Override
    @Transient
    public void deleteAll(Integer id) {
        PackingLibrary packingLibrary = getOne(id);
        if (deviceLibraryDao.getAllByPackingId(id).size()>0){
            throw new ApiException(ResponseEntity.status(303).body("该列装型号已有装备,请进行退装操作"));
        }
        if (packingLibrary.getIsRoot()==1) {
            if (packingLibraryDao.findAllByPartParentIdAndPackingStatus(id,2).size()>0){
                throw new ApiException(ResponseEntity.status(303).body("该列装型号目录下存在列装装备"));
            }
            Integer order = packingLibrary.getShowOrder();
            getInsertList(new SelectPack()).forEach(packingLibrary1 -> {
                if (packingLibrary1.getShowOrder() > order) {
                    packingLibrary1.setShowOrder(packingLibrary1.getShowOrder() - 1);
                    update(packingLibrary1);
                }
            });
        }
        List<Integer> ids = packingLibraryDao.findAllByPartParentId(id).stream().map(PackingLibrary::getId).collect(Collectors.toList());
        delete(id);
        if (ids.size()>0){
            ids.forEach(integer -> {
                if (deviceLibraryDao.getAllByPackingId(integer).size()>0){
                    throw new ApiException(ResponseEntity.status(303).body("该列装型号已有装备,请进行退装操作"));
                }
                deleteAll(integer);
            });
        }
        //发送阅知信息
        List<Integer> userIds = userPublicService.findOtherUser(userUtils.getCurrentUserId());
        MessageBto messageBto = new MessageBto(0,1,"手动删除列装",userIds,0);
        messageBto.setRecord(id.toString());
        messageService.add(messageBto);
    }

    /**
     * @param ids 列装主键id列表
     *            通过id将退装装备恢复到列装
     */
    @Override
    public void removeAll(List<Integer> ids) {
        for (Integer id:ids){
            PackingLibrary packingLibrary = getOne(id);
            packingLibrary.setPackingStatus(2);
            update(packingLibrary);
            //添加列装日志
            PackingLog packingLog = new PackingLog();
            packingLog.setRemark("恢复列装");
            packingLog.setPackingId(id);
            packingLogService.add(packingLog);
        }
        //发送阅知信息
        List<Integer> userIds = userPublicService.findOtherUser(userUtils.getCurrentUserId());
        MessageBto messageBto = new MessageBto(0,1,"恢复列装",userIds,0);
        messageBto.setRecord(StringSplitUtil.idListToString(ids));
        messageService.add(messageBto);
    }

    /**
     * @param ids 列装主键id列表
     *            通过id将回收站装备清空删除
     */
    @Override
    public void cleanAll(List<Integer> ids) {
        for (Integer id:ids){
            PackingLibrary packingLibrary = getOne(id);
            packingLibrary.setDeleteTag(1);
            update(packingLibrary);
            //添加列装日志
            PackingLog packingLog = new PackingLog();
            packingLog.setRemark("回收站清空列装");
            packingLog.setPackingId(id);
            packingLogService.add(packingLog);
        }
        //发送阅知信息
        List<Integer> userIds = userPublicService.findOtherUser(userUtils.getCurrentUserId());
        MessageBto messageBto = new MessageBto(0,1,"回收站清空列装",userIds,0);
        messageBto.setRecord(StringSplitUtil.idListToString(ids));
        messageService.add(messageBto);
    }

    /**
     * 设置顺序的排序
     */
    @Override
    public List<PackingLibrary> setOrder(List<PackingLibrary> packingLibraries) {
        List<PackingLibrary> packingLibraryList = new ArrayList<>();
        for (int i =1;i<=packingLibraries.size();i++){
            PackingLibrary packingLibrary = packingLibraries.get(i-1);
            packingLibrary.setShowOrder(i);
            packingLibraryList.add(packingLibrary);
            update(packingLibrary);
        }
        return packingLibraryList;
    }

    @Override
    public List<Script> getDevcieScript(List<Integer> ids) {
        Map<Integer,DeviceLibrary> deviceLibraryMap = deviceLibraryService.getAllDeviceMap();
        List<Script> scripts = new ArrayList<>();
        List<DeviceLibrary> deviceLibraries = new ArrayList<>();
        ids.forEach(integer -> deviceLibraries.add(deviceLibraryMap.get(integer)));
        Map<Integer, List<DeviceLibrary>> map = deviceLibraries.stream().collect(groupingBy(DeviceLibrary::getPackingId));
        for (Integer packingId:map.keySet()){
            List<DeviceLibrary> deviceLibraryList = map.get(packingId);
            PackingLibrary packingLibrary = getOne(packingId);
            Script script = new Script();
            script.setId(packingId);
            script.setPartParentId(packingLibrary.getPartParentId());
            script.setInvisibleRange(packingLibrary.getInvisibleRangeName());
            script.setModel(packingLibrary.getModel());
            script.setName(packingLibrary.getName());
            script.setSecretLevel(packingLibrary.getSecretLevelName());
            script.setType(packingLibrary.getTypeName());
            script.setNum(deviceLibraryList.size());
            script.setSeqNumber(StringSplitUtil.stringListToString(DeviceSeqUtil.getContinuousSeqs(deviceLibraryList.stream().map(DeviceLibrary::getSeqNumber).collect(Collectors.toList()))));
            scripts.add(script);
        }
        Map<Integer, Script> nodeCollect =
                scripts.stream().collect(Collectors.toMap(Script::getId, script -> script));
        List<Script> scriptList = new ArrayList<>();
        List<Script> conList = GetTreeUtils.parseTreeFromDown(
                scripts,
                Script::getId,
                script -> Optional.ofNullable(nodeCollect.get(script.getPartParentId())),
                Script::addChildNode
        );
        for (Script s:conList) {
            addScript(scriptList,s);
        }
        return scriptList;
    }

    @Override
    public List<Script> getDevcieAllotScript(List<Integer> ids) {
        Map<Integer,DeviceLibrary> deviceLibraryMap = deviceLibraryService.getAllDeviceMap();
        List<Script> scripts = new ArrayList<>();
        List<DeviceLibrary> deviceLibraries = new ArrayList<>();
        ids.forEach(integer -> deviceLibraries.add(deviceLibraryMap.get(integer)));
        Map<Integer, List<DeviceLibrary>> map = deviceLibraries.stream().collect(groupingBy(DeviceLibrary::getPackingId));
        for (Integer packingId:map.keySet()){
                List<DeviceLibrary> deviceLibraryList = map.get(packingId);
                PackingLibrary packingLibrary = getOne(packingId);
                packingLibrary.setConfigName();
                Script script = new Script();
                script.setId(packingId);
                script.setPartParentId(packingLibrary.getPartParentId());
                script.setInvisibleRange(packingLibrary.getInvisibleRangeName());
                script.setModel(packingLibrary.getModel());
                script.setName(packingLibrary.getName());
                script.setSecretLevel(packingLibrary.getSecretLevelName());
                script.setType(packingLibrary.getTypeName());
                script.setNum(deviceLibraryList.size());
                script.setAllotType(packingLibrary.getMatchingRangeName());
                script.setAllotTypeNum(packingLibrary.getMatchingRange());
                script.setSeqNumber(StringSplitUtil.stringListToString(DeviceSeqUtil.getContinuousSeqs(deviceLibraryList.stream().map(DeviceLibrary::getSeqNumber).collect(Collectors.toList()))));
                scripts.add(script);
        }
        Map<Integer, Script> nodeCollect =
                scripts.stream().collect(Collectors.toMap(Script::getId, script -> script));
        List<Script> scriptList = new ArrayList<>();
        List<Script> conList = GetTreeUtils.parseTreeFromDown(
                scripts,
                Script::getId,
                script -> Optional.ofNullable(nodeCollect.get(script.getPartParentId())),
                Script::addChildNode
        );
        for (Script s:conList) {
            addScript(scriptList,s);
        }
        scriptList.forEach(script -> script.setChilds(null));
        return scriptList;
    }

    private void addScript(List<Script> scripts,Script script){
        scripts.add(script);
        if (script.getChilds()!=null&&script.getChilds().size()>0){
            script.getChilds().forEach(s -> addScript(scripts,s));
        }
    }

    /**
     * @param packingId 列装id
     * @param num       配发数量
     * @return 自动选择装备生成的序列号区间
     * 配发按照序列号排序自动选择装备
     */
    @Override
    public AllotSeqs getAllotAutoSeqs(Integer packingId, Integer num) {
        AllotSeqs allotSeqs = new AllotSeqs();
        PredicateBuilder<DeviceLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("ownUnit", userUtils.getCurrentUserUnitName());
        predicateBuilder.eq("lifeStatus", 2);
        predicateBuilder.eq("packingId", packingId);
        List<DeviceLibrary> deviceLibraries = deviceLibraryDao.findAll(predicateBuilder.build()).stream().sorted(Comparator.comparing(DeviceLibrary::getSeqNumber,Comparator.nullsLast(String::compareTo))).collect(Collectors.toList());
        List<String> seqs = deviceLibraries.stream().map(DeviceLibrary::getSeqNumber).collect(Collectors.toList());
        if (seqs.size()>=num) {
            allotSeqs.setStrings(Collections.singletonList(StringSplitUtil.stringListToString(DeviceSeqUtil.getContinuousSeqs(seqs.subList(0, num)))));
            allotSeqs.setIds(deviceLibraries.subList(0,num).stream().map(DeviceLibrary::getId).collect(Collectors.toList()));
            return allotSeqs;
        }
        else {
            throw new ApiException("选择数量大于在库数量");
        }
    }

    @Override
    public Integer getAllotNum(Integer packingId) {
        PredicateBuilder<DeviceLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("ownUnit", userUtils.getCurrentUserUnitName());
        predicateBuilder.eq("lifeStatus", 2);
        predicateBuilder.eq("packingId", packingId);
        return deviceLibraryDao.findAll(predicateBuilder.build()).size();
    }

    @Override
    public List<PackingLibrary> setAllotNum(List<PackingLibrary> packingLibraries) {
        List<PackingLibrary> result = new ArrayList<>();
        packingLibraries.forEach(packingLibrary -> {
            packingLibrary.setDevNum(getAllotNum(packingLibrary.getId()));
            if (packingLibrary.getIsPart()==1){
                packingLibrary.setName("[附件]"+packingLibrary.getName());
            }
            result.add(packingLibrary);
            if (packingLibrary.getChilds()!=null&&packingLibrary.getChilds().size()>0){
                result.addAll(setAllotNum(packingLibrary.getChilds()));
            }
        });
        return result;
    }

    @Override
    public List<DeviceLibrary> getAllDevSeqs(Integer packingId) {
        PredicateBuilder<DeviceLibrary> predicateBuilder = Specifications.and();
//        predicateBuilder.eq("ownUnit", userUtils.getCurrentUserUnitName());
//        predicateBuilder.eq("lifeStatus", 2);
        predicateBuilder.eq("packingId", packingId);
        return deviceLibraryDao.findAll(predicateBuilder.build());
    }

    @Override
    public Boolean modelIsExist(String model) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("isRoot", 1);
        predicateBuilder.eq("model", model);
        return packingLibraryDao.findAll(predicateBuilder.build()).size()>0;
    }

    /**
     * @param id 列装主键id
     *           通过id修改该列装所有子列装型号
     */
    @Override
    public void changeAllModel(Integer id,String model) {
        PackingLibrary packingLibrary = getOne(id);
        //添加列装日志
        PackingLog packingLog = new PackingLog();
        packingLog.setRemark("将型号从"+packingLibrary.getModel()+"改为"+model);
        packingLog.setPackingId(id);
        packingLogService.add(packingLog);
        packingLibrary.setModel(model);
        update(packingLibrary);
        List<Integer> ids = packingLibraryDao.findAllByPartParentId(id).stream().map(PackingLibrary::getId).collect(Collectors.toList());
        ids.forEach(integer -> changeAllModel(integer,model));
    }

    @Override
    public Boolean nameIsExist(String model, String name) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("isRoot", 0);
        predicateBuilder.eq("model", model);
        predicateBuilder.eq("name", name);
        return packingLibraryDao.findAll(predicateBuilder.build()).size()>0;
    }

    @Override
    public Boolean matchingRangeIsExist(Integer parentId,Integer matchingRange) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("isRoot", 0);
        predicateBuilder.eq("partParentId", parentId);
        predicateBuilder.eq("matchingRange", matchingRange);
        return packingLibraryDao.findAll(predicateBuilder.build()).size()>0;
    }

    /**
     * @param parentId 父列装id
     * @param matchingRange 配用范围
     * 查询对应横向或纵向列装
     */
    @Override
    public PackingLibrary findSamePacking(Integer parentId,Integer matchingRange) {
        List<PackingLibrary> packingLibraries = packingLibraryDao.findAllByPartParentIdAndMatchingRange(parentId,matchingRange);
        if (packingLibraries.isEmpty()){
            return null;
        }
        else {
            return packingLibraries.get(0);
        }
    }

    /**
     * @param packingLibraries 父子结构列装
     *                         拆分父子结构列装
     */
    @Override
    public List<PackingLibrary> splitTree(List<PackingLibrary> packingLibraries) {
        List<PackingLibrary> resultList = new ArrayList<>();
        for (PackingLibrary p:packingLibraries){
            resultList.add(p);
            if (p.getChilds()!=null&&p.getChilds().size()>0){
                resultList.addAll(splitTree(p.getChilds()));
            }
        }
        return resultList;
    }

    private Specification<PackingLibrary> getSelectSpecification(PackingLibrarySelectVo packingLibrarySelectVo) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        Integer level = userUtils.getCurrentUnitLevel();
        if (level == 2) {
            predicateBuilder.in("invisibleRange", new Integer[]{2, 3});
        }
        if (level == 3) {
            predicateBuilder.eq("invisibleRange", 3);
        }
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel() != null) {
                predicateBuilder.eq("model", packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType() != null) {
                predicateBuilder.eq("type", packingLibrarySelectVo.getType());
            }
            if (packingLibrarySelectVo.getSecretLevel() != null) {
                predicateBuilder.eq("secretLevel", packingLibrarySelectVo.getSecretLevel());
            }
            if (packingLibrarySelectVo.getInvisibleRange() != null) {
                predicateBuilder.eq("invisibleRange", packingLibrarySelectVo.getInvisibleRange());
            }
            if (packingLibrarySelectVo.getName() != null) {
                predicateBuilder.eq("name", packingLibrarySelectVo.getName());
            }
        }
        predicateBuilder.eq("packingStatus", 2);
        predicateBuilder.eq("isRoot",0);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification2(PackingLibrarySelectVo packingLibrarySelectVo) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        Integer level = userUtils.getCurrentUnitLevel();
        if (level == 2) {
            predicateBuilder.in("invisibleRange", new Integer[]{2, 3});
        }
        if (level == 3) {
            predicateBuilder.eq("invisibleRange", 3);
        }
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel() != null) {
                predicateBuilder.eq("model", packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType() != null) {
                predicateBuilder.eq("type", packingLibrarySelectVo.getType());
            }
            if (packingLibrarySelectVo.getSecretLevel() != null) {
                predicateBuilder.eq("secretLevel", packingLibrarySelectVo.getSecretLevel());
            }
            if (packingLibrarySelectVo.getInvisibleRange() != null) {
                predicateBuilder.eq("invisibleRange", packingLibrarySelectVo.getInvisibleRange());
            }
            if (packingLibrarySelectVo.getPackingStatus()!=null){
                predicateBuilder.eq("packingStatus", packingLibrarySelectVo.getPackingStatus());
            }
            else {
                predicateBuilder.eq("packingStatus", 3);
            }
        }
//        predicateBuilder.eq("isPart", 0);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification3(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("packingStatus", 2);
        predicateBuilder.eq("isPart", 1);
        predicateBuilder.eq("partParentId", id);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification4(Integer id) {
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        predicateBuilder.eq("packingStatus", 3);
        predicateBuilder.eq("isPart", 1);
        predicateBuilder.eq("partParentId", id);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification5(PackingLibrarySelectVo packingLibrarySelectVo) {
        Integer level = userUtils.getCurrentUnitLevel();
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        if (level == 2) {
            predicateBuilder.in("invisibleRange", new Integer[]{2, 3});
        }
        if (level == 3) {
            predicateBuilder.eq("invisibleRange", 3);
        }
        if (packingLibrarySelectVo != null) {
            if (packingLibrarySelectVo.getContent() != null) {
                Class<PackingLibrary> packingLibraryEntityClass = PackingLibrary.class;
                Field[] declaredFields = packingLibraryEntityClass.getDeclaredFields();
                PredicateBuilder<PackingLibrary> p = Specifications.or();
                for (Field field : declaredFields) {
                    if (field.getType().equals(String.class) && field.getAnnotation(Transient.class) == null) {
                        p.like(field.getName(), "%" + packingLibrarySelectVo.getContent() + "%");
                    }
                }
                predicateBuilder.predicate(p.build());
            }
            if (packingLibrarySelectVo.getStartTime() != null) {
                predicateBuilder.gt("createTime", packingLibrarySelectVo.getStartTime());
            }
            if (packingLibrarySelectVo.getEndTime() != null) {
                predicateBuilder.lt("updateTime", packingLibrarySelectVo.getEndTime());
            }
            if (packingLibrarySelectVo.getModel() != null) {
                predicateBuilder.eq("model", packingLibrarySelectVo.getModel());
            }
            if (packingLibrarySelectVo.getType() != null) {
                predicateBuilder.eq("type", packingLibrarySelectVo.getType());
            }
            if (packingLibrarySelectVo.getSecretLevel() != null) {
                predicateBuilder.eq("secretLevel", packingLibrarySelectVo.getSecretLevel());
            }
            if (packingLibrarySelectVo.getInvisibleRange() != null) {
                predicateBuilder.eq("invisibleRange", packingLibrarySelectVo.getInvisibleRange());
            }
            if (packingLibrarySelectVo.getName() != null) {
                predicateBuilder.eq("name", packingLibrarySelectVo.getName());
            }
        }
        predicateBuilder.eq("packingStatus", 2);
        predicateBuilder.eq("isPart", 0);
        return predicateBuilder.build();
    }

    private Specification<PackingLibrary> getSelectSpecification6(){
        Integer level = userUtils.getCurrentUnitLevel();
        PredicateBuilder<PackingLibrary> predicateBuilder = Specifications.and();
        if (level == 2) {
            predicateBuilder.in("invisibleRange", new Integer[]{2, 3});
        }
        if (level == 3) {
            predicateBuilder.eq("invisibleRange", 3);
        }
        predicateBuilder.eq("packingStatus", 2);
        return predicateBuilder.build();
    }
}
