163 lines
4.9 KiB
Go
163 lines
4.9 KiB
Go
package usecase
|
|
|
|
import (
|
|
"math"
|
|
"users_management/m/model/dto/req"
|
|
"users_management/m/model/dto/res"
|
|
"users_management/m/repository"
|
|
"users_management/m/utils/helper"
|
|
"users_management/m/utils/service"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type NearestDeviceUseCase interface {
|
|
GetNearestDevices(request req.NearestDeviceDTO) ([]res.NearestDeviceResponse, error)
|
|
GetNearestDeviceByID(id uuid.UUID, userLat, userLng float64) (res.NearestDeviceDetailResponse, error)
|
|
GetNearestTowers(request req.NearestTowerDTO) ([]res.NearestTowerResponse, error)
|
|
GetNearestTowerByID(id uuid.UUID, userLat, userLng float64) (res.NearestTowerDetailResponse, error)
|
|
}
|
|
|
|
type nearestDeviceUseCase struct {
|
|
nearestDeviceRepo repository.NearestDeviceRepo
|
|
geocoder service.GeocodingService
|
|
validate *validator.Validate
|
|
}
|
|
|
|
func NewNearestDeviceUseCase(nearestDeviceRepo repository.NearestDeviceRepo, geocoder service.GeocodingService) NearestDeviceUseCase {
|
|
return &nearestDeviceUseCase{
|
|
nearestDeviceRepo: nearestDeviceRepo,
|
|
geocoder: geocoder,
|
|
validate: validator.New(),
|
|
}
|
|
}
|
|
|
|
func (u *nearestDeviceUseCase) GetNearestTowers(request req.NearestTowerDTO) ([]res.NearestTowerResponse, error) {
|
|
err := u.validate.Struct(request)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set defaults
|
|
radius := request.Radius
|
|
if radius == 0 {
|
|
radius = 5.0 // Default 5km
|
|
}
|
|
|
|
limit := request.Limit
|
|
if limit == 0 {
|
|
limit = 10 // Default 10 towers
|
|
}
|
|
|
|
towers, err := u.nearestDeviceRepo.GetNearestTowers(
|
|
request.Longitude,
|
|
request.Latitude,
|
|
radius,
|
|
limit,
|
|
request.Province,
|
|
request.City,
|
|
request.District,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
responses, err := helper.ConvertToNearestTowerResponses(towers, u.geocoder)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return responses, nil
|
|
}
|
|
|
|
func (u *nearestDeviceUseCase) GetNearestTowerByID(id uuid.UUID, userLat, userLng float64) (res.NearestTowerDetailResponse, error) {
|
|
tower, err := u.nearestDeviceRepo.GetTowerByIDWithConnections(id)
|
|
if err != nil {
|
|
return res.NearestTowerDetailResponse{}, err
|
|
}
|
|
|
|
// Calculate distance
|
|
distance := calculateDistance(userLat, userLng, tower.Latitude, tower.Longitude)
|
|
|
|
response, err := helper.ConvertToNearestTowerDetailResponse(tower, distance, u.nearestDeviceRepo, u.geocoder)
|
|
if err != nil {
|
|
return res.NearestTowerDetailResponse{}, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (u *nearestDeviceUseCase) GetNearestDevices(request req.NearestDeviceDTO) ([]res.NearestDeviceResponse, error) {
|
|
err := u.validate.Struct(request)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set defaults
|
|
radius := request.Radius
|
|
if radius == 0 {
|
|
radius = 5.0 // Default 5km
|
|
}
|
|
|
|
limit := request.Limit
|
|
if limit == 0 {
|
|
limit = 10 // Default 10 devices
|
|
}
|
|
|
|
devices, err := u.nearestDeviceRepo.GetNearestDevices(
|
|
request.Longitude,
|
|
request.Latitude,
|
|
radius,
|
|
limit,
|
|
request.Province,
|
|
request.City,
|
|
request.District,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Updated function call - removed userLat, userLng parameters since distance is already calculated
|
|
responses, err := helper.ConvertToNearestDeviceResponses(devices, u.nearestDeviceRepo, u.geocoder)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return responses, nil
|
|
}
|
|
|
|
func (u *nearestDeviceUseCase) GetNearestDeviceByID(id uuid.UUID, userLat, userLng float64) (res.NearestDeviceDetailResponse, error) {
|
|
device, err := u.nearestDeviceRepo.GetDeviceByIDWithConnections(id)
|
|
if err != nil {
|
|
return res.NearestDeviceDetailResponse{}, err
|
|
}
|
|
|
|
// Calculate distance
|
|
distance := calculateDistance(userLat, userLng, device.Latitude, device.Longitude)
|
|
|
|
response, err := helper.ConvertToNearestDeviceDetailResponse(device, distance, u.nearestDeviceRepo, u.geocoder)
|
|
if err != nil {
|
|
return res.NearestDeviceDetailResponse{}, err
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
// calculateDistance calculates the distance between two coordinates using Haversine formula
|
|
func calculateDistance(lat1, lng1, lat2, lng2 float64) float64 {
|
|
const earthRadius = 6371 // Earth's radius in kilometers
|
|
|
|
lat1Rad := lat1 * math.Pi / 180
|
|
lng1Rad := lng1 * math.Pi / 180
|
|
lat2Rad := lat2 * math.Pi / 180
|
|
lng2Rad := lng2 * math.Pi / 180
|
|
|
|
dlat := lat2Rad - lat1Rad
|
|
dlng := lng2Rad - lng1Rad
|
|
|
|
a := math.Sin(dlat/2)*math.Sin(dlat/2) + math.Cos(lat1Rad)*math.Cos(lat2Rad)*math.Sin(dlng/2)*math.Sin(dlng/2)
|
|
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
|
|
|
return earthRadius * c
|
|
} |