1# coding=utf-8
2"""
3This module is responsible for generating the check digit and formatting
4ISBN numbers.
5"""
6
7
8class ISBN(object):
9
10    MAX_LENGTH = 13
11
12    def __init__(self, ean=None, group=None, registrant=None, publication=None):
13        self.ean = ean
14        self.group = group
15        self.registrant = registrant
16        self.publication = publication
17
18
19class ISBN13(ISBN):
20
21    def __init__(self, *args, **kwargs):
22        super(ISBN13, self).__init__(*args, **kwargs)
23        self.check_digit = self._check_digit()
24
25    def _check_digit(self):
26        """ Calculate the check digit for ISBN-13.
27        See https://en.wikipedia.org/wiki/International_Standard_Book_Number
28        for calculation.
29        """
30        weights = (1 if x % 2 == 0 else 3 for x in range(12))
31        body = ''.join([self.ean, self.group, self.registrant,
32                        self.publication])
33        remainder = sum(int(b) * w for b, w in zip(body, weights)) % 10
34        diff = 10 - remainder
35        check_digit = 0 if diff == 10 else diff
36        return str(check_digit)
37
38    def format(self, separator=''):
39        return separator.join([self.ean, self.group, self.registrant,
40                               self.publication, self.check_digit])
41
42
43class ISBN10(ISBN):
44
45    def __init__(self, *args, **kwargs):
46        super(ISBN10, self).__init__(*args, **kwargs)
47        self.check_digit = self._check_digit()
48
49    def _check_digit(self):
50        """ Calculate the check digit for ISBN-10.
51        See https://en.wikipedia.org/wiki/International_Standard_Book_Number
52        for calculation.
53        """
54        weights = range(1, 10)
55        body = ''.join([self.group, self.registrant, self.publication])
56        remainder = sum(int(b) * w for b, w in zip(body, weights)) % 11
57        check_digit = 'X' if remainder == 10 else str(remainder)
58        return str(check_digit)
59
60    def format(self, separator=''):
61        return separator.join([self.group, self.registrant, self.publication,
62                               self.check_digit])
63