/// <summary>
 /// Returns a <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.
 /// </summary>
 /// <returns>A <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.</returns>
 /// <param name="barcodeMatrix">Barcode matrix as a jagged array.</param>
 public static String ToString(BarcodeValue[][] barcodeMatrix)
 {
    StringBuilder formatter = new StringBuilder();
    for (int row = 0; row < barcodeMatrix.Length; row++)
    {
       formatter.AppendFormat(CultureInfo.InvariantCulture, "Row {0,2}: ", row);
       for (int column = 0; column < barcodeMatrix[row].Length; column++)
       {
          BarcodeValue barcodeValue = barcodeMatrix[row][column];
          int[] values = barcodeValue.getValue();
          if (values.Length == 0)
          {
             formatter.Append("        ");
          }
          else
          {
             formatter.AppendFormat(CultureInfo.InvariantCulture, "{0,4}({1,2})", values[0], barcodeValue.getConfidence(values[0]));
          }
       }
       formatter.Append("\n");
    }
    return formatter.ToString();
 }
      /// <summary>
      /// Creates the barcode matrix.
      /// </summary>
      /// <returns>The barcode matrix.</returns>
      /// <param name="detectionResult">Detection result.</param>
      private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult)
      {
         // Manually setup Jagged Array in C#
         BarcodeValue[][] barcodeMatrix = new BarcodeValue[detectionResult.RowCount][];
         for (int row = 0; row < barcodeMatrix.Length; row++)
         {
            barcodeMatrix[row] = new BarcodeValue[detectionResult.ColumnCount + 2];
            for (int col = 0; col < barcodeMatrix[row].Length; col++)
            {
               barcodeMatrix[row][col] = new BarcodeValue();
            }
         }

         int column = -1;
         foreach (DetectionResultColumn detectionResultColumn in detectionResult.getDetectionResultColumns())
         {
            column++;
            if (detectionResultColumn == null)
            {
               continue;
            }
            foreach (Codeword codeword in detectionResultColumn.Codewords)
            {
               if (codeword == null || codeword.RowNumber == -1)
               {
                  continue;
               }
               barcodeMatrix[codeword.RowNumber][column].setValue(codeword.Value);
            }
         }
         return barcodeMatrix;
      }
      /// <summary>
      /// Adjusts the codeword count.
      /// </summary>
      /// <param name="detectionResult">Detection result.</param>
      /// <param name="barcodeMatrix">Barcode matrix.</param>
      private static bool adjustCodewordCount(DetectionResult detectionResult, BarcodeValue[][] barcodeMatrix)
      {
         int[] numberOfCodewords = barcodeMatrix[0][1].getValue();
         int calculatedNumberOfCodewords = detectionResult.ColumnCount*
                                           detectionResult.RowCount -
                                           getNumberOfECCodeWords(detectionResult.ErrorCorrectionLevel);
         if (numberOfCodewords.Length == 0)
         {
            if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > PDF417Common.MAX_CODEWORDS_IN_BARCODE)
            {
               return false;
            }
            barcodeMatrix[0][1].setValue(calculatedNumberOfCodewords);
         }
         else if (numberOfCodewords[0] != calculatedNumberOfCodewords)
         {
            // The calculated one is more reliable as it is derived from the row indicator columns
            barcodeMatrix[0][1].setValue(calculatedNumberOfCodewords);
         }

         return true;
      }
      /// <summary>
      /// Creates the barcode matrix.
      /// </summary>
      /// <returns>The barcode matrix.</returns>
      /// <param name="detectionResult">Detection result.</param>
      private static BarcodeValue[][] createBarcodeMatrix(DetectionResult detectionResult)
      {
         // Manually setup Jagged Array in C#
         var barcodeMatrix = new BarcodeValue[detectionResult.RowCount][];
         for (int row = 0; row < barcodeMatrix.Length; row++)
         {
            barcodeMatrix[row] = new BarcodeValue[detectionResult.ColumnCount + 2];
            for (int col = 0; col < barcodeMatrix[row].Length; col++)
            {
               barcodeMatrix[row][col] = new BarcodeValue();
            }
         }

         int column = 0;
         foreach (DetectionResultColumn detectionResultColumn in detectionResult.getDetectionResultColumns())
         {
            if (detectionResultColumn != null)
            {
               foreach (Codeword codeword in detectionResultColumn.Codewords)
               {
                  if (codeword != null)
                  {
                     int rowNumber = codeword.RowNumber;
                     if (rowNumber >= 0)
                     {
                        if (rowNumber >= barcodeMatrix.Length)
                        {
                           // We have more rows than the barcode metadata allows for, ignore them.
                           continue;
                        }
                        barcodeMatrix[rowNumber][column].setValue(codeword.Value);
                     }
                  }
               }
            }
            column++;
         }

         return barcodeMatrix;
      }
 /// <summary>
 /// Gets the barcode metadata.
 /// </summary>
 /// <returns>The barcode metadata.</returns>
 public BarcodeMetadata getBarcodeMetadata()
 {
    var codewords = Codewords;
    BarcodeValue barcodeColumnCount = new BarcodeValue();
    BarcodeValue barcodeRowCountUpperPart = new BarcodeValue();
    BarcodeValue barcodeRowCountLowerPart = new BarcodeValue();
    BarcodeValue barcodeECLevel = new BarcodeValue();
    foreach (Codeword codeword in codewords)
    {
       if (codeword == null)
       {
          continue;
       }
       codeword.setRowNumberAsRowIndicatorColumn();
       int rowIndicatorValue = codeword.Value%30;
       int codewordRowNumber = codeword.RowNumber;
       if (!IsLeft)
       {
          codewordRowNumber += 2;
       }
       switch (codewordRowNumber%3)
       {
          case 0:
             barcodeRowCountUpperPart.setValue(rowIndicatorValue*3 + 1);
             break;
          case 1:
             barcodeECLevel.setValue(rowIndicatorValue/3);
             barcodeRowCountLowerPart.setValue(rowIndicatorValue%3);
             break;
          case 2:
             barcodeColumnCount.setValue(rowIndicatorValue + 1);
             break;
       }
    }
    // Maybe we should check if we have ambiguous values?
    var barcodeColumnCountValues = barcodeColumnCount.getValue();
    var barcodeRowCountUpperPartValues = barcodeRowCountUpperPart.getValue();
    var barcodeRowCountLowerPartValues = barcodeRowCountLowerPart.getValue();
    var barcodeECLevelValues = barcodeECLevel.getValue();
    if ((barcodeColumnCountValues.Length == 0) ||
        (barcodeRowCountUpperPartValues.Length == 0) ||
        (barcodeRowCountLowerPartValues.Length == 0) ||
        (barcodeECLevelValues.Length == 0) ||
         barcodeColumnCountValues[0] < 1 ||
         barcodeRowCountUpperPartValues[0] + barcodeRowCountLowerPartValues[0] < PDF417Common.MIN_ROWS_IN_BARCODE ||
         barcodeRowCountUpperPartValues[0] + barcodeRowCountLowerPartValues[0] > PDF417Common.MAX_ROWS_IN_BARCODE)
    {
       return null;
    }
    var barcodeMetadata = new BarcodeMetadata(barcodeColumnCountValues[0],
                                              barcodeRowCountUpperPartValues[0],
                                              barcodeRowCountLowerPartValues[0],
                                              barcodeECLevelValues[0]);
    removeIncorrectCodewords(codewords, barcodeMetadata);
    return barcodeMetadata;
 }
 /// <summary>
 /// Returns a <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.
 /// </summary>
 /// <returns>A <see cref="System.String"/> that represents the <see cref="ZXing.PDF417.Internal.BarcodeValue"/> jagged array.</returns>
 /// <param name="barcodeMatrix">Barcode matrix as a jagged array.</param>
 public static String ToString(BarcodeValue[][] barcodeMatrix)
 {
     StringBuilder formatter = new StringBuilder();
     for (int row = 0; row < barcodeMatrix.Length; row++)
     {
         formatter.AppendFormat("Row {0,2}: ", row);
         for (int column = 0; column < barcodeMatrix[row].Length; column++)
         {
             BarcodeValue barcodeValue = barcodeMatrix[row][column];
             if (barcodeValue.GetValue().Length == 0)
             {
                 formatter.Append("        ");
             } else
             {
                 formatter.AppendFormat("{0,4}({0,3})", barcodeValue.GetValue()[0], barcodeValue.GetConfidence(barcodeValue.GetValue()[0]));
             }
         }
         formatter.Append("\n");
     }
     return formatter.ToString();
 }