aboutsummaryrefslogtreecommitdiff
path: root/sgdfi/_dbs/_code.py
blob: 5a9abfbcfc39057fce72f035ea28a5c9d12eecd1 (plain)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env python3
#******************************************************************************
# Copyright (C) 2018 Thomas "Cakeisalie5" Touhey <thomas@touhey.fr>
# This file is part of the sgdfi project, which is MIT-licensed.
#******************************************************************************
""" Code decoding for SGDFi. """

from enum import Enum as _Enum, unique as _unique

from ._st import StructureType as _StructureType

__all__ = ["Code", "CodeType"]

@_unique
class CodeType(_Enum):
	""" Unknown code type. """
	UNKNOWN = 0

	""" Structure. """
	STRUCTURE = 1

	""" Adherent. """
	ADHERENT = 2

# If a code starts with:
# - 0, then it is the top (000000000).
# - X0 or X1, then it is a structure (see below for subtypes).
# - X2 to X6, then it is an adherent.
# - X8, then it is a structure related to the national.
#
# If it is a structure and its code ends with:
# - 0000, then it is a territory (territoire).
# - 0081, then it is a “membre associés territorial”,
#   usually a “Développement et réseaux.”.
# - 00, then it is a group (groupe).
# - 81, then it is a “membre associés local”.
#
# XXX: … (units? other types?)
#
# If it is related to the national, then
# - X80 or X86, then it is a centre national.
# - X88, then if the code ends with:
#   - 0X or 10, then it is a centre national.
#   - [1-7]8, then it is a “membres associés national” (développement et
#     réseau formation).
#   - 8X, then it is a “membre associés national”.
#
# For any substructure, after the 10 or 11, the code starts with two digits
# representing the department (e.g. 78 or 91) and a digit representing the
# territory number for this department.

def _strcode(value):
	""" Normalize the code and validate it. """

	try:
		value = int(value)
		assert value >= 0 and value <= 999999999
	except (ValueError, AssertionError):
		raise ValueError("Invalid code.") from None

	return f"{value:09d}"

class Code:
	""" A structure code, which is a 9-digit number. """

	def __init__(self, value):
		self.__code = _strcode(value)

		# Try to deduce things of this code.

		typ  = CodeType.UNKNOWN
		styp = None
		dep  = None
		depn = None
		grpn = None

		if   value[0] == '0':
			typ = CodeType.STRUCTURE
			styp = _StructureType.SOMMET
		elif value[1] in '01':
			dep = int(value[2:4])
			depn = int(value[4]) + (0, 10)[value[1] == '1']

			typ = CodeType.STRUCTURE

			if value[5:7] == '00':
				# That's related to a territory!

				if value[7:9] == '00':
					styp = _StructureType.TERRITOIRE
				else:
					styp = _StructureType.ASSOCIES_T
			else:
				# That's related to a group!

				grpn = int(value[5:7]) - 1

				if value[7:9] == '00':
					styp = _StructureType.GROUPE
				else:
					# TODO: units and stuff?

					styp = _StructureType.ASSOCIES_L
		elif value[1] in '234567':
			# Adherent. X7 is unused for now, but is probably reserved.

			typ = CodeType.ADHERENT
		elif value[1:3] in ('80', '86', '88'):
			if   value[7] == '0' or value[7:9] == '10':
				typ = CodeType.STRUCTURE
				styp = _StructureType.CENTRE_NATIONAL
			elif value[7] in '1234567' and value[8] == '8':
				typ = CodeType.STRUCTURE
				styp = _StructureType.ASSOCIES_N
			elif value[7] == '8':
				typ = CodeType.STRUCTURE
				styp = _StructureType.ASSOCIES_N

		self.__type    = typ
		self.__subtype = styp
		self.__dep     = dep
		self.__depn    = depn
		self.__grpn    = grpn

	def __repr__(self):
		p = [f"code = {self.__code}"]
		if self.__type != CodeType.UNKNOWN:
			p.append(f"type = {self.__type}")
		if self.__type == CodeType.STRUCTURE:
			p.append(f"subtype = {self.__subtype}")
		if self.__dep is not None:
			p.append(f"dep = {self.__dep}")
		if self.__depn is not None:
			p.append(f"depn = {self.__depn}")
		if self.__grpn is not None:
			p.append(f"grpn = {self.__grpn}")

		return f"{self.__class__.__name__}({', '.join(p)})"

	def __str__(self):
		return self.__code

	def __int__(self):
		return int(self.__code)

	def __eq__(self, value):
		return self.__code == _strcode(value)

	@property
	def type(self):
		""" The code type. """

		return self.__type

	@property
	def subtype(self):
		""" The code subtype. """

		return self.__subtype

	@property
	def department(self):
		""" The code of the associated administrative department. """

		return self.__dep

	@property
	def territory_index(self):
		""" The number of the territory in the administrative department. """

		return self.__depn

	@property
	def group_index(self):
		""" The index of the group in the territory. """

		return self.__grpn

# End of file.