package com.bocloud.ims.service.transportor;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.F5BasicObject;
import com.bocloud.cmp.entity.enums.F5RetainedData;
import com.bocloud.cmp.model.f5.*;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.f5.*;
import com.bocloud.ims.repository.resource.f5.*;
import com.bocloud.ims.service.utils.BigIpHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * F5负载均衡同步类
 *
 * @author liuyuanyuan
 */
public class F5Transportor {

    private static Logger logger = LoggerFactory.getLogger(F5Transportor.class);
    private F5BiNodeRepository f5BiNodeRepository;
    private F5BiProfileRepository f5BiProfileRepository;
    private F5BiMonitorRepository f5BiMonitorRepository;
    private F5BiPoolRepository f5BiPoolRepository;
    private F5BiPoolMemberRepository f5BiPoolMemberRepository;
    private F5BiVirtualServerRepository f5BiVirtualServerRepository;
    private F5BiIRulesRepository f5BiIRulesRepository;
    private F5BiDnsResolversRepository f5BiDnsResolversRepository;
    private F5BiSnatPoolRepository f5BiSnatPoolRepository;
    private F5BiVlanRepository f5biVlanRepository;
    private F5BiTunnelRepository f5BiTunnelRepository;
    private F5BiPartitionRepository f5biPartitionRepository;
    private Map<Long, String> cachePartitionById;
    private Map<String, BiPartition> cachePartitionByNameAndVendor;
    private F5BiDataGroupRepository f5BiDataGroupRepository;

    public F5Transportor() {
        super();
    }

    public F5Transportor(F5BiNodeRepository f5BiNodeRepository, F5BiProfileRepository f5BiProfileRepository, F5BiMonitorRepository f5BiMonitorRepository,
                         F5BiPoolRepository f5BiPoolRepository, F5BiPoolMemberRepository f5BiPoolMemberRepository, F5BiVirtualServerRepository f5BiVirtualServerRepository,
                         F5BiIRulesRepository f5BiIRulesRepository, F5BiDnsResolversRepository f5BiDnsResolversRepository, F5BiSnatPoolRepository f5BiSnatPoolRepository,
                         F5BiVlanRepository f5biVlanRepository, F5BiTunnelRepository f5BiTunnelRepository, F5BiPartitionRepository f5biPartitionRepository,
                         F5BiDataGroupRepository f5BiDataGroupRepository) {
        super();
        this.f5BiNodeRepository = f5BiNodeRepository;
        this.f5BiProfileRepository = f5BiProfileRepository;
        this.f5BiMonitorRepository = f5BiMonitorRepository;
        this.f5BiPoolRepository = f5BiPoolRepository;
        this.f5BiPoolMemberRepository = f5BiPoolMemberRepository;
        this.f5BiVirtualServerRepository = f5BiVirtualServerRepository;
        this.f5BiIRulesRepository = f5BiIRulesRepository;
        this.f5BiDnsResolversRepository = f5BiDnsResolversRepository;
        this.f5BiSnatPoolRepository = f5BiSnatPoolRepository;
        this.f5biVlanRepository = f5biVlanRepository;
        this.f5BiTunnelRepository = f5BiTunnelRepository;
        this.f5biPartitionRepository = f5biPartitionRepository;
        this.f5BiDataGroupRepository = f5BiDataGroupRepository;
    }

    public BocloudResult sync(CloudVendor vendor, Object data, Long userId) {
        try {
            Long vendorId = vendor.getId();
            String content = JSONObject.toJSONString(data);
            F5SyncModel model = JSONObject.parseObject(content, F5SyncModel.class);
            // 同步partition
            logger.info("Starting sync partition......");
            this.syncPartition(model.getPartitionModels(), vendorId, userId);
            logger.info("End sync partition......");
            // 查出所有分区作为缓存数据
            cachePartition(vendorId);
            //同步数据组
            logger.info("Starting sync data group......");
            this.syncDataGroup(model.getDataGroupModels(), vendorId, userId);
            logger.info("End sync data group......");
            // 同步tunnel
            logger.info("Starting sync tunnel......");
            this.syncTunnel(model.getTunnelModels(), vendorId, userId);
            logger.info("End sync tunnel......");
            // 同步vlan
            logger.info("Starting sync vlan......");
            this.syncVlan(model.getVlanModels(), vendorId, userId);
            logger.info("End sync vlan......");
            // 同步 地址转换 AddressTranslation
            logger.info("Starting sync Address Translation......");
            this.syncAddressTranslation(model.getSnantPoolModels(), vendorId, userId);
            logger.info("End sync Address Translation......");
            // 同步dns resolvers
            logger.info("Starting sync dns resolvers......");
            this.syncdnsResolvers(model.getDnsResolversModels(), vendorId, userId);
            logger.info("End sync dns resolvers......");
            // 同步rule
            logger.info("Starting sync rule......");
            this.syncRule(model.getRuleModels(), vendorId, userId);
            logger.info("End sync rule......");
            // 同步monitor
            logger.info("Starting sync monitor......");
            this.syncMonitor(model.getMonitorModels(), vendorId, userId);
            logger.info("End sync monitor......");
            // 同步node
            logger.info("Starting sync node......");
            this.syncNode(model.getNodeModels(), vendorId, userId);
            logger.info("End sync node......");
            // 同步profile
            logger.info("Starting sync profile......");
            this.syncProfile(model.getProfileModels(), vendorId, userId);
            logger.info("End sync profile......");
            // 同步pool
            logger.info("Starting sync pool......");
            this.syncPool(model.getPoolModels(), vendorId, userId);
            logger.info("End sync pool......");
            // 同步virtual server
            logger.info("Starting sync virtual server......");
            this.syncVirtualServer(model.getVirtualServerModels(), vendor, userId);
            logger.info("End sync virtual server......");
        } catch (Exception e) {
            logger.error("Sync F5 error:{}", e);
            return new BocloudResult(false, "同步F5负载均衡数据失败");
        }
        return new BocloudResult(true, "同步F5负载均衡数据成功");
    }

    private void syncDataGroup(List<DataGroupModel> dataGroupModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(dataGroupModels)) {
            f5BiDataGroupRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiDataGroup> dataGroups = f5BiDataGroupRepository.list(vendorId);
        Map<String, BiDataGroup> mapBiDataGroup = new HashMap<String, BiDataGroup>();
        for (BiDataGroup biDataGroup : dataGroups) {
            mapBiDataGroup.put(biDataGroup.getName(), biDataGroup);
        }
        for (DataGroupModel model : dataGroupModels) {
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            BiDataGroup biDataGroup = new BiDataGroup();
            if (mapBiDataGroup.containsKey(model.getName())) {
                biDataGroup = mapBiDataGroup.get(model.getName());
                biDataGroup.setVendorId(vendorId);
                biDataGroup.setPartitionId(partition.getId());
                BeanUtils.copyProperties(biDataGroup, model);
                if (null != model.getRecords()) {
                    biDataGroup.setRecords(model.getRecords().toString());
                } else {
                    biDataGroup.setRecords(new ArrayList<>().toString());
                }
                f5BiDataGroupRepository.update(biDataGroup);
                mapBiDataGroup.remove(model.getName());
            } else {
                BeanUtils.copyProperties(biDataGroup, model);
                biDataGroup.setRecords(model.getRecords().toString());
                biDataGroup.setVendorId(vendorId);
                biDataGroup.setPartitionId(partition.getId());
                f5BiDataGroupRepository.save(biDataGroup);
                mapBiDataGroup.remove(model.getName());
            }
        }
        for (String keyset : mapBiDataGroup.keySet()) {
            f5BiDataGroupRepository.remove(mapBiDataGroup.get(keyset).getId(), userId);
        }
    }

