using System;
using System.Collections.Generic;
using System.Text;
namespace FastReport.Barcode
{
///
/// Generates the Plessey barcode.
///
public class BarcodePlessey : LinearBarcodeBase
{
private const String ALPHABET_STRING = "0123456789ABCDEF";
private static readonly int[] startWidths = new int[] { 14, 11, 14, 11, 5, 20, 14, 11 };
private static readonly int[] terminationWidths = new int[] { 25 };
private static readonly int[] endWidths = new int[] { 20, 5, 20, 5, 14, 11, 14, 11 };
private static readonly int[][] numberWidths = new int[][]
{
new int[] { 5, 20, 5, 20, 5, 20, 5, 20 }, // 0
new int[] { 14, 11, 5, 20, 5, 20, 5, 20 }, // 1
new int[] { 5, 20, 14, 11, 5, 20, 5, 20 }, // 2
new int[] { 14, 11, 14, 11, 5, 20, 5, 20 }, // 3
new int[] { 5, 20, 5, 20, 14, 11, 5, 20 }, // 4
new int[] { 14, 11, 5, 20, 14, 11, 5, 20 }, // 5
new int[] { 5, 20, 14, 11, 14, 11, 5, 20 }, // 6
new int[] { 14, 11, 14, 11, 14, 11, 5, 20 }, // 7
new int[] { 5, 20, 5, 20, 5, 20, 14, 11 }, // 8
new int[] { 14, 11, 5, 20, 5, 20, 14, 11 }, // 9
new int[] { 5, 20, 14, 11, 5, 20, 14, 11 }, // A / 10
new int[] { 14, 11, 14, 11, 5, 20, 14, 11 }, // B / 11
new int[] { 5, 20, 5, 20, 14, 11, 14, 11 }, // C / 12
new int[] { 14, 11, 5, 20, 14, 11, 14, 11 }, // D / 13
new int[] { 5, 20, 14, 11, 14, 11, 14, 11 }, // E / 14
new int[] { 14, 11, 14, 11, 14, 11, 14, 11 } // F / 15
};
private static readonly byte[] crcGrid = new byte[] { 1, 1, 1, 1, 0, 1, 0, 0, 1 };
private static readonly int[] crc0Widths = new int[] { 5, 20 };
private static readonly int[] crc1Widths = new int[] { 14, 11 };
private static readonly string start = "606050060";
private static readonly string end = "70050050606";
private static readonly string[] tabelle = new string[] {
"500500500500", //0
"60500500500", //1
"50060500500", //2
"6060500500", //3
"50050060500", //4
"6050060500", //5
"5006060500", //6
"606060500", //7
"50050050060", //8
"6050050060", //9
"5006050060", //A
"606050060", //B
"5005006060", //C
"605006060", //D
"500606060", //E
"60606060" //F
};
internal override string GetPattern()
{
#region ZXing implementation, used for CRC
string contents = text;
int length = contents.Length;
for (int i = 0; i < length; i++)
{
int indexInString = ALPHABET_STRING.IndexOf(contents[i]);
if (indexInString < 0)
throw new ArgumentException("Requested contents contains a not encodable character: '" + contents[i] + "'");
}
// quiet zone + start pattern + data + crc + termination bar + end pattern + quiet zone
int codeWidth = 100 + 100 + length * 100 + 25 * 8 + 25 + 100 + 100;
bool[] result = new bool[codeWidth];
byte[] crcBuffer = new byte[4 * length + 8];
int crcBufferPos = 0;
int pos = 100;
// start pattern
pos += appendPattern(result, pos, startWidths, true);
// data
for (int i = 0; i < length; i++)
{
int indexInString = ALPHABET_STRING.IndexOf(contents[i]);
int[] widths = numberWidths[indexInString];
pos += appendPattern(result, pos, widths, true);
// remember the position number for crc calculation
crcBuffer[crcBufferPos++] = (byte)(indexInString & 1);
crcBuffer[crcBufferPos++] = (byte)((indexInString >> 1) & 1);
crcBuffer[crcBufferPos++] = (byte)((indexInString >> 2) & 1);
crcBuffer[crcBufferPos++] = (byte)((indexInString >> 3) & 1);
}
// CRC calculation
for (int i = 0; i < (4 * length); i++)
{
if (crcBuffer[i] != 0)
{
for (int j = 0; j < 9; j++)
{
crcBuffer[i + j] ^= crcGrid[j];
}
}
}
// append CRC pattern
for (int i = 0; i < 8; i++)
{
switch (crcBuffer[length * 4 + i])
{
case 0:
pos += appendPattern(result, pos, crc0Widths, true);
break;
case 1:
pos += appendPattern(result, pos, crc1Widths, true);
break;
}
}
// termination bar
pos += appendPattern(result, pos, terminationWidths, true);
// end pattern
appendPattern(result, pos, endWidths, false);
//return result;
#endregion
string pattern = "" + start;
//data
foreach(char c in text)
{
int i;
if (int.TryParse("" + c, out i))
pattern += tabelle[i];
else
{
switch (c)
{
case 'A':
pattern += tabelle[10];
break;
case 'B':
pattern += tabelle[11];
break;
case 'C':
pattern += tabelle[12];
break;
case 'D':
pattern += tabelle[13];
break;
case 'E':
pattern += tabelle[14];
break;
case 'F':
pattern += tabelle[15];
break;
default:
throw new Exception("internal Error");
}
}
}
//CRC from ZXing
for (int i = 0; i < 8; i++)
{
switch (crcBuffer[text.Length * 4 + i])
{
case 0:
pattern += "500";
break;
case 1:
pattern += "60";
break;
}
}
pattern += end;
return pattern;
}
///
/// Appends the given pattern to the target array starting at pos.
///
/// encode black/white pattern into this array
/// position to start encoding at in target
/// lengths of black/white runs to encode
/// starting color - false for white, true for black
/// the number of elements added to target.
private int appendPattern(bool[] target, int pos, int[] pattern, bool startColor)
{
bool color = startColor;
int numAdded = 0;
foreach (int len in pattern)
{
for (int j = 0; j < len; j++)
{
target[pos++] = color;
}
numAdded += len;
color = !color; // flip color after each segment
}
return numAdded;
}
}
}