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

245 lines
9.1 KiB
Go

package helper
import (
"fmt"
"log"
"users_management/m/model/dto/res"
"users_management/m/model/entity"
"users_management/m/utils/service"
)
func ConvertToDeviceDetailsResponses(devices []entity.DeviceDetails, geocoder service.GeocodingService) ([]res.DeviceDetailsResponse, error) {
var responses []res.DeviceDetailsResponse
for _, device := range devices {
response, err := ConvertToDeviceDetailsResponse(device, geocoder)
if err != nil {
return nil, err
}
responses = append(responses, response)
}
return responses, nil
}
func ConvertToDeviceDetailsResponse(device entity.DeviceDetails, geocoder service.GeocodingService) (res.DeviceDetailsResponse, 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 all backbones connected to this device
allBackbones := device.GetAllBackbones()
backboneInfos := make([]res.BackboneConnectionInfo, 0)
for _, backbone := range allBackbones {
isStartDevice := backbone.DeviceStartID == device.ID
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,
}
backboneInfos = append(backboneInfos, info)
}
// Get all fishbones connected to this device
allFishbones := device.GetAllFishbones()
fishboneInfos := make([]res.FishboneConnectionInfo, 0)
for _, fishbone := range allFishbones {
isStartDevice := fishbone.DeviceStartID == device.ID
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,
}
fishboneInfos = append(fishboneInfos, info)
}
// Convert tower connections - safely handle nullable ExternalTower
towerInfos := make([]res.TowerConnectionDetail, 0)
for _, tower := range device.Towers {
distance := calculateDistance(device.Latitude, device.Longitude, tower.Latitude, tower.Longitude)
// Safely handle nullable ExternalTower field
var externalTower *bool
if tower.ExternalTower != nil {
externalTower = tower.ExternalTower
} // If tower.ExternalTower is nil, externalTower remains nil
// Safely handle nullable ImageURL
var imageURL *string
if tower.ImageURL != "" {
imageURL = &tower.ImageURL
}
info := res.TowerConnectionDetail{
ID: tower.ID,
TowerCode: tower.TowerCode,
Distance: distance,
ExternalTower: externalTower, // This will be null if tower.ExternalTower is nil
ImageURL: imageURL,
ImageURLs: tower.GetAllImageURLs(), // Get all images as a slice
}
towerInfos = append(towerInfos, info)
}
// Convert entity.PortAssignmentResponse to res.PortAssignmentResponse
entityPortAssignments := device.DevicePort.GetPortAssignmentsWithDetails()
resPortAssignments := make([]res.PortAssignmentResponse, len(entityPortAssignments))
for i, pa := range entityPortAssignments {
resPortAssignments[i] = res.PortAssignmentResponse{
PortNumber: pa.PortNumber,
CustomerName: pa.CustomerName,
IsOccupied: pa.IsOccupied,
}
}
portAssignments := device.DevicePort.GetPortAssignmentsWithDetails()
// Ensure we show all ports up to PortAmount
portAssignmentMap := make(map[int]res.PortAssignmentResponse)
for _, pa := range portAssignments {
portAssignmentMap[pa.PortNumber] = res.PortAssignmentResponse{
PortNumber: pa.PortNumber,
CustomerName: pa.CustomerName,
IsOccupied: pa.IsOccupied,
}
}
// Fill in missing ports
finalPortAssignments := make([]res.PortAssignmentResponse, 0)
for i := 1; i <= device.PortAmount; i++ {
if pa, exists := portAssignmentMap[i]; exists {
finalPortAssignments = append(finalPortAssignments, pa)
} else {
// Determine if this port should be occupied
isOccupied := false
// Count occupied ports before this one
occupiedBefore := 0
for j := 1; j < i; j++ {
if existingPA, exists := portAssignmentMap[j]; exists && existingPA.IsOccupied {
occupiedBefore++
}
}
// Count total ports with customers
customersCount := 0
for _, pa := range portAssignments {
if pa.CustomerName != nil && *pa.CustomerName != "" {
customersCount++
}
}
// This port should be occupied if we haven't reached port_used yet
if occupiedBefore + customersCount < device.DevicePort.PortUsed {
isOccupied = true
}
finalPortAssignments = append(finalPortAssignments, res.PortAssignmentResponse{
PortNumber: i,
CustomerName: nil,
IsOccupied: isOccupied,
})
}
}
var customerNames []string
// If port_used is 0, return empty port assignments
if device.PortAmount == 0 {
finalPortAssignments = []res.PortAssignmentResponse{}
customerNames = []string{}
} else if device.DevicePort.PortUsed == 0 {
// If port_used is 0, return empty port assignments but keep port_amount structure
finalPortAssignments = []res.PortAssignmentResponse{}
customerNames = []string{}
} else {
// Get port assignments with details
portAssignments := device.DevicePort.GetPortAssignmentsWithDetails()
// Convert to response format
finalPortAssignments = make([]res.PortAssignmentResponse, len(portAssignments))
for i, pa := range portAssignments {
finalPortAssignments[i] = res.PortAssignmentResponse{
PortNumber: pa.PortNumber,
CustomerName: pa.CustomerName,
IsOccupied: pa.IsOccupied,
}
}
// Get customer names
customerNames = device.DevicePort.GetCustomerNamesOnly()
}
var deviceImageURLs []string
if device.ImageURL != nil && *device.ImageURL != "" {
deviceImageURLs = append(deviceImageURLs, *device.ImageURL)
}
// Use deviceImageURLs instead of trying to call a non-existent method
allImageURLs := deviceImageURLs
// Handle empty slice vs nil for JSON response
if len(allImageURLs) == 0 {
allImageURLs = []string{} // Return empty array instead of nil
}
response := res.DeviceDetailsResponse{
ID: device.ID,
DeviceCode: device.DeviceCode,
DeviceType: string(device.DeviceType),
Address: address,
Longitude: device.Longitude,
Latitude: device.Latitude,
Status: string(device.Status),
PortAmount: device.PortAmount,
PortUsed: device.DevicePort.PortUsed,
PortAvailable: device.DevicePort.PortAvailable,
CustomerNames: customerNames, // Just customer names
PortAssignments: finalPortAssignments, // Use finalPortAssignments instead of resPortAssignments
Region: device.Region,
Province: device.Province,
City: device.City,
District: device.District,
ImageURL: device.ImageURL,
ImageURLs: allImageURLs, // Use allImageURLs to ensure empty array instead of nil
Backbones: backboneInfos,
Fishbones: fishboneInfos,
Towers: towerInfos,
CreatedAt: device.CreatedAt,
UpdatedAt: device.UpdatedAt,
}
return response, nil
}
// ... rest of helper functions remain the same