    /**
     * 缓存分区数据，减少查询数据库次数
     */
    private void cachePartition(Long vendorId) throws Exception {
        cachePartitionById = Maps.newHashMap();
        cachePartitionByNameAndVendor = Maps.newHashMap();
        List<BiPartition> partitions = f5biPartitionRepository.list(vendorId);
        for (BiPartition biPartition : partitions) {
            cachePartitionById.put(biPartition.getId(), biPartition.getName());
            cachePartitionByNameAndVendor.put(
                    BigIpHelper.partitionCode(String.valueOf(biPartition.getVendorId()), biPartition.getName()),
                    biPartition);
        }

    }

    /**
     * 根据分区名称和平台获取分区信息
     *
     * @param vendorId
     * @throws Exception
     */
    private BiPartition queryPartition(Long vendorId, String partitionName) {
        return cachePartitionByNameAndVendor.get(BigIpHelper.partitionCode(String.valueOf(vendorId), partitionName));
    }

    private void syncPartition(List<PartitionModel> partitionModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(partitionModels)) {
            f5biPartitionRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiPartition> biPartitions = f5biPartitionRepository.list(vendorId);
        Map<String, BiPartition> mapBiPartition = new HashMap<String, BiPartition>();
        for (BiPartition biPartition : biPartitions) {
            mapBiPartition.put(biPartition.getName(), biPartition);
        }
        for (PartitionModel model : partitionModels) {
            BiPartition biPartition = new BiPartition();
            if (mapBiPartition.containsKey(model.getName())) {
                biPartition = mapBiPartition.get(model.getName());
                biPartition.setVendorId(vendorId);
                BeanUtils.copyProperties(biPartition, model);
                f5biPartitionRepository.update(biPartition);
                mapBiPartition.remove(model.getName());
            } else {
                BeanUtils.copyProperties(biPartition, model);
                biPartition.setVendorId(vendorId);
                f5biPartitionRepository.save(biPartition);
                mapBiPartition.remove(model.getName());
            }
        }
        for (String keyset : mapBiPartition.keySet()) {
            f5biPartitionRepository.remove(mapBiPartition.get(keyset).getId(), userId);
        }
    }

