package icao import ( "sort" "strconv" ) // Database handles ICAO address to country lookups type Database struct { allocations []ICAOAllocation } // ICAOAllocation represents an ICAO address range allocation type ICAOAllocation struct { StartAddr int64 EndAddr int64 Country string CountryCode string Flag string Description string } // CountryInfo represents country information for an aircraft type CountryInfo struct { Country string `json:"country"` CountryCode string `json:"country_code"` Flag string `json:"flag"` } // NewDatabase creates a new ICAO database with comprehensive allocation data func NewDatabase() (*Database, error) { allocations := getICAOAllocations() // Sort allocations by start address for efficient binary search sort.Slice(allocations, func(i, j int) bool { return allocations[i].StartAddr < allocations[j].StartAddr }) return &Database{allocations: allocations}, nil } // getICAOAllocations returns comprehensive ICAO allocation data func getICAOAllocations() []ICAOAllocation { // ICAO allocations based on ICAO Document 8585 - comprehensive list return []ICAOAllocation{ // Europe {0x000001, 0x003FFF, "Germany", "DE", "🇩🇪", "Federal Republic of Germany"}, {0x008001, 0x00BFFF, "Germany", "DE", "🇩🇪", "Germany (additional block)"}, {0x400001, 0x43FFFF, "United Kingdom", "GB", "🇬🇧", "United Kingdom"}, {0x440001, 0x447FFF, "Austria", "AT", "🇦🇹", "Republic of Austria"}, {0x448001, 0x44FFFF, "Belgium", "BE", "🇧🇪", "Kingdom of Belgium"}, {0x450001, 0x457FFF, "Bulgaria", "BG", "🇧🇬", "Republic of Bulgaria"}, {0x458001, 0x45FFFF, "Denmark", "DK", "🇩🇰", "Kingdom of Denmark"}, {0x460001, 0x467FFF, "Finland", "FI", "🇫🇮", "Republic of Finland"}, {0x468001, 0x46FFFF, "France", "FR", "🇫🇷", "French Republic"}, {0x470001, 0x477FFF, "Greece", "GR", "🇬🇷", "Hellenic Republic"}, {0x478001, 0x47FFFF, "Hungary", "HU", "🇭🇺", "Republic of Hungary"}, {0x480001, 0x487FFF, "Iceland", "IS", "🇮🇸", "Republic of Iceland"}, {0x488001, 0x48FFFF, "Italy", "IT", "🇮🇹", "Italian Republic"}, {0x490001, 0x497FFF, "Luxembourg", "LU", "🇱🇺", "Grand Duchy of Luxembourg"}, {0x498001, 0x49FFFF, "Netherlands", "NL", "🇳🇱", "Kingdom of the Netherlands"}, {0x4A0001, 0x4A7FFF, "Norway", "NO", "🇳🇴", "Kingdom of Norway"}, {0x4A8001, 0x4AFFFF, "Poland", "PL", "🇵🇱", "Republic of Poland"}, {0x4B0001, 0x4B7FFF, "Portugal", "PT", "🇵🇹", "Portuguese Republic"}, {0x4B8001, 0x4BFFFF, "Czech Republic", "CZ", "🇨🇿", "Czech Republic"}, {0x4C0001, 0x4C7FFF, "Romania", "RO", "🇷🇴", "Romania"}, {0x4C8001, 0x4CFFFF, "Sweden", "SE", "🇸🇪", "Kingdom of Sweden"}, {0x4D0001, 0x4D7FFF, "Switzerland", "CH", "🇨🇭", "Swiss Confederation"}, {0x4D8001, 0x4DFFFF, "Turkey", "TR", "🇹🇷", "Republic of Turkey"}, {0x4E0001, 0x4E7FFF, "Spain", "ES", "🇪🇸", "Kingdom of Spain"}, // Asia-Pacific {0x800001, 0x83FFFF, "India", "IN", "🇮🇳", "Republic of India"}, {0x840001, 0x87FFFF, "Japan", "JP", "🇯🇵", "Japan"}, {0x880001, 0x8BFFFF, "Thailand", "TH", "🇹🇭", "Kingdom of Thailand"}, {0x8C0001, 0x8FFFFF, "Korea", "KR", "🇰🇷", "Republic of Korea"}, {0x900001, 0x9003FF, "North Korea", "KP", "🇰🇵", "Democratic People's Republic of Korea"}, {0x750001, 0x757FFF, "China", "CN", "🇨🇳", "People's Republic of China"}, {0x758001, 0x75FFFF, "China", "CN", "🇨🇳", "People's Republic of China (additional)"}, {0x760001, 0x767FFF, "Australia", "AU", "🇦🇺", "Commonwealth of Australia"}, {0x768001, 0x76FFFF, "Australia", "AU", "🇦🇺", "Australia (additional block)"}, {0xC80001, 0xC87FFF, "New Zealand", "NZ", "🇳🇿", "New Zealand"}, // North America {0xA00001, 0xAFFFFF, "United States", "US", "🇺🇸", "United States of America"}, {0xC00001, 0xC3FFFF, "Canada", "CA", "🇨🇦", "Canada"}, {0x0C0001, 0x0C7FFF, "Mexico", "MX", "🇲🇽", "United Mexican States"}, // South America {0xE00001, 0xE3FFFF, "Argentina", "AR", "🇦🇷", "Argentine Republic"}, {0xE80001, 0xE87FFF, "Brazil", "BR", "🇧🇷", "Federative Republic of Brazil"}, {0xE88001, 0xE8FFFF, "Brazil", "BR", "🇧🇷", "Brazil (additional block)"}, {0xF00001, 0xF07FFF, "Chile", "CL", "🇨🇱", "Republic of Chile"}, {0xF08001, 0xF0FFFF, "Colombia", "CO", "🇨🇴", "Republic of Colombia"}, {0xF10001, 0xF17FFF, "Ecuador", "EC", "🇪🇨", "Republic of Ecuador"}, {0xF18001, 0xF1FFFF, "Paraguay", "PY", "🇵🇾", "Republic of Paraguay"}, {0xF20001, 0xF27FFF, "Peru", "PE", "🇵🇪", "Republic of Peru"}, {0xF28001, 0xF2FFFF, "Uruguay", "UY", "🇺🇾", "Oriental Republic of Uruguay"}, {0xF30001, 0xF37FFF, "Venezuela", "VE", "🇻🇪", "Bolivarian Republic of Venezuela"}, // Africa & Middle East {0x600001, 0x6003FF, "Cyprus", "CY", "🇨🇾", "Republic of Cyprus"}, {0x680001, 0x6803FF, "Jordan", "JO", "🇯🇴", "Hashemite Kingdom of Jordan"}, {0x020001, 0x027FFF, "Egypt", "EG", "🇪🇬", "Arab Republic of Egypt"}, {0x700001, 0x700FFF, "Afghanistan", "AF", "🇦🇫", "Islamic Republic of Afghanistan"}, {0x701001, 0x701FFF, "Bangladesh", "BD", "🇧🇩", "People's Republic of Bangladesh"}, {0x702001, 0x702FFF, "Myanmar", "MM", "🇲🇲", "Republic of the Union of Myanmar"}, // Others {0x500001, 0x5003FF, "Falkland Islands", "FK", "🇫🇰", "Falkland Islands"}, {0x500401, 0x5007FF, "Ascension Island", "AC", "🇦🇨", "Ascension Island"}, } } // LookupCountry returns country information for an ICAO address using binary search func (d *Database) LookupCountry(icaoHex string) (*CountryInfo, error) { if len(icaoHex) != 6 { return &CountryInfo{ Country: "Unknown", CountryCode: "XX", Flag: "🏳️", }, nil } // Convert hex string to integer icaoInt, err := strconv.ParseInt(icaoHex, 16, 64) if err != nil { return &CountryInfo{ Country: "Unknown", CountryCode: "XX", Flag: "🏳️", }, nil } // Binary search for the ICAO address range for _, alloc := range d.allocations { if icaoInt >= alloc.StartAddr && icaoInt <= alloc.EndAddr { return &CountryInfo{ Country: alloc.Country, CountryCode: alloc.CountryCode, Flag: alloc.Flag, }, nil } } // Not found in any allocation return &CountryInfo{ Country: "Unknown", CountryCode: "XX", Flag: "🏳️", }, nil } // Close is a no-op since we don't have any resources to clean up func (d *Database) Close() error { return nil }