-
Notifications
You must be signed in to change notification settings - Fork 1
/
kennitala.go
132 lines (108 loc) · 3.54 KB
/
kennitala.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package kennitala
import (
kennitalaerrors "github.com/johannbrynjar/kennitala/kennitalaerror"
utils "github.com/johannbrynjar/kennitala/utils"
)
var (
ErrInvalidKennitalaType = errInvalidKennitalaType()
ErrInvalidKennitalaLength = errInvalidKennitalaLength()
ErrInvalidKennitalaCentury = errInvalidKennitalaCentury()
ErrInvalidKennitalaFirstLetter = errInvalidKennitalaFirstLetter()
ErrInvalidKennitalaCheckDigit = errInvalidKennitalaCheckDigit()
)
func errInvalidKennitalaType() error { return kennitalaerrors.ErrInvalidKennitalaType }
func errInvalidKennitalaLength() error { return kennitalaerrors.ErrInvalidKennitalaLength }
func errInvalidKennitalaCentury() error { return kennitalaerrors.ErrInvalidKennitalaCentury }
func errInvalidKennitalaFirstLetter() error { return kennitalaerrors.ErrInvalidKennitalaFirstLetter }
func errInvalidKennitalaCheckDigit() error { return kennitalaerrors.ErrInvalidKennitalaCheckDigit }
type Kennitala string
type KennitalaType int8
const (
KennitalaIndividual KennitalaType = 1 << iota
KennitalaCompany
KennitalaSystem
KennitalaAllTypes KennitalaType = KennitalaIndividual | KennitalaCompany | KennitalaSystem
)
func (kennitalaType KennitalaType) isValidKennitalaType() error {
switch kennitalaType {
case KennitalaIndividual, KennitalaCompany, KennitalaSystem, KennitalaAllTypes:
return nil
}
return errInvalidKennitalaType()
}
func (kennitalaType KennitalaType) hasFlag(flag KennitalaType) bool { return kennitalaType&flag != 0 }
func (kennitala Kennitala) IsValidKennitala(kennitalaType KennitalaType) error {
if err := kennitalaType.isValidKennitalaType(); err != nil {
return err
}
if len(kennitala) != 10 {
return errInvalidKennitalaLength()
}
centuries := map[string]string{
"8": "19th",
"9": "20th",
"0": "21st",
}
century := string(kennitala[9])
_, exists := centuries[century]
if !exists {
return errInvalidKennitalaCentury()
}
allowFirstLetters := map[string]string{}
if kennitalaType.hasFlag(KennitalaIndividual) {
// Kennitala for individuals starts with 0, 1, 2 and 3
allowFirstLetters["0"] = "0"
allowFirstLetters["1"] = "1"
allowFirstLetters["2"] = "2"
allowFirstLetters["3"] = "3"
}
if kennitalaType.hasFlag(KennitalaCompany) {
// Kennitala for companies starts with 4, 5, 6 and 7
allowFirstLetters["4"] = "4"
allowFirstLetters["5"] = "5"
allowFirstLetters["6"] = "6"
allowFirstLetters["7"] = "7"
}
if kennitalaType.hasFlag(KennitalaSystem) {
// Kerfiskennitala start with 8 and 9
allowFirstLetters["8"] = "8"
allowFirstLetters["9"] = "8"
}
first := string(kennitala[0])
_, exists = allowFirstLetters[first]
if !exists {
return errInvalidKennitalaFirstLetter()
}
checkDigit, _ := utils.StringToInt(string(kennitala[8]))
calculatedCheckDigit, _ := calculateCheckDigit(kennitala)
if checkDigit != calculatedCheckDigit {
return errInvalidKennitalaCheckDigit()
}
return nil
}
func (kennitala Kennitala) IsPerson() error {
return kennitala.IsValidKennitala(KennitalaIndividual)
}
func calculateCheckDigit(kennitala Kennitala) (int8, error) {
if len(kennitala) != 10 {
return -1, errInvalidKennitalaLength()
}
multiples := [8]int8{3, 2, 7, 6, 5, 4, 3, 2}
sum := uint16(0)
for i := uint8(0); i < 8; i++ {
num, _ := utils.StringToInt(string(kennitala[i]))
// if err != nil {
// // TODO: handle error
// }
sum += uint16(num * multiples[i])
}
parity := (sum % 11)
if parity == 0 {
return 0, nil
}
parity = 11 - parity
if parity == 10 {
return 0, errInvalidKennitalaCheckDigit()
}
return int8(parity), nil
}