    private void syncTunnel(List<TunnelModel> tunnelModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(tunnelModels)) {
            f5BiTunnelRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiTunnel> biTunnels = f5BiTunnelRepository.list(vendorId);
        Map<String, BiTunnel> mapTunnels = new HashMap<String, BiTunnel>();
        for (BiTunnel tunnel : biTunnels) {
            mapTunnels.put(BigIpHelper.partitionCode(cachePartitionById.get(tunnel.getPartitionId()), tunnel.getName()),
                    tunnel);
        }
        for (TunnelModel model : tunnelModels) {
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiTunnel biTunnel = new BiTunnel();
            if (mapTunnels.containsKey(partitionCode)) {
                biTunnel = mapTunnels.get(partitionCode);
                biTunnel.setVendorId(vendorId);
                biTunnel.setPartitionId(partition.getId());
                BeanUtils.copyProperties(biTunnel, model);
                f5BiTunnelRepository.update(biTunnel);
                mapTunnels.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biTunnel, model);
                biTunnel.setVendorId(vendorId);
                biTunnel.setPartitionId(partition.getId());
                f5BiTunnelRepository.save(biTunnel);
                mapTunnels.remove(partitionCode);
            }
        }
        for (String keyset : mapTunnels.keySet()) {
            f5BiTunnelRepository.remove(mapTunnels.get(keyset).getId(), userId);
        }

    }

    private void syncVlan(List<VlanModel> vlanModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(vlanModels)) {
            f5biVlanRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiVlans> biVlans = f5biVlanRepository.list(vendorId);
        Map<String, BiVlans> mapVlans = new HashMap<String, BiVlans>();
        for (BiVlans vlan : biVlans) {
            mapVlans.put(BigIpHelper.partitionCode(cachePartitionById.get(vlan.getPartitionId()), vlan.getName()),
                    vlan);
        }
        for (VlanModel model : vlanModels) {
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiVlans vlan = new BiVlans();
            String description = model.getDescription();
            Boolean sourceChecking = null;
            sourceChecking = "disabled".equals(model.getSourceChecking()) ? false : true;
            if (mapVlans.containsKey(partitionCode)) {
                vlan = mapVlans.get(partitionCode);
                vlan.setVendorId(vendorId);
                BeanUtils.copyProperties(vlan, model);
                vlan.setRemark(description);
                vlan.setSourceChecking(sourceChecking);
                vlan.setPartitionId(partition.getId());
                f5biVlanRepository.update(vlan);
                mapVlans.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(vlan, model);
                vlan.setVendorId(vendorId);
                vlan.setRemark(description);
                vlan.setSourceChecking(sourceChecking);
                vlan.setPartitionId(partition.getId());
                f5biVlanRepository.save(vlan);
                mapVlans.remove(partitionCode);
            }
        }
        for (String keyset : mapVlans.keySet()) {
            f5biVlanRepository.remove(mapVlans.get(keyset).getId(), userId);
        }
    }

    private void syncAddressTranslation(List<SnantPoolModel> snantPoolModels, Long vendorId, Long userId)
            throws Exception {
        if (ListTool.isEmpty(snantPoolModels)) {
            f5BiSnatPoolRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiSnatPool> biSnatPools = f5BiSnatPoolRepository.list(vendorId);
        Map<String, BiSnatPool> mapSnatPool = new HashMap<String, BiSnatPool>();
        for (BiSnatPool biSnatPool : biSnatPools) {
            mapSnatPool.put(BigIpHelper.partitionCode(cachePartitionById.get(biSnatPool.getPartitionId()),
                    biSnatPool.getName()), biSnatPool);
        }
        for (SnantPoolModel model : snantPoolModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiSnatPool biSnatPool = new BiSnatPool();
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            if (mapSnatPool.containsKey(partitionCode)) {
                biSnatPool = mapSnatPool.get(partitionCode);
                biSnatPool.setVendorId(vendorId);
                BeanUtils.copyProperties(biSnatPool, model);
                biSnatPool.setPartitionId(partition.getId());
                f5BiSnatPoolRepository.update(biSnatPool);
                mapSnatPool.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biSnatPool, model);
                biSnatPool.setVendorId(vendorId);
                biSnatPool.setPartitionId(partition.getId());
                f5BiSnatPoolRepository.save(biSnatPool);
                mapSnatPool.remove(partitionCode);
            }
        }
        for (String keyset : mapSnatPool.keySet()) {
            f5BiSnatPoolRepository.remove(mapSnatPool.get(keyset).getId(), userId);
        }
    }

    /**
     * 同步F5 dns resolvers
     *
     * @param dnsResolversModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncdnsResolvers(List<DnsResolversModel> dnsResolversModels, Long vendorId, Long userId)
            throws Exception {
        if (ListTool.isEmpty(dnsResolversModels)) {
            f5BiDnsResolversRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiDnsResolvers> dnsResolvers = f5BiDnsResolversRepository.list(vendorId);
        Map<String, BiDnsResolvers> mapDnsResolvers = new HashMap<String, BiDnsResolvers>();
        for (BiDnsResolvers biDnsResolvers : dnsResolvers) {
            mapDnsResolvers.put(BigIpHelper.partitionCode(cachePartitionById.get(biDnsResolvers.getPartitionId()),
                    biDnsResolvers.getName()), biDnsResolvers);
        }
        for (DnsResolversModel model : dnsResolversModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            BiDnsResolvers biDnsResolvers = new BiDnsResolvers();
            Boolean answerDefaultZones = Boolean
                    .parseBoolean(model.getAnswerDefaultZones().replaceAll("yes", "true").replaceAll("no", "false"));
            Boolean randomizeQueryNameCase = Boolean.parseBoolean(
                    model.getRandomizeQueryNameCase().replaceAll("yes", "true").replaceAll("no", "false"));
            Boolean useIpv4 = Boolean
                    .parseBoolean(model.getUseIpv4().replaceAll("yes", "true").replaceAll("no", "false"));
            Boolean useIpv6 = Boolean
                    .parseBoolean(model.getUseIpv6().replaceAll("yes", "true").replaceAll("no", "false"));
            Boolean useTcp = Boolean
                    .parseBoolean(model.getUseTcp().replaceAll("yes", "true").replaceAll("no", "false"));
            Boolean useUdp = Boolean
                    .parseBoolean(model.getUseUdp().replaceAll("yes", "true").replaceAll("no", "false"));
            if (mapDnsResolvers.containsKey(partitionCode)) {
                biDnsResolvers = mapDnsResolvers.get(partitionCode);
                biDnsResolvers.setVendorId(vendorId);
                BeanUtils.copyProperties(biDnsResolvers, model);
                biDnsResolvers.setAnswerDefaultZones(answerDefaultZones);
                biDnsResolvers.setRandomizeQueryNameCase(randomizeQueryNameCase);
                biDnsResolvers.setUseIpv4(useIpv4);
                biDnsResolvers.setUseIpv6(useIpv6);
                biDnsResolvers.setUseTcp(useTcp);
                biDnsResolvers.setUseUdp(useUdp);
                biDnsResolvers.setVendorId(vendorId);
                biDnsResolvers.setPartitionId(partition.getId());
                f5BiDnsResolversRepository.update(biDnsResolvers);
                mapDnsResolvers.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biDnsResolvers, model);
                biDnsResolvers.setAnswerDefaultZones(answerDefaultZones);
                biDnsResolvers.setRandomizeQueryNameCase(randomizeQueryNameCase);
                biDnsResolvers.setUseIpv4(useIpv4);
                biDnsResolvers.setUseIpv6(useIpv6);
                biDnsResolvers.setUseTcp(useTcp);
                biDnsResolvers.setUseUdp(useUdp);
                biDnsResolvers.setVendorId(vendorId);
                biDnsResolvers.setPartitionId(partition.getId());
                f5BiDnsResolversRepository.save(biDnsResolvers);
                mapDnsResolvers.remove(partitionCode);
            }
        }
        for (String keyset : mapDnsResolvers.keySet()) {
            f5BiDnsResolversRepository.remove(mapDnsResolvers.get(keyset).getId(), userId);
        }
    }

    /**
     * 同步F5 IRULE
     *
     * @param ruleModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncRule(List<RuleModel> ruleModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(ruleModels)) {
            f5BiIRulesRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiIRules> iRules = f5BiIRulesRepository.list(vendorId);
        Map<String, BiIRules> mapIRules = new HashMap<String, BiIRules>();
        for (BiIRules rule : iRules) {
            mapIRules.put(BigIpHelper.partitionCode(cachePartitionById.get(rule.getPartitionId()), rule.getName()),
                    rule);
        }
        for (RuleModel model : ruleModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            BiIRules biIRules = new BiIRules();
            Boolean ignoreVerification = null;
            String verificationStatusModel = null;
            if (null != model.getIgnoreVerification()) {
                ignoreVerification = true;
            } else {
                ignoreVerification = false;
            }
            checkIsReservedData(model.getName(), biIRules);
            Boolean reserved = biIRules.getReserved();
            if (null != model.getApiAnonymous()) {
                model.setApiAnonymous(StringUtils.substringAfter(model.getApiAnonymous(), "nodelete nowrite"));
                String verificationStatus = "";
                if (null != model.getApiRawValues()) {
                    Map<String, Object> apiRawValues = model.getApiRawValues();
                    verificationStatus = (String) apiRawValues.get("verificationStatus");
                }
                switch (verificationStatus) {
                    case "signature-not-verified":
                        verificationStatusModel = "Signature Not Verified";
                        break;
                    case "signature-verified":
                        verificationStatusModel = "F5 Verified";
                        break;
                    default:
                        break;
                }
            } else {
                verificationStatusModel = "None";
            }
            if (mapIRules.containsKey(partitionCode)) {
                biIRules = mapIRules.get(partitionCode);
                biIRules.setVendorId(vendorId);
                BeanUtils.copyProperties(biIRules, model);
                biIRules.setIgnoreVerification(ignoreVerification);
                biIRules.setVerificationStatus(verificationStatusModel);
                biIRules.setReserved(reserved);
                biIRules.setPartitionId(partition.getId());
                f5BiIRulesRepository.update(biIRules);
                mapIRules.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biIRules, model);
                biIRules.setIgnoreVerification(ignoreVerification);
                biIRules.setVerificationStatus(verificationStatusModel);
                biIRules.setVendorId(vendorId);
                biIRules.setReserved(reserved);
                biIRules.setPartitionId(partition.getId());
                f5BiIRulesRepository.save(biIRules);
                mapIRules.remove(partitionCode);
            }
        }
        for (String keyset : mapIRules.keySet()) {
            f5BiIRulesRepository.remove(mapIRules.get(keyset).getId(), userId);
        }

    }

    private void checkIsReservedData(String name, BiIRules biIRules) {
        switch (name) {
            case F5RetainedData.Rule._SYS_APM_EXCHANGE_SUPPORT_OA_BASIC_AUTH:
            case F5RetainedData.Rule._SYS_APM_EXCHANGE_SUPPORT_OA_NTLM_AUTH:
            case F5RetainedData.Rule._SYS_APM_EXCHANGE_SUPPORT_HELPER:
            case F5RetainedData.Rule._SYS_APM_EXCHANGE_SUPPORT_MAIN:
            case F5RetainedData.Rule._SYS_APM_OFFICE365_SAML_BASIC_AUTH:
            case F5RetainedData.Rule._SYS_APM_ACTIVE_SYNC:
            case F5RetainedData.Rule._SYS_AUTH_KRBDELEGATE:
            case F5RetainedData.Rule._SYS_AUTH_LDAP:
            case F5RetainedData.Rule._SYS_AUTH_RADIUS:
            case F5RetainedData.Rule._SYS_AUTH_SSL_CC_LDAP:
            case F5RetainedData.Rule._SYS_AUTH_SSL_CRLDP:
            case F5RetainedData.Rule._SYS_AUTH_SSL_OCSP:
            case F5RetainedData.Rule._SYS_AUTH_TACACS:
            case F5RetainedData.Rule._SYS_THHPS_REDIRECT:
            case F5RetainedData.Rule._SYS_APM_MS_OFFICE_OFBA_SUPPORT:
                biIRules.setReserved(true);
                break;
            default:
                biIRules.setReserved(false);
                break;
        }

    }

    /**
     * 同步f5 virtual server
     *
     * @param virtualServerModels
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncVirtualServer(List<VirtualServerModel> virtualServerModels, CloudVendor vendor, Long userId)
            throws Exception {
        Long vendorId = vendor.getId();
        if (ListTool.isEmpty(virtualServerModels)) {
            f5BiVirtualServerRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiVirtualServer> virtualServers = f5BiVirtualServerRepository.list(vendorId);
        HashMap<String, BiVirtualServer> mapVirtualServer = Maps.newHashMap();
        for (BiVirtualServer biVirtualServer : virtualServers) {
            mapVirtualServer.put(BigIpHelper.partitionCode(cachePartitionById.get(biVirtualServer.getPartitionId()),
                    biVirtualServer.getName()), biVirtualServer);
        }
        for (VirtualServerModel model : virtualServerModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition biPartition = queryPartition(vendorId, model.getPartition());
            // 处理poolmember的name，地址和端口
            String virtualServerAddress = model.getDestination().split(":")[0].replace("/" + model.getPartition() + "/",
                    "");
            String virtualServerPort = model.getDestination().split(":")[1];
            // 处理vs关联的pool
            Long poolId = null;
            if (null != model.getPool()) {
                Map<String, String> map = BigIpHelper.parse(model.getPool(), BigIpHelper.EnumHelper.FULLPATH.name());
                BiPartition partition = queryPartition(vendorId, map.get("partition"));
                BiPool biPool = f5BiPoolRepository.queryByName(map.get("name"), vendorId, partition.getId());
                if (null != biPool.getId()) {
                    poolId = biPool.getId();
                }
            }
            // 处理vs关联的profile
            Long profileId = null;
            Long clientProfileId = null;
            Long serverProfileId = null;
            List<ProfileModel> profileModels = model.getProfileModels();
            for (ProfileModel profileModel : profileModels) {
                // http profile
                BiPartition partition = queryPartition(vendorId, profileModel.getPartition());
                BiProfile profile = f5BiProfileRepository.queryByName(profileModel.getName(), vendorId, partition.getId());
                if (null != profile) {
                    switch (profile.getCategory()) {
                        case "profile-http":
                            profileId = profile.getId();
                            break;
                        case "persistence-cookie":
                            break;
                        case "persistence-dest-addr":
                            break;
                        case "persistence-hash":
                            break;
                        case "persistence-msrdp":
                            break;
                        case "persistence-sip":
                            break;
                        case "persistence-source-addr":
                            break;
                        case "persistence-ssl":
                            break;
                        case "persistence-universal":
                            break;
                        case "profile-tcp":
                            // 处理tcp profile
                            switch (profileModel.getContext()) {
                                case "all":
                                    clientProfileId = profile.getId();
                                    serverProfileId = profile.getId();
                                    break;
                                case "clientside":
                                    clientProfileId = profile.getId();
                                    break;
                                case "aserversidell":
                                    serverProfileId = profile.getId();
                                    break;
                                default:
                                    break;
                            }
                            break;
                        case "profile-udp":
                            break;
                        case "profile-sctp":
                            break;
                        default:
                            break;
                    }
                }
            }
            // vlan and tunnel
            String vlanAndTunnelTraffic = null;
            ArrayList<JSONObject> vlanList = Lists.newArrayList();
            if (null == model.getVlans()) {
                vlanAndTunnelTraffic = "all";
            } else {
                if (null != model.getVlansDisabled()) {
                    vlanAndTunnelTraffic = "disabled";
                }
                if (null != model.getVlansEnabled()) {
                    vlanAndTunnelTraffic = "enabled";
                }
                List<String> vlans = model.getVlans();
                for (String vlan : vlans) {
                    // 获取vlan的分区
                    Map<String, String> map = BigIpHelper.parse(vlan, BigIpHelper.EnumHelper.FULLPATH.name());
                    BiPartition partition = queryPartition(vendorId, map.get("partition"));
                    BiVlans biVlans = f5biVlanRepository.queryByName(map.get("name"), vendorId, partition.getId());
                    if (null == biVlans) {
                        // 如果查询为null，有可能为tunnel
                        BiTunnel tunnel = f5BiTunnelRepository.queryByName(map.get("name"), vendorId, partition.getId());
                        HashMap<String, Object> vlanMap = Maps.newHashMap();
                        vlanMap.put("category", "tunnel");
                        vlanMap.put("id", tunnel.getId());
                        vlanList.add(JSONObject.parseObject(JSONObject.toJSONString(vlanMap)));
                    } else {
                        HashMap<String, Object> vlanMap = Maps.newHashMap();
                        vlanMap.put("category", "vlan");
                        vlanMap.put("id", biVlans.getId());
                        vlanList.add(JSONObject.parseObject(JSONObject.toJSONString(vlanMap)));
                    }
                }
            }
            // source Address Translation
            Long snatPoolId = null;
            Map<String, Object> sourceAddressTranslation = model.getSourceAddressTranslation();
            String type = (String) sourceAddressTranslation.get("type");
            if ("snat".equals(type)) {
                String pool = (String) sourceAddressTranslation.get("pool");
                // 关联的snatpool的分区
                Map<String, String> map = BigIpHelper.parse(pool, BigIpHelper.EnumHelper.FULLPATH.name());
                BiPartition partition = queryPartition(vendorId, map.get("partition"));
                BiSnatPool snatPool = f5BiSnatPoolRepository.queryByName(map.get("name"), vendorId, partition.getId());
                if (null != snatPool) {
                    snatPoolId = snatPool.getId();
                }
            }
            // 关联rule
            List<Long> ruleIds = Lists.newArrayList();
            List<String> rules = model.getRules();
            if (null != rules) {
                for (String rule : rules) {
                    // 关联的rule的分区
                    // 关联的snatpool的分区
                    Map<String, String> map = BigIpHelper.parse(rule, BigIpHelper.EnumHelper.FULLPATH.name());
                    BiPartition partition = queryPartition(vendorId, map.get("partition"));
                    BiIRules biIRules = f5BiIRulesRepository.queryByName(map.get("name"), vendorId, partition.getId());
                    if (null != biIRules) {
                        ruleIds.add(biIRules.getId());
                    }
                }
            }
            // Default Persistence Profile
            Long defaultPersistenceProfileId = null;
            List<Map<String, Object>> persist = model.getPersist();
            if (null != persist) {
                for (Map<String, Object> date : persist) {
                    String name = (String) date.get("name");
                    BiPartition partition = queryPartition(vendorId, (String) date.get("partition"));
                    BiProfile profile = f5BiProfileRepository.queryByName(name, vendorId, partition.getId());
                    if (null != profile) {
                        defaultPersistenceProfileId = profile.getId();
                    }
                }
            }
            // Fallback Persistence Profile
            Long fallbackPersistenceProfileId = null;
            String fallbackPersistence = model.getFallbackPersistence();
            if (null != fallbackPersistence) {
                // 获取回滚profile分区
                Map<String, String> map = BigIpHelper.parse(fallbackPersistence,
                        BigIpHelper.EnumHelper.FULLPATH.name());
                BiPartition partition = queryPartition(vendorId, map.get("partition"));
                BiProfile profile = f5BiProfileRepository.queryByName(map.get("name"), vendorId, partition.getId());
                if (null != profile) {
                    fallbackPersistenceProfileId = profile.getId();
                }
            }
            String ipProtocol = model.getIpProtocol();
            BiVirtualServer biVirtualServer = new BiVirtualServer();
            if (mapVirtualServer.containsKey(partitionCode)) {
                biVirtualServer = mapVirtualServer.get(partitionCode);
                BeanUtils.copyProperties(biVirtualServer, model);
                biVirtualServer.setCreatorId(userId);
                biVirtualServer.setAddress(virtualServerAddress);
                biVirtualServer.setPort(virtualServerPort);
                biVirtualServer.setPoolId(poolId);
                biVirtualServer.setHttpProfileId(profileId);
                biVirtualServer.setProtocolProfileClientId(clientProfileId);
                biVirtualServer.setProtocolProfileServerId(serverProfileId);
                biVirtualServer.setVlanAndTunnelTraffic(vlanAndTunnelTraffic);
                biVirtualServer.setVlansAndTunnels(String.valueOf(vlanList));
                biVirtualServer.setSourceAddressTranslation(type);
                biVirtualServer.setSnatPoolId(snatPoolId);
                biVirtualServer.setIrules(String.valueOf(ruleIds));
                biVirtualServer.setDefaultPersistenceProfileId(defaultPersistenceProfileId);
                biVirtualServer.setFallbackPersistenceProfileId(fallbackPersistenceProfileId);
                biVirtualServer.setProtocol(ipProtocol);
                biVirtualServer.setVendorId(vendorId);
                biVirtualServer.setPartitionId(biPartition.getId());
                f5BiVirtualServerRepository.update(biVirtualServer);
                mapVirtualServer.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biVirtualServer, model);
                biVirtualServer.setCreatorId(userId);
                biVirtualServer.setAddress(virtualServerAddress);
                biVirtualServer.setPort(virtualServerPort);
                biVirtualServer.setPoolId(poolId);
                biVirtualServer.setHttpProfileId(profileId);
                biVirtualServer.setProtocolProfileClientId(clientProfileId);
                biVirtualServer.setProtocolProfileServerId(serverProfileId);
                biVirtualServer.setVlanAndTunnelTraffic(vlanAndTunnelTraffic);
                biVirtualServer.setVlansAndTunnels(String.valueOf(vlanList));
                biVirtualServer.setSourceAddressTranslation(type);
                biVirtualServer.setSnatPoolId(snatPoolId);
                biVirtualServer.setIrules(String.valueOf(ruleIds));
                biVirtualServer.setDefaultPersistenceProfileId(defaultPersistenceProfileId);
                biVirtualServer.setFallbackPersistenceProfileId(fallbackPersistenceProfileId);
                biVirtualServer.setProtocol(ipProtocol);
                biVirtualServer.setVendorId(vendorId);
                biVirtualServer.setProjectId(0L);
                biVirtualServer.setOwnerId(0L);
                biVirtualServer.setPartitionId(biPartition.getId());
                f5BiVirtualServerRepository.save(biVirtualServer);
                mapVirtualServer.remove(partitionCode);
            }
        }
        for (String keyset : mapVirtualServer.keySet()) {
            f5BiVirtualServerRepository.remove(mapVirtualServer.get(keyset).getId(), userId);
        }
    }

    /**
     * 同步f5 pool
     *
     * @param poolModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncPool(List<PoolModel> poolModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(poolModels)) {
            // 删除pool的同时，需要删除所关联的所有poolmember
            f5BiPoolRepository.removeByVID(vendorId, userId);
            f5BiPoolMemberRepository.removeByVId(vendorId, userId);
            return;
        }
        List<BiPool> pools = f5BiPoolRepository.list(vendorId);
        Map<String, BiPool> mapPool = Maps.newHashMap();
        for (BiPool biPool : pools) {
            mapPool.put(BigIpHelper.partitionCode(cachePartitionById.get(biPool.getPartitionId()), biPool.getName()),
                    biPool);
        }
        for (PoolModel model : poolModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            // 解析pool关联的所有monitor
            String monitors = null;
            if (null != model.getMonitor()) {
                String monitor = model.getMonitor();
                String[] monitorNames = monitor.split("and");
                List<Long> monitorIds = Lists.newArrayList();
                for (String monitorName : monitorNames) {
                    Map<String, String> map = BigIpHelper.parse(monitorName, BigIpHelper.EnumHelper.FULLPATH.name());
                    BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
                    BiMonitor biMonitor = this.f5BiMonitorRepository.queryByName(map.get("name"), vendorId,
                            biPartition.getId());
                    monitorIds.add(biMonitor.getId());
                }
                monitors = StringUtils.join(monitorIds, ",");
            }
            BiPool biPool = new BiPool();
            Long poolId = null;
            if (mapPool.containsKey(partitionCode)) {
                biPool = mapPool.get(partitionCode);
                poolId = biPool.getId();
                BeanUtils.copyProperties(biPool, model);
                biPool.setLoadBalancingMethod(model.getLoadBalancingMode());
                if (0 == model.getMinActiveMembers()) {
                    biPool.setPriorityGroupActivation("disabled");
                } else {
                    biPool.setPriorityGroupActivation("less-than");
                }
                biPool.setAvailableMember(String.valueOf(model.getMinActiveMembers()));
                biPool.setCreatorId(userId);
                biPool.setMonitor(monitors);
                biPool.setVendorId(vendorId);
                biPool.setPartitionId(partition.getId());
                f5BiPoolRepository.update(biPool);
                mapPool.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biPool, model);
                biPool.setLoadBalancingMethod(model.getLoadBalancingMode());
                if (0 == model.getMinActiveMembers()) {
                    biPool.setPriorityGroupActivation("disabled");
                } else {
                    biPool.setPriorityGroupActivation("less-than");
                }
                biPool.setAvailableMember(String.valueOf(model.getMinActiveMembers()));
                biPool.setCreatorId(userId);
                biPool.setMonitor(monitors);
                biPool.setVendorId(vendorId);
                biPool.setPartitionId(partition.getId());
                f5BiPoolRepository.save(biPool);
                // 查询出新保存的pool为后续的同步poolmember使用
                BiPartition biPartition = queryPartition(vendorId, model.getPartition());
                BiPool pool = f5BiPoolRepository.queryByName(model.getName(), vendorId, biPartition.getId());
                poolId = pool.getId();
                mapPool.remove(partitionCode);
            }
            // 同步pool下的poolmember数据
            syncPoolMember(model.getPoolMemberModels(), poolId, vendorId, userId);
        }
        for (String keyset : mapPool.keySet()) {
            // 删除pool的同时，需要删除所关联的所有poolmember
            f5BiPoolRepository.remove(mapPool.get(keyset).getId(), userId);
            f5BiPoolMemberRepository.removeByPoolId(mapPool.get(keyset).getId(), userId);
        }
    }

    /**
     * 同步f5 pool下关联的所有poolmember信息
     *
     * @param poolMemberModels
     * @param poolId
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncPoolMember(List<PoolMemberModel> poolMemberModels, Long poolId, Long vendorId, Long userId)
            throws Exception {
        if (ListTool.isEmpty(poolMemberModels)) {
            f5BiPoolMemberRepository.removeByVIdAndPoolId(vendorId, userId, poolId);
            return;
        }
        List<BiPoolMember> poolMembers = f5BiPoolMemberRepository.list(vendorId, poolId);
        Map<String, BiPoolMember> mapPoolMember = Maps.newHashMap();
        for (BiPoolMember biPoolMember : poolMembers) {
            mapPoolMember.put(BigIpHelper.partitionCode(cachePartitionById.get(biPoolMember.getPartitionId()),
                    biPoolMember.getName()), biPoolMember);
        }
        for (PoolMemberModel model : poolMemberModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            // 处理poolmember的name，地址和端口
            String poolMemberPort = model.getName().split(":")[1];
            BiPoolMember poolMember = new BiPoolMember();
            poolMember.setRemark(model.getDescription());
            if (mapPoolMember.containsKey(partitionCode)) {
                poolMember = mapPoolMember.get(partitionCode);
                BeanUtils.copyProperties(poolMember, model);
                poolMember.setCreatorId(userId);
                poolMember.setName(model.getName());
                poolMember.setPoolMemberAddress(model.getAddress());
                poolMember.setPoolMemberPort(poolMemberPort);
                poolMember.setPoolId(poolId);
                poolMember.setPriority(model.getPriorityGroup());
                if ("disabled".equals(model.getRateLimit())) {
                    poolMember.setConnectionRateLimit(0L);
                } else {
                    poolMember.setConnectionRateLimit(Long.valueOf(model.getRateLimit()));
                }
                // 判断pool的address是否为node
                BiPartition biPartition = queryPartition(vendorId, model.getPartition());
                BiNode biNode = f5BiNodeRepository.queryByAddress(model.getAddress(), vendorId, biPartition.getId());
                if (null != biNode) {
                    poolMember.setNodeId(biNode.getId());
                } else {
                    poolMember.setNodeId(0L);
                }
                poolMember.setVendorId(vendorId);
                poolMember.setPartitionId(partition.getId());
                f5BiPoolMemberRepository.update(poolMember);
                mapPoolMember.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(poolMember, model);
                poolMember.setCreatorId(userId);
                poolMember.setName(model.getName());
                poolMember.setPoolMemberAddress(model.getAddress());
                poolMember.setPoolMemberPort(poolMemberPort);
                poolMember.setPoolId(poolId);
                poolMember.setPriority(model.getPriorityGroup());
                if ("disabled".equals(model.getRateLimit())) {
                    poolMember.setConnectionRateLimit(0L);
                } else {
                    poolMember.setConnectionRateLimit(Long.valueOf(model.getRateLimit()));
                }
                // 判断pool的address是否为node
                BiPartition biPartition = queryPartition(vendorId, model.getPartition());
                BiNode biNode = f5BiNodeRepository.queryByAddress(model.getAddress(), vendorId, biPartition.getId());
                if (null != biNode) {
                    poolMember.setNodeId(biNode.getId());
                } else {
                    poolMember.setNodeId(0L);
                }
                poolMember.setVendorId(vendorId);
                poolMember.setPartitionId(partition.getId());
                f5BiPoolMemberRepository.save(poolMember);
                mapPoolMember.remove(partitionCode);
            }
        }
        for (String keyset : mapPoolMember.keySet()) {
            f5BiPoolMemberRepository.remove(mapPoolMember.get(keyset).getId(), userId);
        }
    }

    /**
     * 同步f5 monitor
     *
     * @param monitorModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncMonitor(List<MonitorModel> monitorModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(monitorModels)) {
            f5BiMonitorRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiMonitor> monitors = f5BiMonitorRepository.list(vendorId);
        HashMap<String, BiMonitor> mapMonitor = Maps.newHashMap();
        for (BiMonitor biMonitor : monitors) {
            mapMonitor.put(
                    BigIpHelper.partitionCode(cachePartitionById.get(biMonitor.getPartitionId()), biMonitor.getName()),
                    biMonitor);
        }
        ArrayList<MonitorModel> unprocessedQueues = Lists.newArrayList();
        for (MonitorModel model : monitorModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            // 获取monitor类型
            String kind = model.getKind().replace("tm:ltm:monitor:", "");
            String type = kind.split(":")[0].toString();
            // 处理Configuration
            String configuration = null;
            switch (type) {
                case "http":
                case "https":
                case "tcp":
                    // 处理ip
                    model.setAliasAddress(StringUtils.substringBefore(model.getDestination(), ":"));
                    model.setAliasServicePort(StringUtils.substringAfter(model.getDestination(), ":"));
                    // 处理password
                    if (null != model.getPassword()) {
                        model.setPassword("");
                    }
                    model.setReverse(model.getReverse().equals("disabled") ? "no" : "yes");
                    model.setTransparent(model.getTransparent().equals("disabled") ? "no" : "yes");
                    break;
                case "icmp":
                    // 处理ip
                    model.setAliasAddress(StringUtils.substringBefore(model.getDestination(), ":"));
                    model.setTransparent(model.getTransparent().equals("disabled") ? "no" : "yes");
                    break;
                case "soap":
                    // 处理password
                    if (null != model.getPassword()) {
                        model.setPassword("");
                    }
                    break;
                default:
                    break;
            }
            configuration = JSONObject.toJSONString(model);
            BiMonitor biMonitor = new BiMonitor();
            if (mapMonitor.containsKey(partitionCode)) {
                biMonitor = mapMonitor.get(partitionCode);
                BeanUtils.copyProperties(biMonitor, model);
                biMonitor.setCreatorId(userId);
                biMonitor.setType(type);
                biMonitor.setVendorId(vendorId);
                if (null != model.getDefaultsFrom()) {
                    // 获取parentId
                    buildObjectParentId(F5BasicObject.MONITOR, null, null, model, biMonitor, null, unprocessedQueues,
                            vendorId, model.getPartition());
                } else {
                    // 处理内置数据
                    disposeInternalData(F5BasicObject.MONITOR, model.getName(), null, biMonitor);
                }
                biMonitor.setConfiguration(configuration);
                biMonitor.setPartitionId(partition.getId());
                f5BiMonitorRepository.update(biMonitor);
                mapMonitor.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biMonitor, model);
                if (null != model.getDefaultsFrom()) {
                    // 获取parentId
                    buildObjectParentId(F5BasicObject.MONITOR, null, null, model, biMonitor, null, unprocessedQueues,
                            vendorId, model.getPartition());
                } else {
                    // 处理内置数据
                    disposeInternalData(F5BasicObject.MONITOR, model.getName(), null, biMonitor);
                }
                biMonitor.setCreatorId(userId);
                biMonitor.setType(type);
                biMonitor.setVendorId(vendorId);
                biMonitor.setConfiguration(configuration);
                biMonitor.setPartitionId(partition.getId());
                f5BiMonitorRepository.save(biMonitor);
                mapMonitor.remove(partitionCode);
            }
        }
        // 统一处理profile关联的parentId
        List<BiMonitor> monitorList = f5BiMonitorRepository.list(vendorId);
        List<BiMonitor> pendingData = Lists.newArrayList();
        for (BiMonitor biMonitor : monitorList) {
            BiPartition partition = f5biPartitionRepository.query(biMonitor.getPartitionId());
            if (null == biMonitor.getParentMonitorId()) {
                for (MonitorModel model : unprocessedQueues) {
                    if (biMonitor.getName().equals(model.getName())
                            && partition.getName().equals(model.getPartition())) {
                        BiPartition biPartition = queryPartition(vendorId, model.getPartition());
                        BiMonitor monitor = f5BiMonitorRepository.queryByName(model.getName(), vendorId, biPartition.getId());
                        if (null == monitor) {
                            // 若没有父节点的信息则为内置信息 parentId设置为0
                            biMonitor.setParentMonitorId(0L);
                        } else {
                            biMonitor.setParentMonitorId(monitor.getId());
                        }
                        pendingData.add(biMonitor);
                        break;
                    }
                }
            }
        }
        if (!pendingData.isEmpty()) {
            f5BiMonitorRepository.batchUpdate(pendingData, pendingData.size());
        }
        for (String keyset : mapMonitor.keySet()) {
            f5BiMonitorRepository.remove(mapMonitor.get(keyset).getId(), userId);
        }

    }

    /**
     * 同步f5 profile
     *
     * @param profileModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncProfile(List<ProfileModel> profileModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(profileModels)) {
            f5BiProfileRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiProfile> profiles = f5BiProfileRepository.list(vendorId);
        Map<String, BiProfile> mapProfile = Maps.newHashMap();
        for (BiProfile profile : profiles) {
            mapProfile.put(
                    BigIpHelper.partitionCode(cachePartitionById.get(profile.getPartitionId()), profile.getName()),
                    profile);
        }
        // 未处理parentId的model数据
        ArrayList<ProfileModel> unprocessedQueues = Lists.newArrayList();
        for (ProfileModel model : profileModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            BiProfile biProfile = new BiProfile();
            String categroy = StringUtils
                    .substringBeforeLast(StringUtils.substringAfter(model.getKind(), "tm:ltm:"), ":")
                    .replaceAll(":", "-");
            String configuration = null;
            switch (categroy) {
                case "profile-http":
                    // 获取关联的dns解析器
                    if ("explicit".equals(model.getProxyType())) {
                        String dnsResolver = String.valueOf(model.getExplicitProxy().get("dnsResolver"));
                        if (!"none".equals(dnsResolver) && null != model.getExplicitProxy().get("dnsResolver")
                                && !"".equals(model.getExplicitProxy().get("dnsResolver"))) {
                            Map<String, String> map = BigIpHelper.parse(dnsResolver,
                                    BigIpHelper.EnumHelper.FULLPATH.name());
                            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
                            BiDnsResolvers biDnsResolvers = f5BiDnsResolversRepository.queryByName(map.get("name"), vendorId,
                                    biPartition.getId());
                            model.setDnsResolverId(biDnsResolvers.getId());
                        }
                    }
                    break;
                default:
                    if (null != model.getRule()) {
                        if (!"none".equals(model.getRule())) {
                            Map<String, String> map = BigIpHelper.parse(model.getRule(),
                                    BigIpHelper.EnumHelper.FULLPATH.name());
                            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
                            BiIRules biIRules = f5BiIRulesRepository.queryByName(map.get("name"), vendorId, biPartition.getId());
                            model.setRuleId(biIRules.getId());
                        }
                    }
                    break;
            }
            configuration = JSONObject.toJSONString(model);
            if (mapProfile.containsKey(partitionCode)) {
                biProfile = mapProfile.get(partitionCode);
                if (null != model.getDefaultsFrom() && !"none".equals(model.getDefaultsFrom())) {
                    // 获取parentId
                    buildObjectParentId(F5BasicObject.PROFILE, model, biProfile, null, null, unprocessedQueues, null,
                            vendorId, model.getPartition());
                } else {
                    // 处理内置数据
                    disposeInternalData(F5BasicObject.PROFILE, model.getName(), biProfile, null);
                }
                BeanUtils.copyProperties(biProfile, model);
                biProfile.setCreatorId(userId);
                biProfile.setVendorId(vendorId);
                biProfile.setProxyMode(model.getProxyType());
                biProfile.setConfiguration(configuration);
                biProfile.setCategory(categroy);
                biProfile.setPartitionId(partition.getId());
                f5BiProfileRepository.update(biProfile);
                mapProfile.remove(partitionCode);
            } else {
                if (null != model.getDefaultsFrom() && !"none".equals(model.getDefaultsFrom())) {
                    // 获取parentId
                    buildObjectParentId(F5BasicObject.PROFILE, model, biProfile, null, null, unprocessedQueues, null,
                            vendorId, model.getPartition());
                } else {
                    // 处理内置数据
                    disposeInternalData(F5BasicObject.PROFILE, model.getName(), biProfile, null);
                }
                BeanUtils.copyProperties(biProfile, model);
                biProfile.setProxyMode(model.getProxyType());
                biProfile.setCreatorId(userId);
                biProfile.setVendorId(vendorId);
                biProfile.setConfiguration(configuration);
                biProfile.setCategory(categroy);
                biProfile.setPartitionId(partition.getId());
                f5BiProfileRepository.save(biProfile);
                mapProfile.remove(partitionCode);
            }
        }
        for (String keyset : mapProfile.keySet()) {
            f5BiProfileRepository.remove(mapProfile.get(keyset).getId(), userId);
        }
        // 统一处理profile关联的parentId
        List<BiProfile> profileList = f5BiProfileRepository.list(vendorId);
        ArrayList<BiProfile> pendingData = Lists.newArrayList();
        for (BiProfile biProfile : profileList) {
            BiPartition partition = f5biPartitionRepository.query(biProfile.getPartitionId());
            if (null == biProfile.getParentProfileId()) {
                for (ProfileModel model : unprocessedQueues) {
                    if (biProfile.getName().equals(model.getName())
                            && partition.getName().equals(model.getPartition())) {
                        BiPartition biPartition = queryPartition(vendorId, model.getPartition());
                        BiProfile profile = f5BiProfileRepository.queryByName(model.getName(), vendorId, biPartition.getId());
                        biProfile.setParentProfileId(profile.getId());
                        pendingData.add(biProfile);
                        break;
                    }
                }
            }
        }
        if (!pendingData.isEmpty()) {
            f5BiProfileRepository.batchUpdate(pendingData, pendingData.size());
        }
    }

    /**
     * 处理内置信息
     *
     * @param objectName
     * @param modelName
     * @param biProfile
     * @param biMonitor
     */
    public void disposeInternalData(String objectName, String modelName, BiProfile biProfile, BiMonitor biMonitor) {
        // 处理profile的内置信息
        if (F5BasicObject.PROFILE.equals(objectName)) {
            switch (modelName) {
                case F5RetainedData.Profile.HTTP:
                case F5RetainedData.Profile.HTTP_EXPLICIT:
                case F5RetainedData.Profile.HTTP_TRANSPARENT:
                case F5RetainedData.Profile.TCP:
                case F5RetainedData.Profile.APM_FORWARDING_CLIENT_TCP:
                case F5RetainedData.Profile.APM_FORWARDING_SERVER_TCP:
                case F5RetainedData.Profile.F5_TCP_LAN:
                case F5RetainedData.Profile.F5_TCP_MOBILE:
                case F5RetainedData.Profile.F5_TCP_PROGRESSIVE:
                case F5RetainedData.Profile.F5_TCP_WAN:
                case F5RetainedData.Profile.MPTCP_MOBILE_OPTIMIZED:
                case F5RetainedData.Profile.SPLITSESSION_DEFAULT_TCP:
                case F5RetainedData.Profile.TCP_LAN_OPTIMIZED:
                case F5RetainedData.Profile.UDP:
                case F5RetainedData.Profile.UDP_DECREMENT_TTL:
                case F5RetainedData.Profile.UDP_GTM_DNS:
                case F5RetainedData.Profile.UDP_PRESERVE_TTL:
                case F5RetainedData.Profile.SCTP:
                case F5RetainedData.Profile.COOKIE:
                case F5RetainedData.Profile.DEST_ADDR:
                case F5RetainedData.Profile.HASH:
                case F5RetainedData.Profile.HOST:
                case F5RetainedData.Profile.MSRDP:
                case F5RetainedData.Profile.SIP_INFO:
                case F5RetainedData.Profile.SOURCE_ADDR:
                case F5RetainedData.Profile.SSL:
                case F5RetainedData.Profile.UNIVERSAL:
                    biProfile.setReserved(true);
                    biProfile.setParentProfileId(0L);
                    break;
                default:
                    break;
            }
        }
        if (F5BasicObject.MONITOR.equals(objectName)) {
            switch (modelName) {
                case F5RetainedData.Monitor.HTTP:
                case F5RetainedData.Monitor.HTTPS:
                case F5RetainedData.Monitor.ICMP:
                case F5RetainedData.Monitor.INBAND:
                case F5RetainedData.Monitor.REAL_SERVER:
                case F5RetainedData.Monitor.UDP:
                case F5RetainedData.Monitor.TCP:
                case F5RetainedData.Monitor.TCP_ECHO:
                case F5RetainedData.Monitor.TCP_HALF_OPEN:
                case F5RetainedData.Monitor.SNMP_DCA:
                case F5RetainedData.Monitor.GATEWAY_ICMP:
                    biMonitor.setReserved(true);
                    biMonitor.setParentMonitorId(0L);
                    break;
                default:
                    break;
            }
        }

    }

    /**
     * 获取构建parentID
     *
     * @param objectName
     * @param profileModel
     * @param biProfile
     * @param monitorModel
     * @param biMonitor
     * @param unprocessedProfileQueues
     * @param unprocessedMonitorQueues
     * @throws Exception
     */
    public void buildObjectParentId(String objectName, ProfileModel profileModel, BiProfile biProfile,
                                    MonitorModel monitorModel, BiMonitor biMonitor, List<ProfileModel> unprocessedProfileQueues,
                                    List<MonitorModel> unprocessedMonitorQueues, Long vendorId, String partition) throws Exception {
        if (F5BasicObject.PROFILE.equals(objectName)) {
            // 处理profile的关联文件defaultsFrom,去除前面的路径
            Map<String, String> map = BigIpHelper.parse(profileModel.getDefaultsFrom(),
                    BigIpHelper.EnumHelper.FULLPATH.name());
            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
            BiProfile profile = f5BiProfileRepository.queryByName(map.get("name"), vendorId, biPartition.getId());
            // 若找不到parentId则暂时先设为null，后面统一处理
            if (null != profile) {
                biProfile.setParentProfileId(profile.getId());
            } else {
                biProfile.setParentProfileId(null);
                profileModel.setName(map.get("name"));
                profileModel.setPartition(map.get("partition"));
                unprocessedProfileQueues.add(profileModel);
            }
            biProfile.setReserved(false);
        }
        if (F5BasicObject.MONITOR.equals(objectName)) {
            // 处理monitor的关联文件defaultsFrom,去除前面的路径
            Map<String, String> map = BigIpHelper.parse(monitorModel.getDefaultsFrom(),
                    BigIpHelper.EnumHelper.FULLPATH.name());
            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
            BiMonitor monitor = f5BiMonitorRepository.queryByName(map.get("name"), vendorId, biPartition.getId());
            // 判读是否为内置信息
            switch (biMonitor.getName()) {
                case F5RetainedData.Monitor.HTTP_HEAD_F5:
                case F5RetainedData.Monitor.HTTPS_443:
                case F5RetainedData.Monitor.HTTPS_HEAD_F5:
                case F5RetainedData.Monitor.TCP_ECHO:
                case F5RetainedData.Monitor.TCP_HALF_OPEN:
                    biMonitor.setReserved(true);
                    break;
                default:
                    biMonitor.setReserved(false);
                    break;
            }
            // 若找不到parentId则暂时先设为null，后面统一处理
            if (null != monitor) {
                biMonitor.setParentMonitorId(monitor.getId());
            } else {
                biMonitor.setParentMonitorId(null);
                monitorModel.setName(map.get("name"));
                monitorModel.setPartition(map.get("partition"));
                unprocessedMonitorQueues.add(monitorModel);
            }
        }
    }

    /**
     * 同步f5 node
     *
     * @param nodeModels
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncNode(List<NodeModel> nodeModels, Long vendorId, Long userId) throws Exception {
        if (ListTool.isEmpty(nodeModels)) {
            f5BiNodeRepository.removeByVendor(vendorId, userId);
            return;
        }
        List<BiNode> nodes = f5BiNodeRepository.list(vendorId);
        Map<String, BiNode> mapNode = Maps.newHashMap();
        for (BiNode biNode : nodes) {
            mapNode.put(BigIpHelper.partitionCode(cachePartitionById.get(biNode.getPartitionId()), biNode.getName()),
                    biNode);
        }
        for (NodeModel model : nodeModels) {
            String partitionCode = BigIpHelper.partitionCode(model.getPartition(), model.getName());
            BiPartition partition = queryPartition(vendorId, model.getPartition());
            BiNode biNode = new BiNode();
            if (mapNode.containsKey(partitionCode)) {
                biNode = mapNode.get(partitionCode);
                biNode.setVendorId(vendorId);
                biNode.setCreatorId(userId);
                BeanUtils.copyProperties(biNode, model);
                biNode.setAvailableCount(model.getMinimummonitors());
                if ("disabled".equals(model.getRateLimit())) {
                    biNode.setConnectionRateLimit(0L);
                } else {
                    biNode.setConnectionRateLimit(Long.valueOf(model.getRateLimit()));
                }
                // 处理node关联的monitor
                disposeMonitor(model, biNode, vendorId);
                biNode.setPartitionId(partition.getId());
                f5BiNodeRepository.update(biNode);
                mapNode.remove(partitionCode);
            } else {
                BeanUtils.copyProperties(biNode, model);
                biNode.setAvailableCount(model.getMinimummonitors());
                if ("disabled".equals(model.getRateLimit())) {
                    biNode.setConnectionRateLimit(0L);
                } else {
                    biNode.setConnectionRateLimit(Long.valueOf(model.getRateLimit()));
                }
                // 处理node关联的monitor
                disposeMonitor(model, biNode, vendorId);
                biNode.setCreatorId(userId);
                biNode.setVendorId(vendorId);
                biNode.setPartitionId(partition.getId());
                f5BiNodeRepository.save(biNode);
                mapNode.remove(partitionCode);
            }
        }
        for (String keyset : mapNode.keySet()) {
            f5BiNodeRepository.remove(mapNode.get(keyset).getId(), userId);
        }
    }

    /**
     * 解析处理node关联的monitor
     *
     * @param model
     * @param biNode
     */
    private void disposeMonitor(NodeModel model, BiNode biNode, Long vendorId) {
        String monitor = model.getMonitor().trim();
        switch (monitor) {
            case "default":
                biNode.setHealthMonitors("default");
                biNode.setSelectMonitors(String.valueOf(new ArrayList<>()));
                break;
            case "/Common/none":
                biNode.setHealthMonitors("none");
                biNode.setSelectMonitors(String.valueOf(new ArrayList<>()));
                break;
            default:
                try {
                    biNode.setHealthMonitors("node-specific");
                    List<Long> monitorIds = Lists.newArrayList();
                    // 解析返回的字符串
                    // Availability Requirement :ALL
                    if (-1 != monitor.indexOf("min")) {
                        // 截取关联的monitor部分
                        String monitorData = StringUtils.substringBefore(StringUtils.substringAfter(monitor, "{"), "}")
                                .trim();
                        String[] monitors = monitorData.split(" ");
                        for (String monitorName : monitors) {
                            Map<String, String> map = BigIpHelper.parse(monitorName,
                                    BigIpHelper.EnumHelper.FULLPATH.name());
                            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
                            BiMonitor biMonitor = f5BiMonitorRepository.queryByName(map.get("name"), vendorId,
                                    biPartition.getId());
                            monitorIds.add(biMonitor.getId());
                        }
                        String availableCount = StringUtils
                                .substringBefore(StringUtils.substringAfter(monitor.replace(" ", ""), "min"), "of{");
                        biNode.setAvailabilityRequirement("at-least");
                        biNode.setAvailableCount(Long.valueOf(availableCount));
                    } else {
                        // Availability Requirement :at-least
                        String[] monitors = monitor.trim().split("and");
                        for (String monitorName : monitors) {
                            Map<String, String> map = BigIpHelper.parse(monitorName,
                                    BigIpHelper.EnumHelper.FULLPATH.name());
                            BiPartition biPartition = queryPartition(vendorId, map.get("partition"));
                            BiMonitor biMonitor = f5BiMonitorRepository.queryByName(map.get("name"), vendorId,
                                    biPartition.getId());
                            monitorIds.add(biMonitor.getId());
                        }
                        biNode.setAvailabilityRequirement("all");
                    }
                    biNode.setSelectMonitors(String.valueOf(monitorIds));
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
                break;
        }
    }

}
