1# -*- coding: utf-8 -*-
2# Copyright (c) 2003, Taro Ogawa.  All Rights Reserved.
3# Copyright (c) 2013, Savoir-faire Linux inc.  All Rights Reserved.
4
5# This library is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13# You should have received a copy of the GNU Lesser General Public
14# License along with this library; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
16# MA 02110-1301 USA
17
18from __future__ import print_function, unicode_literals
19
20
21class Num2Word_ID():
22    BASE = {0: [],
23            1: ["satu"],
24            2: ["dua"],
25            3: ["tiga"],
26            4: ["empat"],
27            5: ["lima"],
28            6: ["enam"],
29            7: ["tujuh"],
30            8: ["delapan"],
31            9: ["sembilan"]}
32
33    TENS_TO = {3: "ribu",
34               6: "juta",
35               9: "miliar",
36               12: "triliun",
37               15: "kuadriliun",
38               18: "kuantiliun",
39               21: "sekstiliun",
40               24: "septiliun",
41               27: "oktiliun",
42               30: "noniliun",
43               33: "desiliun"}
44
45    errmsg_floatord = "Cannot treat float number as ordinal"
46    errmsg_negord = "Cannot treat negative number as ordinal"
47    errmsg_toobig = "Too large"
48    max_num = 10 ** 36
49
50    def split_by_koma(self, number):
51        return str(number).split('.')
52
53    def split_by_3(self, number):
54        """
55        starting here, it groups the number by three from the tail
56        '1234567' -> (('1',),('234',),('567',))
57        :param number:str
58        :rtype:tuple
59        """
60        blocks = ()
61        length = len(number)
62
63        if length < 3:
64            blocks += ((number,),)
65        else:
66            len_of_first_block = length % 3
67
68            if len_of_first_block > 0:
69                first_block = number[0:len_of_first_block],
70                blocks += first_block,
71
72            for i in range(len_of_first_block, length, 3):
73                next_block = (number[i:i + 3],),
74                blocks += next_block
75
76        return blocks
77
78    def spell(self, blocks):
79        """
80        it adds the list of spelling to the blocks
81        (
82        ('1',),('034',)) -> (('1',['satu']),('234',['tiga', 'puluh', 'empat'])
83        )
84        :param blocks: tuple
85        :rtype: tuple
86        """
87        word_blocks = ()
88        first_block = blocks[0]
89        if len(first_block[0]) == 1:
90            if first_block[0] == '0':
91                spelling = ['nol']
92            else:
93                spelling = self.BASE[int(first_block[0])]
94        elif len(first_block[0]) == 2:
95            spelling = self.puluh(first_block[0])
96        else:
97            spelling = (
98                self.ratus(first_block[0][0]) + self.puluh(first_block[0][1:3])
99                )
100
101        word_blocks += (first_block[0], spelling),
102
103        for block in blocks[1:]:
104            spelling = self.ratus(block[0][0]) + self.puluh(block[0][1:3])
105            block += spelling,
106            word_blocks += block,
107
108        return word_blocks
109
110    def ratus(self, number):
111        # it is used to spell
112        if number == '1':
113            return ['seratus']
114        elif number == '0':
115            return []
116        else:
117            return self.BASE[int(number)] + ['ratus']
118
119    def puluh(self, number):
120        # it is used to spell
121        if number[0] == '1':
122            if number[1] == '0':
123                return ['sepuluh']
124            elif number[1] == '1':
125                return ['sebelas']
126            else:
127                return self.BASE[int(number[1])] + ['belas']
128        elif number[0] == '0':
129            return self.BASE[int(number[1])]
130        else:
131            return (
132                self.BASE[int(number[0])] + ['puluh']
133                + self.BASE[int(number[1])]
134            )
135
136    def spell_float(self, float_part):
137        # spell the float number
138        word_list = []
139        for n in float_part:
140            if n == '0':
141                word_list += ['nol']
142                continue
143            word_list += self.BASE[int(n)]
144        return ' '.join(['', 'koma'] + word_list)
145
146    def join(self, word_blocks, float_part):
147        """
148        join the words by first join lists in the tuple
149        :param word_blocks: tuple
150        :rtype: str
151        """
152        word_list = []
153        length = len(word_blocks) - 1
154        first_block = word_blocks[0],
155        start = 0
156
157        if length == 1 and first_block[0][0] == '1':
158            word_list += ['seribu']
159            start = 1
160
161        for i in range(start, length + 1, 1):
162            word_list += word_blocks[i][1]
163            if not word_blocks[i][1]:
164                continue
165            if i == length:
166                break
167            word_list += [self.TENS_TO[(length - i) * 3]]
168
169        return ' '.join(word_list) + float_part
170
171    def to_cardinal(self, number):
172        if number >= self.max_num:
173            raise OverflowError(self.errmsg_toobig % (number, self.max_num))
174        minus = ''
175        if number < 0:
176            minus = 'min '
177        float_word = ''
178        n = self.split_by_koma(abs(number))
179        if len(n) == 2:
180            float_word = self.spell_float(n[1])
181        return minus + self.join(self.spell(self.split_by_3(n[0])), float_word)
182
183    def to_ordinal(self, number):
184        self.verify_ordinal(number)
185        out_word = self.to_cardinal(number)
186        if out_word == "satu":
187            return "pertama"
188        return "ke" + out_word
189
190    def to_ordinal_num(self, number):
191        self.verify_ordinal(number)
192        return "ke-" + str(number)
193
194    def to_currency(self, value):
195        return self.to_cardinal(value) + " rupiah"
196
197    def to_year(self, value):
198        return self.to_cardinal(value)
199
200    def verify_ordinal(self, value):
201        if not value == int(value):
202            raise TypeError(self.errmsg_floatord % value)
203        if not abs(value) == value:
204            raise TypeError(self.errmsg_negord % value)
205