-
Notifications
You must be signed in to change notification settings - Fork 1
/
dxcc.go
101 lines (85 loc) · 2.72 KB
/
dxcc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package dxcc
import (
"strings"
"unicode/utf8"
"github.com/ftl/hamradio/latlon"
)
// DefaultURL is the original URL of the cty.dat file: http://www.country-files.com/cty/cty.dat
const DefaultURL = "http://www.country-files.com/cty/cty.dat"
// DefaultLocalFilename is the default name for the file that is used to store the contents of cty.dat locally in the user's home directory.
const DefaultLocalFilename = ".config/hamradio/cty.dat"
// Prefixes contains all DXCC prefixes.
type Prefixes struct {
items map[string][]Prefix
}
// Prefix contains the information for one specific DXCC prefix.
// The information from the cty.dat file is denormalized: each specific
// prefix carries all the information associated with its primary prefix.
type Prefix struct {
Prefix string
Name string
CQZone CQZone
ITUZone ITUZone
Continent string
LatLon latlon.LatLon
TimeOffset TimeOffset
PrimaryPrefix string
NeedsExactMatch bool
NotARRLCompliant bool
}
// CQZone represents a CQ zone.
type CQZone int
// ITUZone represents an ITU zone.
type ITUZone int
// TimeOffset represents a time offset to UTC.
type TimeOffset float64
// DefaultPrefixes returns the default Prefixes instance. It optionally loads the latest update on demand.
func DefaultPrefixes(updateOnDemand bool) (*Prefixes, bool, error) {
localFilename, err := LocalFilename()
if err != nil {
return nil, false, err
}
updated := false
if updateOnDemand {
updated, _ = Update(DefaultURL, localFilename)
}
result, err := LoadLocal(localFilename)
return result, updated, err
}
// NewPrefixes creates a new instance of prefixes.
func NewPrefixes() *Prefixes {
return &Prefixes{make(map[string][]Prefix)}
}
func (prefixes *Prefixes) add(newPrefixes ...Prefix) {
for _, prefix := range newPrefixes {
key := strings.ToUpper(prefix.Prefix)
ps, ok := prefixes.items[key]
if !ok {
ps = make([]Prefix, 0, 1)
}
prefixes.items[key] = append(ps, prefix)
}
}
// Find returns the best matching prefixes for a given string.
// Since a prefix might be ambiguous, a slice of prefixes that match is returned.
func (prefixes Prefixes) Find(s string) ([]Prefix, bool) {
normalString := strings.ToUpper(strings.TrimSpace(s))
isExactMatch := true
for len(normalString) > 0 {
if ps, ok := prefixes.items[normalString]; ok {
result := make([]Prefix, 0, len(ps))
for _, prefix := range ps {
if !prefix.NeedsExactMatch || isExactMatch {
result = append(result, prefix)
}
}
if len(result) > 0 {
return result, true
}
}
_, lastRuneSize := utf8.DecodeLastRuneInString(normalString)
normalString = normalString[:len(normalString)-lastRuneSize]
isExactMatch = false
}
return []Prefix{}, false
}