context: /*
   * Copyright 2008 ZXing authors
   *
   * 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.
   */
  
  using System;
  using System.Collections.Generic;
  using System.Text;
  using ZXing.Common;
  
  namespace ZXing.OneD
  {
     /// <summary>
     /// <p>Decodes Code 128 barcodes.</p>
     ///
     /// <author>Sean Owen</author>
     /// </summary>
     public sealed class Code128Reader : OneDReader
     {
        internal static int[][] CODE_PATTERNS = {
                                                  new[] {2, 1, 2, 2, 2, 2}, // 0
                                                  new[] {2, 2, 2, 1, 2, 2},
                                                  new[] {2, 2, 2, 2, 2, 1},
                                                  new[] {1, 2, 1, 2, 2, 3},
                                                  new[] {1, 2, 1, 3, 2, 2},
                                                  new[] {1, 3, 1, 2, 2, 2}, // 5
                                                  new[] {1, 2, 2, 2, 1, 3},
                                                  new[] {1, 2, 2, 3, 1, 2},
                                                  new[] {1, 3, 2, 2, 1, 2},
                                                  new[] {2, 2, 1, 2, 1, 3},
                                                  new[] {2, 2, 1, 3, 1, 2}, // 10
                                                  new[] {2, 3, 1, 2, 1, 2},
                                                  new[] {1, 1, 2, 2, 3, 2},
                                                  new[] {1, 2, 2, 1, 3, 2},
                                                  new[] {1, 2, 2, 2, 3, 1},
                                                  new[] {1, 1, 3, 2, 2, 2}, // 15
                                                  new[] {1, 2, 3, 1, 2, 2},
                                                  new[] {1, 2, 3, 2, 2, 1},
                                                  new[] {2, 2, 3, 2, 1, 1},
                                                  new[] {2, 2, 1, 1, 3, 2},
                                                  new[] {2, 2, 1, 2, 3, 1}, // 20
                                                  new[] {2, 1, 3, 2, 1, 2},
                                                  new[] {2, 2, 3, 1, 1, 2},
                                                  new[] {3, 1, 2, 1, 3, 1},
                                                  new[] {3, 1, 1, 2, 2, 2},
                                                  new[] {3, 2, 1, 1, 2, 2}, // 25
                                                  new[] {3, 2, 1, 2, 2, 1},
                                                  new[] {3, 1, 2, 2, 1, 2},
                                                  new[] {3, 2, 2, 1, 1, 2},
                                                  new[] {3, 2, 2, 2, 1, 1},
                                                  new[] {2, 1, 2, 1, 2, 3}, // 30
                                                  new[] {2, 1, 2, 3, 2, 1},
                                                  new[] {2, 3, 2, 1, 2, 1},
                                                  new[] {1, 1, 1, 3, 2, 3},
                                                  new[] {1, 3, 1, 1, 2, 3},
                                                  new[] {1, 3, 1, 3, 2, 1}, // 35
                                                  new[] {1, 1, 2, 3, 1, 3},
                                                  new[] {1, 3, 2, 1, 1, 3},
                                                  new[] {1, 3, 2, 3, 1, 1},
                                                  new[] {2, 1, 1, 3, 1, 3},
                                                  new[] {2, 3, 1, 1, 1, 3}, // 40
                                                  new[] {2, 3, 1, 3, 1, 1},
                                                  new[] {1, 1, 2, 1, 3, 3},
                                                  new[] {1, 1, 2, 3, 3, 1},
                                                  new[] {1, 3, 2, 1, 3, 1},
                                                  new[] {1, 1, 3, 1, 2, 3}, // 45
                                                  new[] {1, 1, 3, 3, 2, 1},
                                                  new[] {1, 3, 3, 1, 2, 1},
                                                  new[] {3, 1, 3, 1, 2, 1},
                                                  new[] {2, 1, 1, 3, 3, 1},
                                                  new[] {2, 3, 1, 1, 3, 1}, // 50
                                                  new[] {2, 1, 3, 1, 1, 3},
                                                  new[] {2, 1, 3, 3, 1, 1},
                                                  new[] {2, 1, 3, 1, 3, 1},
                                                  new[] {3, 1, 1, 1, 2, 3},
                                                  new[] {3, 1, 1, 3, 2, 1}, // 55
                                                  new[] {3, 3, 1, 1, 2, 1},
                                                  new[] {3, 1, 2, 1, 1, 3},
                                                  new[] {3, 1, 2, 3, 1, 1},
                                                  new[] {3, 3, 2, 1, 1, 1},
                                                  new[] {3, 1, 4, 1, 1, 1}, // 60
                                                  new[] {2, 2, 1, 4, 1, 1},
                                                  new[] {4, 3, 1, 1, 1, 1},
                                                  new[] {1, 1, 1, 2, 2, 4},
                                                  new[] {1, 1, 1, 4, 2, 2},
                                                  new[] {1, 2, 1, 1, 2, 4}, // 65
                                                  new[] {1, 2, 1, 4, 2, 1},
                                                  new[] {1, 4, 1, 1, 2, 2},
                                                  new[] {1, 4, 1, 2, 2, 1},
                                                  new[] {1, 1, 2, 2, 1, 4},
                                                  new[] {1, 1, 2, 4, 1, 2}, // 70
                                                  new[] {1, 2, 2, 1, 1, 4},
                                                  new[] {1, 2, 2, 4, 1, 1},
                                                  new[] {1, 4, 2, 1, 1, 2},
                                                  new[] {1, 4, 2, 2, 1, 1},
                                                  new[] {2, 4, 1, 2, 1, 1}, // 75
                                                  new[] {2, 2, 1, 1, 1, 4},
                                                  new[] {4, 1, 3, 1, 1, 1},
                                                  new[] {2, 4, 1, 1, 1, 2},
                                                  new[] {1, 3, 4, 1, 1, 1},
                                                  new[] {1, 1, 1, 2, 4, 2}, // 80
                                                  new[] {1, 2, 1, 1, 4, 2},
                                                  new[] {1, 2, 1, 2, 4, 1},
                                                  new[] {1, 1, 4, 2, 1, 2},
                                                  new[] {1, 2, 4, 1, 1, 2},
                                                  new[] {1, 2, 4, 2, 1, 1}, // 85
                                                  new[] {4, 1, 1, 2, 1, 2},
                                                  new[] {4, 2, 1, 1, 1, 2},
                                                  new[] {4, 2, 1, 2, 1, 1},
                                                  new[] {2, 1, 2, 1, 4, 1},
                                                  new[] {2, 1, 4, 1, 2, 1}, // 90
                                                  new[] {4, 1, 2, 1, 2, 1},
                                                  new[] {1, 1, 1, 1, 4, 3},
                                                  new[] {1, 1, 1, 3, 4, 1},
                                                  new[] {1, 3, 1, 1, 4, 1},
                                                  new[] {1, 1, 4, 1, 1, 3}, // 95
                                                  new[] {1, 1, 4, 3, 1, 1},
                                                  new[] {4, 1, 1, 1, 1, 3},
                                                  new[] {4, 1, 1, 3, 1, 1},
                                                  new[] {1, 1, 3, 1, 4, 1},
                                                  new[] {1, 1, 4, 1, 3, 1}, // 100
                                                  new[] {3, 1, 1, 1, 4, 1},
                                                  new[] {4, 1, 1, 1, 3, 1},
                                                  new[] {2, 1, 1, 4, 1, 2},
                                                  new[] {2, 1, 1, 2, 1, 4},
                                                  new[] {2, 1, 1, 2, 3, 2}, // 105
                                                  new[] {2, 3, 3, 1, 1, 1, 2}
                                               };
  
        private static readonly int MAX_AVG_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.25f);
        private static readonly int MAX_INDIVIDUAL_VARIANCE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.7f);
  
        private const int CODE_SHIFT = 98;
  
        private const int CODE_CODE_C = 99;
        private const int CODE_CODE_B = 100;
        private const int CODE_CODE_A = 101;
  
        private const int CODE_FNC_1 = 102;
        private const int CODE_FNC_2 = 97;
        private const int CODE_FNC_3 = 96;
        private const int CODE_FNC_4_A = 101;
        private const int CODE_FNC_4_B = 100;
  
        private const int CODE_START_A = 103;
        private const int CODE_START_B = 104;
        private const int CODE_START_C = 105;
        private const int CODE_STOP = 106;
  
        private static int[] findStartPattern(BitArray row)
        {
           int width = row.Size;
           int rowOffset = row.getNextSet(0);
  
           int counterPosition = 0;
           int[] counters = new int[6];
           int patternStart = rowOffset;
           bool isWhite = false;
           int patternLength = counters.Length;
  
           for (int i = rowOffset; i < width; i++)
           {
              if (row[i] ^ isWhite)
              {
                 counters[counterPosition]++;
              }
              else
              {
                 if (counterPosition == patternLength - 1)
                 {
                    int bestVariance = MAX_AVG_VARIANCE;
                    int bestMatch = -1;
                    for (int startCode = CODE_START_A; startCode <= CODE_START_C; startCode++)
                    {
                       int variance = patternMatchVariance(counters, CODE_PATTERNS[startCode],
                           MAX_INDIVIDUAL_VARIANCE);
                       if (variance < bestVariance)
                       {
                          bestVariance = variance;
                          bestMatch = startCode;
                       }
                    }
                    if (bestMatch >= 0)
                    {
                       // Look for whitespace before start pattern, >= 50% of width of start pattern
                       if (row.isRange(Math.Max(0, patternStart - (i - patternStart) / 2), patternStart,
                           false))
                       {
                          return new int[] { patternStart, i, bestMatch };
                       }
                    }
                    patternStart += counters[0] + counters[1];
                    Array.Copy(counters, 2, counters, 0, patternLength - 2);
                    counters[patternLength - 2] = 0;
                    counters[patternLength - 1] = 0;
                    counterPosition--;
                 }
                 else
                 {
                    counterPosition++;
                 }
                 counters[counterPosition] = 1;
                 isWhite = !isWhite;
              }
           }
           return null;
        }
  
        private static bool decodeCode(BitArray row, int[] counters, int rowOffset, out int code)
        {
           code = -1;
           if (!recordPattern(row, rowOffset, counters))
              return false;
  
           int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
           for (int d = 0; d < CODE_PATTERNS.Length; d++)
           {
              int[] pattern = CODE_PATTERNS[d];
              int variance = patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
              if (variance < bestVariance)
              {
                 bestVariance = variance;
                 code = d;
              }
           }
           // TODO We're overlooking the fact that the STOP pattern has 7 values, not 6.
           return code >= 0;
        }
  
        override public Result decodeRow(int rowNumber, BitArray row, IDictionary<DecodeHintType, object> hints)
        {
           bool convertFNC1 = hints != null && hints.ContainsKey(DecodeHintType.ASSUME_GS1);
  
           int[] startPatternInfo = findStartPattern(row);
           if (startPatternInfo == null)
              return null;
           int startCode = startPatternInfo[2];
           int codeSet;
           switch (startCode)
           {
              case CODE_START_A:
                 codeSet = CODE_CODE_A;
                 break;
              case CODE_START_B:
                 codeSet = CODE_CODE_B;
                 break;
              case CODE_START_C:
                 codeSet = CODE_CODE_C;
                 break;
              default:
                 return null;
           }
  
           bool done = false;
           bool isNextShifted = false;
  
  
gt:          var result = new StringBuilder(20);