OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
181 ilm 1
/*
2
 * Copyright 2014 Robin Stuart
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5
 * in compliance with the License. You may obtain a copy of the License at
6
 *
7
 * http://www.apache.org/licenses/LICENSE-2.0
8
 *
9
 * Unless required by applicable law or agreed to in writing, software distributed under the License
10
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
 * or implied. See the License for the specific language governing permissions and limitations under
12
 * the License.
13
 */
14
package uk.org.okapibarcode.backend;
15
 
16
/**
17
 * <p>
18
 * Implements Channel Code according to ANSI/AIM BC12-1998.
19
 *
20
 * <p>
21
 * Channel Code encodes whole integer values between 0 and 7,742,862.
22
 *
23
 * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
24
 */
25
public class ChannelCode extends Symbol {
26
 
27
    private int preferredNumberOfChannels;
28
 
29
    private final int[] space = new int[11];
30
    private final int[] bar = new int[11];
31
    private double currentValue;
32
    private double targetValue;
33
 
34
    /**
35
     * Sets the preferred number of channels used to encode data. This setting will be ignored if
36
     * the value to be encoded requires more channels.
37
     *
38
     * @param channels the preferred number of channels (3 to 8, inclusive)
39
     */
40
    public void setPreferredNumberOfChannels(final int channels) {
41
        if (channels < 3 || channels > 8) {
42
            throw new IllegalArgumentException("Invalid Channel Code number of channels: " + channels);
43
        }
44
        this.preferredNumberOfChannels = channels;
45
    }
46
 
47
    /**
48
     * Returns the preferred number of channels used to encode data.
49
     *
50
     * @return the preferred number of channels used to encode data
51
     */
52
    public int getPreferredNumberOfChannels() {
53
        return this.preferredNumberOfChannels;
54
    }
55
 
56
    @Override
57
    protected void encode() {
58
 
59
        int channels;
60
        int i;
61
        int leadingZeroCount;
62
 
63
        if (this.content.length() > 7) {
64
            throw new OkapiException("Input too long");
65
        }
66
 
67
        if (!this.content.matches("[0-9]+")) {
68
            throw new OkapiException("Invalid characters in input");
69
        }
70
 
71
        if (this.preferredNumberOfChannels <= 2 || this.preferredNumberOfChannels > 8) {
72
            channels = 3;
73
        } else {
74
            channels = this.preferredNumberOfChannels;
75
        }
76
 
77
        this.targetValue = Integer.parseInt(this.content);
78
 
79
        switch (channels) {
80
        case 3:
81
            if (this.targetValue > 26) {
82
                channels++;
83
            }
84
        case 4:
85
            if (this.targetValue > 292) {
86
                channels++;
87
            }
88
        case 5:
89
            if (this.targetValue > 3493) {
90
                channels++;
91
            }
92
        case 6:
93
            if (this.targetValue > 44072) {
94
                channels++;
95
            }
96
        case 7:
97
            if (this.targetValue > 576688) {
98
                channels++;
99
            }
100
        case 8:
101
            if (this.targetValue > 7742862) {
102
                channels++;
103
            }
104
        }
105
 
106
        if (channels == 9) {
107
            throw new OkapiException("Value out of range");
108
        }
109
 
110
        infoLine("Channels Used: " + channels);
111
 
112
        for (i = 0; i < 11; i++) {
113
            this.bar[i] = 0;
114
            this.space[i] = 0;
115
        }
116
 
117
        this.bar[0] = this.space[1] = this.bar[1] = this.space[2] = this.bar[2] = 1;
118
        this.currentValue = 0;
119
        this.pattern = new String[1];
120
        nextSpace(channels, 3, channels, channels);
121
 
122
        leadingZeroCount = channels - 1 - this.content.length();
123
 
124
        this.readable = "";
125
        for (i = 0; i < leadingZeroCount; i++) {
126
            this.readable += "0";
127
        }
128
        this.readable += this.content;
129
 
130
        this.row_count = 1;
131
        this.row_height = new int[] { -1 };
132
    }
133
 
134
    private void nextSpace(final int channels, final int i, final int maxSpace, final int maxBar) {
135
        for (int s = i < channels + 2 ? 1 : maxSpace; s <= maxSpace; s++) {
136
            this.space[i] = s;
137
            nextBar(channels, i, maxBar, maxSpace + 1 - s);
138
        }
139
    }
140
 
141
    private void nextBar(final int channels, final int i, final int maxBar, final int maxSpace) {
142
        int b = this.space[i] + this.bar[i - 1] + this.space[i - 1] + this.bar[i - 2] > 4 ? 1 : 2;
143
        if (i < channels + 2) {
144
            for (; b <= maxBar; b++) {
145
                this.bar[i] = b;
146
                nextSpace(channels, i + 1, maxSpace, maxBar + 1 - b);
147
            }
148
        } else if (b <= maxBar) {
149
            this.bar[i] = maxBar;
150
            checkIfDone();
151
            this.currentValue++;
152
        }
153
    }
154
 
155
    private void checkIfDone() {
156
        if (this.currentValue == this.targetValue) {
157
            /* Target reached - save the generated pattern */
158
            final StringBuilder sb = new StringBuilder();
159
            sb.append("11110");
160
            for (int i = 0; i < 11; i++) {
161
                sb.append((char) (this.space[i] + '0'));
162
                sb.append((char) (this.bar[i] + '0'));
163
            }
164
            this.pattern[0] = sb.toString();
165
        }
166
    }
167
}