OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Blame | Last modification | View Log | RSS feed

/*
 * Copyright 2014 Robin Stuart
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package uk.org.okapibarcode.backend;

/**
 * <p>
 * Implements Channel Code according to ANSI/AIM BC12-1998.
 *
 * <p>
 * Channel Code encodes whole integer values between 0 and 7,742,862.
 *
 * @author <a href="mailto:rstuart114@gmail.com">Robin Stuart</a>
 */
public class ChannelCode extends Symbol {

    private int preferredNumberOfChannels;

    private final int[] space = new int[11];
    private final int[] bar = new int[11];
    private double currentValue;
    private double targetValue;

    /**
     * Sets the preferred number of channels used to encode data. This setting will be ignored if
     * the value to be encoded requires more channels.
     *
     * @param channels the preferred number of channels (3 to 8, inclusive)
     */
    public void setPreferredNumberOfChannels(final int channels) {
        if (channels < 3 || channels > 8) {
            throw new IllegalArgumentException("Invalid Channel Code number of channels: " + channels);
        }
        this.preferredNumberOfChannels = channels;
    }

    /**
     * Returns the preferred number of channels used to encode data.
     *
     * @return the preferred number of channels used to encode data
     */
    public int getPreferredNumberOfChannels() {
        return this.preferredNumberOfChannels;
    }

    @Override
    protected void encode() {

        int channels;
        int i;
        int leadingZeroCount;

        if (this.content.length() > 7) {
            throw new OkapiException("Input too long");
        }

        if (!this.content.matches("[0-9]+")) {
            throw new OkapiException("Invalid characters in input");
        }

        if (this.preferredNumberOfChannels <= 2 || this.preferredNumberOfChannels > 8) {
            channels = 3;
        } else {
            channels = this.preferredNumberOfChannels;
        }

        this.targetValue = Integer.parseInt(this.content);

        switch (channels) {
        case 3:
            if (this.targetValue > 26) {
                channels++;
            }
        case 4:
            if (this.targetValue > 292) {
                channels++;
            }
        case 5:
            if (this.targetValue > 3493) {
                channels++;
            }
        case 6:
            if (this.targetValue > 44072) {
                channels++;
            }
        case 7:
            if (this.targetValue > 576688) {
                channels++;
            }
        case 8:
            if (this.targetValue > 7742862) {
                channels++;
            }
        }

        if (channels == 9) {
            throw new OkapiException("Value out of range");
        }

        infoLine("Channels Used: " + channels);

        for (i = 0; i < 11; i++) {
            this.bar[i] = 0;
            this.space[i] = 0;
        }

        this.bar[0] = this.space[1] = this.bar[1] = this.space[2] = this.bar[2] = 1;
        this.currentValue = 0;
        this.pattern = new String[1];
        nextSpace(channels, 3, channels, channels);

        leadingZeroCount = channels - 1 - this.content.length();

        this.readable = "";
        for (i = 0; i < leadingZeroCount; i++) {
            this.readable += "0";
        }
        this.readable += this.content;

        this.row_count = 1;
        this.row_height = new int[] { -1 };
    }

    private void nextSpace(final int channels, final int i, final int maxSpace, final int maxBar) {
        for (int s = i < channels + 2 ? 1 : maxSpace; s <= maxSpace; s++) {
            this.space[i] = s;
            nextBar(channels, i, maxBar, maxSpace + 1 - s);
        }
    }

    private void nextBar(final int channels, final int i, final int maxBar, final int maxSpace) {
        int b = this.space[i] + this.bar[i - 1] + this.space[i - 1] + this.bar[i - 2] > 4 ? 1 : 2;
        if (i < channels + 2) {
            for (; b <= maxBar; b++) {
                this.bar[i] = b;
                nextSpace(channels, i + 1, maxSpace, maxBar + 1 - b);
            }
        } else if (b <= maxBar) {
            this.bar[i] = maxBar;
            checkIfDone();
            this.currentValue++;
        }
    }

    private void checkIfDone() {
        if (this.currentValue == this.targetValue) {
            /* Target reached - save the generated pattern */
            final StringBuilder sb = new StringBuilder();
            sb.append("11110");
            for (int i = 0; i < 11; i++) {
                sb.append((char) (this.space[i] + '0'));
                sb.append((char) (this.bar[i] + '0'));
            }
            this.pattern[0] = sb.toString();
        }
    }
}