1 ///
2 module barcode.ean13;
3 
4 import std.experimental.logger;
5 
6 import std.algorithm;
7 import std.exception;
8 import std..string;
9 import std.range;
10 import std.array;
11 import std.typecons : tuple;
12 import std.ascii;
13 
14 import barcode.types;
15 import barcode.util;
16 
17 ///
18 class EAN13 : BarCodeEncoder
19 {
20 protected:
21 
22     enum lead_trailer = bitsStr!"#-#";
23     enum separator = bitsStr!"-#-#-";
24 
25     enum Bits!ushort[10][2] modules_AB = [[
26         bitsStr!"---##-#",
27         bitsStr!"--##--#",
28         bitsStr!"--#--##",
29         bitsStr!"-####-#",
30         bitsStr!"-#---##",
31         bitsStr!"-##---#",
32         bitsStr!"-#-####",
33         bitsStr!"-###-##",
34         bitsStr!"-##-###",
35         bitsStr!"---#-##"
36     ],
37     [
38         bitsStr!"-#--###",
39         bitsStr!"-##--##",
40         bitsStr!"--##-##",
41         bitsStr!"-#----#",
42         bitsStr!"--###-#",
43         bitsStr!"-###--#",
44         bitsStr!"----#-#",
45         bitsStr!"--#---#",
46         bitsStr!"---#--#",
47         bitsStr!"--#-###"
48     ]];
49 
50     enum Bits!ushort[10] modules_C = [
51         bitsStr!"###--#-",
52         bitsStr!"##--##-",
53         bitsStr!"##-##--",
54         bitsStr!"#----#-",
55         bitsStr!"#-###--",
56         bitsStr!"#--###-",
57         bitsStr!"#-#----",
58         bitsStr!"#---#--",
59         bitsStr!"#--#---",
60         bitsStr!"###-#--"
61     ];
62 
63     enum ubyte[6][10] parities = [
64         [0, 0, 0, 0, 0, 0],
65         [0, 0, 1, 0, 1, 1],
66         [0, 0, 1, 1, 0, 1],
67         [0, 0, 1, 1, 1, 0],
68         [0, 1, 0, 0, 1, 1],
69         [0, 1, 1, 0, 0, 1],
70         [0, 1, 1, 1, 0, 0],
71         [0, 1, 0, 1, 0, 1],
72         [0, 1, 0, 1, 1, 0],
73         [0, 1, 1, 0, 1, 0]
74     ];
75 
76     enum MODULE = 7;
77     enum DIGITS = 12;
78     enum WIDTH = lead_trailer.count * 2 + separator.count + MODULE + DIGITS;
79 
80 public:
81 pure:
82 
83     ///
84     override BarCode encode(string data)
85     {
86         enforce(data.length == DIGITS, format("length of data must be %s", DIGITS));
87         enforce(data.all!isDigit, "all symbols must be a numbers");
88 
89         BitArray ret;
90 
91         size_t idx(char ch) { return cast(size_t)ch - cast(size_t)'0'; }
92         void append(T)(Bits!T bb) { ret.addBits(bb); }
93 
94         append(lead_trailer);
95 
96         int checkSum = 0;
97         foreach (i; 0 .. DIGITS)
98             checkSum += (i%2 == 1 ? 1 : 3) * idx(data[i]);
99 
100         checkSum %= 10;
101         checkSum = checkSum == 0 ? 0 : 10 - checkSum;
102 
103         assert (checkSum >= 0 && checkSum < 10, "checkSum calc wrong");
104 
105         auto pp = parities[checkSum];
106 
107         foreach (i; 0 .. 6) append(modules_AB[pp[i]][idx(data[i])]);
108 
109         append(separator);
110 
111         foreach (i; 6 .. 12) append(modules_C[idx(data[i])]);
112 
113         append(lead_trailer);
114 
115         return BarCode(ret.length, ret, "ean13");
116     }
117 }