NAM-APJATEL-BACKEND/utils/helper/nearest_device_helper.go

212 lines
7.3 KiB
Go

package helper
import (
"fmt"
"log"
"math"
"users_management/m/model/dto/res"
"users_management/m/model/entity"
"users_management/m/repository"
"users_management/m/utils/service"
"github.com/google/uuid"
)
func ConvertToNearestDeviceResponses(devices []entity.DeviceWithDistance, repo repository.NearestDeviceRepo, geocoder service.GeocodingService) ([]res.NearestDeviceResponse, error) {
var responses []res.NearestDeviceResponse
for _, device := range devices {
// Get address
address := ""
if geocoder != nil {
addr, err := geocoder.GetAddressFromCoordinates(device.Latitude, device.Longitude)
if err != nil {
log.Printf("Geocoding error for device %s: %v", device.DeviceCode, err)
address = fmt.Sprintf("Coordinates: %.6f, %.6f", device.Latitude, device.Longitude)
} else {
address = addr
}
}
// Count connections
backboneCount, fishboneCount, towerCount, err := repo.CountConnectionsByDeviceID(device.ID)
if err != nil {
log.Printf("Error counting connections for device %s: %v", device.DeviceCode, err)
backboneCount, fishboneCount, towerCount = 0, 0, 0
}
response := res.NearestDeviceResponse{
ID: device.ID,
DeviceCode: device.DeviceCode,
DeviceType: string(device.DeviceType),
Distance: device.Distance, // Use the calculated distance from query
Address: address,
Longitude: device.Longitude,
Latitude: device.Latitude,
Status: string(device.Status),
PortAmount: device.PortAmount,
Region: device.Region,
Province: device.Province,
City: device.City,
District: device.District,
BackboneCount: backboneCount,
FishboneCount: fishboneCount,
TowerCount: towerCount,
CreatedAt: device.CreatedAt,
}
responses = append(responses, response)
}
return responses, nil
}
func ConvertToNearestDeviceDetailResponse(device entity.Device, distance float64, repo repository.NearestDeviceRepo, geocoder service.GeocodingService) (res.NearestDeviceDetailResponse, error) {
// Get address
address := ""
if geocoder != nil {
addr, err := geocoder.GetAddressFromCoordinates(device.Latitude, device.Longitude)
if err != nil {
log.Printf("Geocoding error for device %s: %v", device.DeviceCode, err)
address = fmt.Sprintf("Coordinates: %.6f, %.6f", device.Latitude, device.Longitude)
} else {
address = addr
}
}
// Get detailed connection information
backbones, err := repo.GetBackbonesByDeviceID(device.ID)
if err != nil {
return res.NearestDeviceDetailResponse{}, err
}
fishbones, err := repo.GetFishbonesByDeviceID(device.ID)
if err != nil {
return res.NearestDeviceDetailResponse{}, err
}
towers, err := repo.GetTowersByDeviceID(device.ID)
if err != nil {
return res.NearestDeviceDetailResponse{}, err
}
// Convert to response format
backboneInfos := convertToBackboneConnectionInfos(backbones, device.ID)
fishboneInfos := convertToFishboneConnectionInfos(fishbones, device.ID)
towerInfos := convertToTowerConnectionInfos(towers, device.Latitude, device.Longitude)
response := res.NearestDeviceDetailResponse{
ID: device.ID,
DeviceCode: device.DeviceCode,
DeviceType: string(device.DeviceType),
Distance: distance,
Address: address,
Longitude: device.Longitude,
Latitude: device.Latitude,
Status: string(device.Status),
PortAmount: device.PortAmount,
Province: device.Province,
City: device.City,
District: device.District,
ImageURL: device.ImageURL,
Backbones: backboneInfos,
Fishbones: fishboneInfos,
Towers: towerInfos,
CreatedAt: device.CreatedAt,
UpdatedAt: device.UpdatedAt,
}
return response, nil
}
func convertToBackboneConnectionInfos(backbones []entity.Backbone, deviceID uuid.UUID) []res.BackboneConnectionInfo {
var infos []res.BackboneConnectionInfo
for _, backbone := range backbones {
isStartDevice := backbone.DeviceStartID == deviceID
connectedTo := ""
if isStartDevice && backbone.DeviceEnd.DeviceCode != "" {
connectedTo = backbone.DeviceEnd.DeviceCode
} else if !isStartDevice && backbone.DeviceStart.DeviceCode != "" {
connectedTo = backbone.DeviceStart.DeviceCode
}
info := res.BackboneConnectionInfo{
ID: backbone.ID,
BackboneCode: backbone.BackboneCode,
CoreAmount: backbone.CoreAmount,
IsStartDevice: isStartDevice,
ConnectedTo: connectedTo,
}
infos = append(infos, info)
}
return infos
}
func convertToFishboneConnectionInfos(fishbones []entity.Fishbone, deviceID uuid.UUID) []res.FishboneConnectionInfo {
var infos []res.FishboneConnectionInfo
for _, fishbone := range fishbones {
isStartDevice := fishbone.DeviceStartID == deviceID
connectedTo := ""
if isStartDevice && fishbone.DeviceEnd.DeviceCode != "" {
connectedTo = fishbone.DeviceEnd.DeviceCode
} else if !isStartDevice && fishbone.DeviceStart.DeviceCode != "" {
connectedTo = fishbone.DeviceStart.DeviceCode
}
info := res.FishboneConnectionInfo{
ID: fishbone.ID,
FishboneCode: fishbone.FishboneCode,
CoreAmount: fishbone.CoreAmount,
BackboneCode: fishbone.Backbone.BackboneCode,
IsStartDevice: isStartDevice,
ConnectedTo: connectedTo,
}
infos = append(infos, info)
}
return infos
}
func convertToTowerConnectionInfos(towers []entity.Tower, deviceLat, deviceLng float64) []res.TowerConnectionInfo {
var infos []res.TowerConnectionInfo
for _, tower := range towers {
// Calculate distance from device to tower
distance := calculateDistance(deviceLat, deviceLng, tower.Latitude, tower.Longitude)
info := res.TowerConnectionInfo{
ID: tower.ID,
TowerCode: tower.TowerCode,
Distance: distance,
ImageURL: &tower.ImageURL,
}
infos = append(infos, info)
}
return infos
}
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
}