import com.sweetfish.service.RetResult
import com.sdtool.common.api.BusinessExecutor
import com.sdtool.common.datas.ERPModule
import com.sdtool.common.entity.base.ProcessStringItem
import com.sdtool.common.entity.system.ParseAreaResult
import com.sdtool.common.tool.ERPUtils
import groovy.json.JsonSlurper
import org.apache.commons.lang3.StringUtils
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger

import javax.annotation.Resource
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
import java.util.regex.Matcher
import java.util.regex.Pattern
import java.util.stream.Collectors
import java.util.stream.Stream

/**
 * Created by jlutt on 2022-02-09
 * 地址解析为省市区联系人电话
 * @author jlutt
 */
class BE_ParseAddress implements BusinessExecutor<ProcessStringItem, ParseAreaResult> {

    protected final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())

    private static final String EMPTY = "", BLANK = " "

    /**
     * 手机号正则
     */
    public static String mobile = "(86-1[0-9]{10})|(861[0-9]{10})|(1[0-9]{10})|(1[0-9]{2} [0-9]{4} [0-9]{4})|(1[0-9]{6} [0-9]{4})|(1[0-9]{6}-[0-9]{4})"

    public static Pattern mobilePattern = Pattern.compile(mobile, 32)
    /**
     * 座机号正则
     */
    public static String phone = "(([0-9]{3,4}-)[0-9]{7,8})|([0-9]{12})|([0-9]{11})|([0-9]{10})|([0-9]{9})|([0-9]{8})|([0-9]{7})"

    public static Pattern phonePattern = Pattern.compile(phone, 32)

    /**
     * 邮编正则
     */
    public static String zipCode = "([0-9]{6})"

    public static Pattern zipCodePattern = Pattern.compile(zipCode, 32)

    def excludeKeys = [
            "自治区直辖县级行政区划",
            "省直辖县级行政区划",
            "联系人手机号码",
            "不代收货款",
            "所在地区",
            "详细地址",
            "收货地址",
            "手机号码",
            "发件人",
            "手机号",
            "收货人",
            "收件人",
            "不代收",
            "收货",
            "邮编",
            "电話",
            "电话",
            "地址",
            "：",
            ":",
            "；", ";", "，", ",", "。", "、"
    ]

    //省份有些简称，搜索省份时，可以去掉下面这些词再搜索一次，比如内蒙古自治区，可能简称为内蒙
    public Set<String> provinceKeys = new LinkedHashSet<>(Arrays.asList("特别行政区", "古自治区", "维吾尔自治区", "壮族自治区", "回族自治区", "自治区", "省省直辖", "省", "市"))

    public Set<String> cityKeys = new LinkedHashSet<>(Arrays.asList("布依族苗族自治州", "苗族侗族自治州", "藏族羌族自治州", "哈尼族彝族自治州", "壮族苗族自治州", "傣族景颇族自治州", "蒙古族藏族自治州",
            "傣族自治州", "白族自治州", "藏族自治州", "彝族自治州", "回族自治州", "蒙古自治州", "朝鲜族自治州", "地区", "哈萨克自治州", "盟", "市"))

    public Set<String> countyKeys = new LinkedHashSet<>(Arrays.asList("满族自治县", "满族蒙古族自治县", "蒙古族自治县", "朝鲜族自治县",
            "回族彝族自治县", "彝族回族苗族自治县", "彝族苗族自治县", "土家族苗族自治县", "布依族苗族自治县", "苗族布依族自治县",
            "彝族傣族自治县", "傣族彝族自治县", "仡佬族苗族自治县", "黎族苗族自治县", "苗族侗族自治县", "哈尼族彝族傣族自治县", "哈尼族彝族自治县",
            "彝族哈尼族拉祜族自治县", "傣族拉祜族佤族自治县", "傣族佤族自治县", "拉祜族佤族布朗族傣族自治县", "苗族瑶族傣族自治县", "彝族回族自治县",
            "独龙族怒族自治县", "保安族东乡族撒拉族自治县", "回族土族自治县", "撒拉族自治县", "哈萨克自治县", "塔吉克自治县",
            "回族自治县", "畲族自治县", "土家族自治县", "布依族自治县", "苗族自治县", "瑶族自治县", "侗族自治县", "水族自治县", "傈僳族自治县",
            "仫佬族自治县", "毛南族自治县", "黎族自治县", "羌族自治县", "彝族自治县", "藏族自治县", "纳西族自治县", "裕固族自治县", "哈萨克族自治县",
            "哈尼族自治县", "拉祜族自治县", "佤族自治县",
            "回族",
            "左旗", "右旗", "中旗", "后旗", "联合旗", "自治旗", "旗", "自治县",
            "区", "县", "市"))

    private Map<String, String> provinceShort = new LinkedHashMap<>()

    private Map<String, String> cityShort = new LinkedHashMap<>()

    private Map<String, String> countyShort = new LinkedHashMap<>()

    private Map<String, String> PROVINCES = new LinkedHashMap<String, String>()

    private Map<String, String> CITIES = new LinkedHashMap<String, String>()

    private Map<String, String> COUNTIES = new LinkedHashMap<String, String>()

    @Resource(name = "APP_HOME")
    private String appHome

    @Override
    String scriptName() {
        return "地址解析为省市区联系人电话"
    }

    @Override
    ERPModule module() {
        return ERPModule.ADDRESSPARSER
    }

    @Override
    void start(long supplierCode) {
        def jsonSlurper = new JsonSlurper()

        def provicesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "provices.json")
        def provicesJsonArray = jsonSlurper.parse(provicesJsonFile)

        provicesJsonArray.each { it ->
            PROVINCES.put(it["code"] as String, it["name"] as String)
        }

        def citiesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "cities.json")
        def citiesJsonArray = jsonSlurper.parse(citiesJsonFile)

        citiesJsonArray.each { it ->
            CITIES.put(it["code"] as String, it["name"] as String)
        }

        def countiesJsonFile = new File(appHome + File.separator + "conf" + File.separator + "addressdata" + File.separator + "counties.json")
        def countiesJsonArray = jsonSlurper.parse(countiesJsonFile)

        countiesJsonArray.each { it ->
            COUNTIES.put(it["code"] as String, it["name"] as String)
        }

        for (Map.Entry<String, String> entry : PROVINCES.entrySet()) {
            String result = entry.getValue()
            for (String key : provinceKeys) {
                result = result.replace(key, "")
            }
            provinceShort.put(entry.getKey(), result)
        }

        for (Map.Entry<String, String> entry : CITIES.entrySet()) {
            String result = entry.getValue()
            if (result.length() > 2) {
                for (String key : cityKeys) {
                    result = result.replace(key, "")
                }
                cityShort.put(entry.getKey(), result)
            }
        }

        for (Map.Entry<String, String> entry : COUNTIES.entrySet()) {
            String result = entry.getValue()
            if ("雨花台区" == result) {
                result = "雨花区"
            } else if ("郑州高新技术产业开发区" == result) {
                result = "高新区"
            }
            if (result.length() > 2) {
                for (String key : countyKeys) {
                    if (result.indexOf(key) > 0) {
                        result = result.replace(key, "")
                    }
                }
                countyShort.put(entry.getKey(), result)
            }
        }
    }

    @Override
    RetResult<List<ParseAreaResult>> executeList(ProcessStringItem source) {
        List<ParseAreaResult> results = parse(source.getItemValue(), false)
        return RetResult.<List<ParseAreaResult>> successT().result(results)
    }

    List<ParseAreaResult> parse(String address, boolean parseAll) {
        //整体代码参考 https://github.com/pupuk/addr/blob/master/addr.go和 https://github.com/pupuk/address
        //实现，用字符串处理看来是到头了，不要再纠结啥不对了。
        //都能运里面使用过高德的正地理编码，不输入完整的门牌号也是有差距的，顶多到区县，
        //再不对，可使用百度平台的地址识别，不过从别人测试的结果看也是不能保证的100%
        String inputAddress = address

        ParseAreaResult extraResult = new ParseAreaResult()
        //地址清洗 替换特殊字符,解析手机,座机,邮编,格式化多余空格
        address = cleanAddress(address)

        //提取手机号
        address = parseMobile(address, extraResult)

        //提取电话号码
        address = parsePhone(address, extraResult)

        //提取邮编
        address = parseZipCode(address, extraResult)

        address = address.replaceAll(" {2,}", BLANK)

//        logger.info(address)

        String memo = parseMemo(inputAddress)

        //解析地址
        List<ParseAreaResult> results = parseAddress(address, parseAll)

        //将解析的地址结果重新解析一次名称
        if ((results != null) && (!results.isEmpty())) {
            results.each { r ->
                r.setMobile(extraResult.getMobile())
                r.setPhone(extraResult.getPhone())
                r.setZipCode(extraResult.getZipCode())
                parseName(r, 11)
            }
        } else {
            parseName(extraResult, 11)
            results.add(extraResult)
        }

        results.each { it.memo = memo }
        return results
    }

    private String cleanAddress(String address) {
        address = address.replaceAll("-", EMPTY)

        address = address.replaceAll("\\[.*?]", "")
        address = address.replaceAll("【.*?】", "")

        for (String key : excludeKeys) {
            address = address.replaceAll(key, " ")
        }


        //有一段替换代码groovy执行不了，改成java执行
        return ERPUtils.formatParseAddress(address)
    }

    /**
     * 提取手机号码
     */
    private static String parseMobile(String address, ParseAreaResult result) {
        String mobile = patternGetStr(mobilePattern, address, 0)
        if (StringUtils.isNotEmpty(mobile)) {
            result.setMobile(mobile)
            return address.replaceAll(mobile, BLANK)
        }
        return address
    }

    /**
     * 提取座机号码
     */
    private static String parsePhone(String address, ParseAreaResult result) {
        String phone = patternGetStr(phonePattern, address, 0)
        if (StringUtils.isNotEmpty(phone)) {
            result.setPhone(phone)
            return address.replaceAll(phone, BLANK)
        }
        return address
    }

    /**
     * 提取邮编
     */
    private static String parseZipCode(String address, ParseAreaResult result) {
        String zipCode = patternGetStr(zipCodePattern, address, 0)
        if (StringUtils.isNotEmpty(zipCode)) {
            result.setZipCode(zipCode)
            return address.replaceAll(zipCode, BLANK)
        }
        return address
    }

    /**
     * 提取名称
     */
    private static void parseName(ParseAreaResult result, int maxLen) {
        //设置result
        if (StringUtils.isEmpty(result.getName())) {
            //List<String> list = Stream.of(result.getDetails().split(" ")).collect(Collectors.toCollection(ArrayList::new));
            if (StringUtils.isNotBlank(result.getDetails())) {
                List<String> list = result.getDetails().split(" ") as List
                AtomicReference<String> name = new AtomicReference<>("")
                AtomicInteger index = new AtomicInteger(-1)
                list.each { s ->
                    index.addAndGet(1)
                    if (StringUtils.isNotEmpty(s) && s.length() < maxLen) {
                        if (StringUtils.isEmpty(name.get()) || name.get().length() > s.length()) {
                            name.set(s)
                        }
                    }
                }

                if (StringUtils.isNotEmpty(name.get())) {
                    result.setName(name.get().trim())
                    list.remove(index.get())
                    result.setDetails(list.stream().collect(Collectors.joining(" ")))
                }
            } else {
                result.setName("")
            }
        }
    }

    private static String parseMemo(String address) {
        def result = []
        def matcher = address =~ /([\[【])(.*?)([]】])/
        matcher.each { result << it[2] }
        return result.join(",")
    }

    private static String patternGetStr(Pattern pattern, CharSequence content, int groupIndex) {
        if (null != content && null != pattern) {
            Matcher matcher = pattern.matcher(content)
            return matcher.find() ? matcher.group(groupIndex) : null
        } else {
            return null
        }
    }

    private List<ParseAreaResult> parseAddress(String address, boolean parseAll) {
        List<ParseAreaResult> list = new ArrayList<>()
        list.addAll(0, parseByProvince(address))

        if (parseAll || list.isEmpty() || !list.get(0).getParse()) {
            list.addAll(0, parseByCity(address))
            if (parseAll || list.isEmpty() || !list.get(0).getParse()) {
                list.addAll(0, parseByCounty(address))
            }
        }

        // 可信度排序
        list.sort { a, b ->
            int aNameLength = StringUtils.isEmpty(a.name) ? -1 : a.getName().length()
            int bNameLength = StringUtils.isEmpty(b.getName()) ? -1 : b.getName().length()
            return a.getParse() && !b.getParse() ? -1 : !a.getParse() && b.getParse() ? 1 : aNameLength > bNameLength ? 1 : aNameLength < bNameLength ? -1 : 0
        }

        return list
    }

    /**
     * 通过区解析地址
     * @param addressBase
     * @return
     */
    private List<ParseAreaResult> parseByCounty(String addressBase) {
        List<ParseAreaResult> results = new ArrayList<>()
        ParseAreaResult result = new ParseAreaResult()
        result.setType("parseByCounty")
        String address = addressBase
        for (Map.Entry<String, String> entry : COUNTIES.entrySet()) {
            String countyCode = entry.getKey()
            String countyName = entry.getValue()
            int index = address.indexOf(countyName)
            String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
            int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
            if (StringUtils.isNotEmpty(shortCounty)) {
                index = address.indexOf(shortCounty)
            }

            if (index > -1) {
                if (countyCode.contains("-")) {
                    countyCode = countyCode.split("-")[0]
                }
                result.setCode(countyCode)
                result.setCounty(countyName)
                result.setCountyCode(countyCode)

                String cityCode = countyCode.substring(0, 4) + "00"
                String city = CITIES.get(cityCode)
                result.setCityCode(cityCode)
                result.setCity(city)

                String provinceCode = countyCode.substring(0, 2) + "0000"
                String province = PROVINCES.get(provinceCode)
                result.setProvinceCode(provinceCode)
                result.setProvince(province)


                String leftAddress = address.substring(0, index)
                String _provinceName = "", _cityName = ""
                if (StringUtils.isNotEmpty(leftAddress)) {
                    _provinceName = province
                    int _index = leftAddress.indexOf(_provinceName)
                    if (_index == -1) {
                        _provinceName = provinceShort.get(countyCode.substring(0, 2) + "0000")
                        _index = leftAddress.indexOf(_provinceName)
                        if (_index == -1) {
                            _provinceName = ""
                        }
                    }
                    if (StringUtils.isNotEmpty(_provinceName)) {
                        leftAddress = leftAddress.replaceAll(_provinceName, "")
                    }

                    _cityName = city
                    _index = leftAddress.indexOf(_cityName)
                    if (_index == -1) {
                        _cityName = cityShort.get(countyCode.substring(0, 4) + "00")

                        _index = (StringUtils.isBlank(_cityName)) ? -1 : leftAddress.indexOf(_cityName)

                        if (_index == -1) {
                            _cityName = ""
                        }
                    }
                    if (StringUtils.isNotEmpty(_cityName)) {
                        leftAddress = leftAddress.replaceAll(_cityName, "")
                    }
                    if (StringUtils.isNotEmpty(leftAddress)) {
                        result.setName(leftAddress.trim())
                    }
                }
                address = address.substring(index + countyLength)

                if (StringUtils.isNotEmpty(_provinceName) || StringUtils.isNotEmpty(_cityName)) {
                    result.setParse(true)
                    break
                } else {
                    //如果没有识别到地区 缓存本次结果，并重置数据
                    ParseAreaResult newResult = new ParseAreaResult()
                    newResult.mobile = result.mobile
                    newResult.phone = result.phone
                    newResult.zipCode = result.zipCode
                    newResult.province = result.province
                    newResult.provinceCode = result.provinceCode
                    newResult.city = result.city
                    newResult.cityCode = result.cityCode
                    newResult.county = result.county
                    newResult.countyCode = result.countyCode
                    newResult.address = result.address
                    newResult.details = result.details
                    newResult.code = result.code
                    newResult.name = result.name
                    newResult.type = result.type
                    newResult.parse = result.parse

                    newResult.setDetails(address.trim())
                    results.add(0, newResult)
                    result.clean()
                    address = addressBase
                }
            }
        }

        if (StringUtils.isNotEmpty(result.getCode())) {
            result.setDetails(address.trim())
            results.add(0, result)
        }
        return results
    }

    /**
     * 通过省解析地址
     * @param addressBase
     * @return
     */
    private List<ParseAreaResult> parseByCity(String addressBase) {
        List<ParseAreaResult> results = new ArrayList<>()
        ParseAreaResult result = new ParseAreaResult()
        result.setType("parseByCity")
        String address = addressBase
        for (Map.Entry<String, String> entry : CITIES.entrySet()) {
            String cityCode = entry.getKey()
            String cityName = entry.getValue()
            int index = address.indexOf(cityName)
            String shortCity = index > -1 ? "" : cityShort.get(cityCode)
            int cityLength = StringUtils.isNotEmpty(shortCity) ? shortCity.length() : cityName.length()
            if (StringUtils.isNotEmpty(shortCity)) {
                index = address.indexOf(shortCity)
            }

            if (index > -1) {
                result.setCode(cityCode)
                result.setCity(cityName)
                result.setCityCode(cityCode)

                String provinceCode = cityCode.substring(0, 2) + "0000"
                String province = PROVINCES.get(provinceCode)
                result.setProvinceCode(provinceCode)
                result.setProvince(province)

                String leftAddress = address.substring(0, index)
                String _provinceName = ""
                if (StringUtils.isNotEmpty(leftAddress)) {
                    _provinceName = province
                    int _index = leftAddress.indexOf(_provinceName)
                    if (_index == -1) {
                        _provinceName = provinceShort.get(cityCode.substring(0, 2) + "0000")
                        _index = leftAddress.indexOf(_provinceName)
                        if (_index == -1) {
                            _provinceName = ""
                        }
                    }
                    if (StringUtils.isNotEmpty(_provinceName)) {
                        leftAddress = leftAddress.replace(_provinceName, "")
                    }
                    if (StringUtils.isNotEmpty(leftAddress)) {
                        result.setName(leftAddress)
                    }
                }

                address = address.substring(index + cityLength)
                address = parseAreaByCity(address, result)
                if (StringUtils.isNotEmpty(_provinceName) || StringUtils.isNotEmpty(result.getCounty())) {
                    result.setParse(true)
                    break
                } else {
                    //如果没有识别到地区 缓存本次结果，并重置数据
                    ParseAreaResult newResult = new ParseAreaResult()
                    newResult.mobile = result.mobile
                    newResult.phone = result.phone
                    newResult.zipCode = result.zipCode
                    newResult.province = result.province
                    newResult.provinceCode = result.provinceCode
                    newResult.city = result.city
                    newResult.cityCode = result.cityCode
                    newResult.county = result.county
                    newResult.countyCode = result.countyCode
                    newResult.address = result.address
                    newResult.details = result.details
                    newResult.code = result.code
                    newResult.name = result.name
                    newResult.type = result.type
                    newResult.parse = result.parse

                    newResult.setDetails(address.trim())
                    results.add(0, newResult)
                    result.clean()
                    address = addressBase
                }
            }
        }

        if (StringUtils.isNotEmpty(result.getCode())) {
            result.setDetails(address.trim())
            results.add(0, result)
        }
        return results
    }

    /**
     * 通过省解析地址
     * @param addressBase
     * @return
     */
    private List<ParseAreaResult> parseByProvince(String addressBase) {
        List<ParseAreaResult> results = new ArrayList<>()
        ParseAreaResult result = new ParseAreaResult()
        result.setType("parseByProvince")
        String address = addressBase

        for (Map.Entry<String, String> entry : PROVINCES.entrySet()) {
            String code = entry.getKey()
            String province = entry.getValue()

            int index = address.indexOf(province)
            String shortProvince = index > -1 ? "" : provinceShort.get(code)
            int provinceLength = StringUtils.isNotEmpty(shortProvince) ? shortProvince.length() : province.length()
            if (StringUtils.isNotEmpty(shortProvince)) {
                index = address.indexOf(shortProvince)
            }

            if (index > -1) {
                if (index > 0) {
                    result.setName(address.substring(0, index).trim())
                    address = address.substring(index).trim()
                }
                result.setCode(code)
                result.setProvince(province)
                result.setProvinceCode(code)

                String _address = address.substring(provinceLength)

                if (StringUtils.isNotBlank(_address)) {
                    if (!_address.startsWith("市") || _address.indexOf(province) > -1) {
                        address = _address
                    }
                }

                //如果是用短名匹配的 要替换省关键字
                if (StringUtils.isNotEmpty(shortProvince)) {
                    for (String key : provinceKeys) {
                        if (address.indexOf(key) == 0) {
                            address = address.substring(key.length())
                        }
                    }
                }
                String __address = parseCityByProvince(address, result)
                if (StringUtils.isEmpty(result.getCity())) {
                    __address = parseCountyByProvince(address, result)
                }

                if (StringUtils.isNotEmpty(result.getCity())) {
                    address = __address
                    result.setParse(true)
                    break
                } else {
                    //如果没有识别到地区 缓存本次结果，并重置数据
                    ParseAreaResult newResult = new ParseAreaResult()
                    newResult.mobile = result.mobile
                    newResult.phone = result.phone
                    newResult.zipCode = result.zipCode
                    newResult.province = result.province
                    newResult.provinceCode = result.provinceCode
                    newResult.city = result.city
                    newResult.cityCode = result.cityCode
                    newResult.county = result.county
                    newResult.countyCode = result.countyCode
                    newResult.address = result.address
                    newResult.details = result.details
                    newResult.code = result.code
                    newResult.name = result.name
                    newResult.type = result.type
                    newResult.parse = result.parse

                    newResult.setDetails(address.trim())
                    results.add(0, newResult)
                    result.clean()
                    address = addressBase
                }
            }
        }

        //设置code
        if (StringUtils.isNotEmpty(result.getCode())) {
            result.setDetails(address.trim())
            results.add(0, result)
        }
        return results
    }

    private String parseCountyByProvince(String address, ParseAreaResult result) {
        Map<String, String> counties = getTargetsByCode(AreaEnum.COUNTY, result.getCode())
        for (Map.Entry<String, String> entry : counties.entrySet()) {
            String countyCode = entry.getKey()
            String countyName = entry.getValue()
            int index = address.indexOf(countyName)
            String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
            int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
            if (StringUtils.isNotEmpty(shortCounty)) {
                index = address.indexOf(shortCounty)
            }
            if (index > -1 && index < 6) {
                if (countyCode.contains("-")) {
                    countyCode = countyCode.split("-")[0]
                }
                result.setCode(countyCode)
                result.setCounty(countyName)
                result.setCountyCode(countyCode)

                String cityCode = countyCode.substring(0, 4) + "00"
                String cityName = CITIES.get(cityCode)
                result.setCity(cityName)
                result.setCityCode(cityCode)

                address = address.substring(index + countyLength)

                if (StringUtils.isNotEmpty(shortCounty)) {
                    for (String key : countyKeys) {
                        if (address.indexOf(key) == 0) {
                            address = address.substring(key.length())
                        }
                    }
                }
                break
            }
        }
        return address
    }

    /**
     * 通过省解析城市信息
     * @param address
     * @param result
     * @return
     */
    private String parseCityByProvince(String address, ParseAreaResult result) {
        Map<String, String> cities = getTargetsByCode(AreaEnum.CITY, result.getCode())
        for (Map.Entry<String, String> entry : cities.entrySet()) {
            String cityCode = entry.getKey()
            String cityName = entry.getValue()
            int index = address.indexOf(cityName)
            String shortCity = index > -1 ? "" : cityShort.get(cityCode)
            int cityLength = StringUtils.isNotEmpty(shortCity) ? shortCity.length() : cityName.length()
            if (StringUtils.isNotEmpty(shortCity)) {
                index = address.indexOf(shortCity)
            }
            if (index > -1 && index < 3) {
                result.setCode(cityCode)
                result.setCity(cityName)
                result.setCityCode(cityCode)
                address = address.substring(index + cityLength)
                //如果是用短名匹配的 要替换市关键字
                if (StringUtils.isNotEmpty(shortCity)) {
                    String finalAddress = address
                    for (String key : cityKeys) {
                        if (address.indexOf(key) == 0 && !StringUtils.equals(key, "市")) {
                            //排除几个会导致异常的解析
                            boolean anyMatch = Stream.of("市北区", "市南区", "市中区", "市辖区").anyMatch { v -> finalAddress.indexOf(v) == 0 }
                            if (!anyMatch) {
                                address = address.substring(key.length())
                            }
                        }
                    }
                }
                address = parseAreaByCity(address, result)
                break
            }
        }
        return address
    }

    /**
     * 通过城市解析地区信息
     * @param address
     * @param result
     * @return
     */
    private String parseAreaByCity(String address, ParseAreaResult result) {
        Map<String, String> counties = getTargetsByCode(AreaEnum.COUNTY, result.getCode())
        for (Map.Entry<String, String> entry : counties.entrySet()) {
            String countyCode = entry.getKey()
            String countyName = entry.getValue()
            int index = address.indexOf(countyName)
            String shortCounty = index > -1 ? "" : countyShort.get(countyCode)
            int countyLength = StringUtils.isNotEmpty(shortCounty) ? shortCounty.length() : countyName.length()
            if (StringUtils.isNotEmpty(shortCounty)) {
                index = address.indexOf(shortCounty)
            }
            if (index > -1 && index < 3) {
                if (countyCode.contains("-")) {
                    countyCode = countyCode.split("-")[0]
                }
                result.setCode(countyCode)
                result.setCounty(countyName)
                result.setCountyCode(countyCode)

                address = address.substring(index + countyLength)
                if (StringUtils.isNotEmpty(shortCounty)) {
                    for (String key : countyKeys) {
                        if (address.indexOf(key) == 0) {
                            address = address.substring(key.length())
                        }
                    }
                }
                break
            }
        }
        return address
    }

    /**
     * 通过编码获取省市集合对象
     *
     * @param target 省,市枚举
     * @param code 编码,为地区,市,省
     * @return 地址对象
     */
    private Map<String, String> getTargetsByCode(AreaEnum target, String code) {
        Map<String, String> targets = null
        if (AreaEnum.PROVINCE == target) {
            String provinceCode = code.substring(0, 2)
            targets = putTargets(provinceCode, PROVINCES)
        } else if (AreaEnum.CITY == target) {
            String provinceCode = code.substring(0, 2)
            targets = putTargets(provinceCode, CITIES)
        } else if (AreaEnum.COUNTY == target) {
            if ("00" == code.substring(2, 4)) {
                String provinceCode = code.substring(0, 2)
                targets = putTargets(provinceCode, COUNTIES)
            } else {
                String cityCode = code.substring(0, 4)
                targets = putTargets(cityCode, COUNTIES)
            }
        }
        return targets
    }

    /**
     * 查找sources中key以preCode开头的对象,并存储到targets中
     * 其中break必须要依赖于数据是有一定顺序的,必须targets记录在同一范围,中间不能插入其他对象
     *
     * @param preCode
     * @param sources
     */
    private static Map<String, String> putTargets(String preCode, Map<String, String> sources) {
        Map<String, String> targets = new LinkedHashMap<>()
        for (Map.Entry<String, String> entry : sources.entrySet()) {
            int index = entry.getKey().indexOf(preCode)
            if (index == 0) {
                targets.put(entry.getKey(), entry.getValue())
            } else if (targets.size() > 0 && index != 0) {
                break
            }
        }
        return targets
    }
}
