Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

# -*- coding: UTF-8 -*- 

# Copyright 2014-2015 Luc Saffre 

# License: BSD (see file COPYING for details) 

 

""" 

Utilities for `lino.modlib.countries`. 

 

Defines models 

:class:`AddressFormatter` and 

:class:`CountryDrivers`. 

 

""" 

from __future__ import print_function 

from __future__ import unicode_literals 

from builtins import str 

from builtins import object 

 

import logging 

logger = logging.getLogger(__name__) 

 

from django.core.exceptions import ValidationError 

 

from lino.api import rt 

from lino.utils import join_words 

from lino.utils.instantiator import InstanceGenerator 

 

from .choicelists import PlaceTypes 

from .choicelists import CountryDrivers 

 

 

class AddressFormatter(object): 

    """Format used in BE, DE, FR, NL... 

 

    """ 

    def get_city_lines(me, self): 

        if self.city is not None: 

            s = join_words(self.zip_code or self.city.zip_code, self.city) 

            if s: 

                yield s 

 

    def get_street_lines(me, self): 

        if self.street: 

            s = join_words( 

                self.street_prefix, self.street, 

                self.street_no) 

            if self.street_box: 

                if self.street_box[0] in '/-': 

                    s += self.street_box 

                else: 

                    s += ' ' + self.street_box 

            yield s 

 

 

class EstonianAddressFormatter(AddressFormatter): 

 

    """Format used in Estonia. 

 

    """ 

 

    def format_place(self, p): 

        if p.type == PlaceTypes.municipality: 

            return "%s vald" % p 

        elif p.type == PlaceTypes.village: 

            return "%s küla" % p 

        elif p.type == PlaceTypes.county: 

            return "%s maakond" % p 

        return str(p) 

 

    def get_city_lines(me, self): 

        lines = [] 

        if self.city: 

            city = self.city 

            zip_code = self.zip_code or self.city.zip_code 

            # Tallinna linnaosade asemel kirjutakse "Tallinn" 

            if city.type == PlaceTypes.township and city.parent: 

                city = city.parent 

            # linna puhul pole vaja maakonda 

            if city.type in (PlaceTypes.town, PlaceTypes.city): 

                s = join_words(zip_code, city) 

            else: 

                lines.append(me.format_place(city)) 

                p = city.parent 

                while p and not CountryDrivers.EE.is_region(p): 

                    lines.append(me.format_place(p)) 

                    p = p.parent 

                if self.region: 

                    s = join_words(zip_code, self.region) 

                elif p: 

                    s = join_words(zip_code, me.format_place(p)) 

                elif len(lines) and zip_code: 

                    lines[-1] = zip_code + ' ' + lines[-1] 

                    s = '' 

                else: 

                    s = zip_code 

        else: 

            s = join_words(self.zip_code, self.region) 

        if s: 

            lines.append(s) 

        return lines 

 

 

ADDRESS_FORMATTERS = dict() 

ADDRESS_FORMATTERS[None] = AddressFormatter() 

ADDRESS_FORMATTERS['EE'] = EstonianAddressFormatter() 

 

 

def get_address_formatter(country): 

    """Return the address formatter (an :class:`AddressFormatter` 

instance) for the given country.""" 

    if country and country.isocode: 

        af = ADDRESS_FORMATTERS.get(country.isocode, None) 

        if af is not None: 

            return af 

    return ADDRESS_FORMATTERS.get(None) 

 

 

class PlaceGenerator(InstanceGenerator): 

    def __init__(self): 

        super(PlaceGenerator, self).__init__() 

        self.prev_obj = None 

        EE = rt.modules.countries.Country.objects.get(isocode="EE") 

 

        for pt in PlaceTypes.objects(): 

            self.add_instantiator( 

                pt.name, 'countries.Place', 'name zip_code', 

                country=EE, 

                type=pt) 

 

    def on_new(self, obj): 

        prev = self.prev_obj 

        if prev and prev.type and obj.type: 

            otype = self.assimilate(obj.type) 

            ptype = self.assimilate(prev.type) 

            if ptype < otype: 

                obj.parent = prev 

            else: 

                p = prev.parent 

                while p and not self.can_be_parent( 

                        self.assimilate(p.type), otype): 

                    p = p.parent 

                if p is not None: 

                    obj.parent = p 

                elif False: 

                    logger.warning( 

                        "%s (%s) is no parent for %s (%s)", 

                        prev, prev.type, obj, obj.type) 

 

        try: 

            obj.full_clean() 

            obj.save() 

            self.prev_obj = obj 

            return obj 

        except ValidationError as e: 

            logger.warning( 

                "Failed to load %s (%s) : %s", 

                obj, obj.type, e) 

        # return super(PlaceGenerator, self).on_new(obj) 

 

    def can_be_parent(self, ptype, otype): 

        """return True if a place of type pt can be parent for a place of type 

        ot. 

 

        """ 

        if ptype < otype: 

            return True 

        return False 

 

    def assimilate(self, pt): 

        """In Estonia, municipalities and towns can be siblings within a same 

county.""" 

        if pt == PlaceTypes.municipality: 

            return PlaceTypes.town 

        return pt