package ditu

import (
	"git.rosy.net.cn/baseapi/platformapi/tencent_map"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"math"
	"strings"

	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/globals/api"
)

const (
	keyMultiple = 1000000
)

type Coordinate struct {
	Lng float64
	Lat float64
}

func roundCoordinate(lng, lat float64, roundLng, roundLat int) (lng2, lat2 int) {
	lng2 = jxutils.StandardCoordinate2Int(lng+jxutils.IntCoordinate2Standard(roundLng)/2) / roundLng * roundLng
	lat2 = jxutils.StandardCoordinate2Int(lat+jxutils.IntCoordinate2Standard(roundLat)/2) / roundLat * roundLat
	return lng2, lat2
}

func (c *Coordinate) GetMapKey() int64 {
	return int64(c.Lng*keyMultiple*keyMultiple + c.Lat*keyMultiple)
}

func GetRound4Radius(lng, lat float64, gridWith int) (roundLng, roundLat int) {
	lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(gridWith), 90)
	_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(gridWith), 0)
	return jxutils.StandardCoordinate2Int(math.Abs(lng2 - lng)), jxutils.StandardCoordinate2Int(math.Abs(lat2 - lat))
}

func GetGridsFromCoordinate(lng, lat float64, radius int, roundLng, roundLat int) (coordList []*Coordinate) {
	if lng != 0 && lat != 0 {
		beginLng, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(radius), 270)
		_, beginLat := jxutils.ConvertDistanceToLogLat(lng, lat, float64(radius), 180)
		intBeginLng, intBeginLat := roundCoordinate(beginLng, beginLat, roundLng, roundLat)

		endLng, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(radius), 90)
		_, endLat := jxutils.ConvertDistanceToLogLat(lng, lat, float64(radius), 0)
		intEndLng, intEndLat := roundCoordinate(endLng, endLat, roundLng, roundLat)

		for intLng := intBeginLng; intLng <= intEndLng; intLng += roundLng {
			for intLat := intBeginLat; intLat <= intEndLat; intLat += roundLat {
				coordList = append(coordList, &Coordinate{
					Lng: jxutils.IntCoordinate2Standard(intLng),
					Lat: jxutils.IntCoordinate2Standard(intLat),
				})
			}
		}
	}
	return coordList
}

func GetDistrictCoordinateList(districtCode int, radius, gridWith int) (coordList []*Coordinate) {
	//districts, err := api.AutonaviAPI.GetDistricts(1, utils.Int2Str(districtCode))
	//if err == nil {
	//	if len(districts) > 0 {
	//		roundLng, roundLat := GetRound4Radius(districts[0].Lng, districts[0].Lat, gridWith)
	//		tmpCoordList := getDistrictCoordinateList(districts, radius, gridWith, roundLng, roundLat)
	//		if len(tmpCoordList) > 0 {
	//			coordList = append(coordList, &Coordinate{
	//				Lng: districts[0].Lng,
	//				Lat: districts[0].Lat,
	//			})
	//			coordList = append(coordList, tmpCoordList...)
	//		}
	//	}
	//}
	return coordList
}

func GetCityCoordinateList(cityCode int, radius, gridWith int) (coordList []*Coordinate) {
	place, err := dao.GetPlaces(dao.GetDB(), []int{cityCode})
	if err != nil {
		return nil
	}
	districts, err := api.TencentMapAPI.GetDistricts(2, utils.Int2Str(cityCode), int(place[0].Level+1))
	if err == nil {
		if len(districts) > 0 {
			roundLng, roundLat := GetRound4Radius(districts[0].Lng, districts[0].Lat, gridWith)
			tmpCoordList := getDistrictCoordinateList(districts, radius, gridWith, roundLng, roundLat)
			if len(tmpCoordList) > 0 {
				coordList = append(coordList, &Coordinate{
					Lng: districts[0].Lng,
					Lat: districts[0].Lat,
				})
				coordList = append(coordList, tmpCoordList...)
			}
		}
	}
	return coordList
}

func needCheckTown(place *tencent_map.District) bool {
	for _, v := range []string{"街道", "镇"} {
		if strings.Index(place.Name, v) >= 0 {
			return true
		}
	}
	return false
}

func getDistrictCoordinateList(districtList []*tencent_map.District, radius, gridWith, roundLng, roundLat int) (coordList []*Coordinate) {
	coordMap := make(map[int64]*Coordinate)
	for _, v := range districtList {
		if (v.Level <= 3 || (v.Level == 4 && needCheckTown(v))) && v.Lng != 0 && v.Lat != 0 {
			realRadius := radius
			if v.Level == 2 {
				realRadius = 2 * radius
			} else if v.Level == 2 {
				realRadius = radius / 2
			}
			tmpCoordList := GetGridsFromCoordinate(v.Lng, v.Lat, realRadius, roundLng, roundLat)
			if v.Level <= 3 {
				tmpCoordList = append(tmpCoordList, getDistrictCoordinateList(v.Districts, radius, gridWith, roundLng, roundLat)...)
			}
			for _, coord := range tmpCoordList {
				coordMap[coord.GetMapKey()] = coord
			}
		}
	}
	for _, coord := range coordMap {
		coordList = append(coordList, coord)
	}
	return coordList
}

// 老版本
//func getDistrictCoordinateList(districtList []*autonavi.District, radius, gridWith, roundLng, roundLat int) (coordList []*Coordinate) {
//	coordMap := make(map[int64]*Coordinate)
//	for _, v := range districtList {
//		if (v.Level <= 3 || (v.Level == 4 && needCheckTown(v))) && v.Lng != 0 && v.Lat != 0 {
//			realRadius := radius
//			if v.Level == 2 {
//				realRadius = 2 * radius
//			} else if v.Level == 2 {
//				realRadius = radius / 2
//			}
//			tmpCoordList := GetGridsFromCoordinate(v.Lng, v.Lat, realRadius, roundLng, roundLat)
//			if v.Level <= 3 {
//				tmpCoordList = append(tmpCoordList, getDistrictCoordinateList(v.Districts, radius, gridWith, roundLng, roundLat)...)
//			}
//			for _, coord := range tmpCoordList {
//				coordMap[coord.GetMapKey()] = coord
//			}
//		}
//	}
//	for _, coord := range coordMap {
//		coordList = append(coordList, coord)
//	}
//	return coordList
//}
