docs: private static int calculateBinaryString(int[] inputData, StringBuilder binaryString) {
  
          EncodeMode last_mode = EncodeMode.NUMERIC;
          int encoding_method, i, j, read_posn;
          boolean latch;
          int remainder, d1, d2, value;
          String padstring;
          double weight;
          int group_val;
          int current_length;
  
          read_posn = 0;
  
          /* Decide whether a compressed data field is required and if so what method to use - method 2 = no compressed data field */
  
          if (inputData.length >= 16 && inputData[0] == '0' && inputData[1] == '1') {
              /* (01) and other AIs */
              encoding_method = 1;
          } else {
              /* any AIs */
              encoding_method = 2;
          }
  
          if (inputData.length >= 20 && encoding_method == 1 && inputData[2] == '9' && inputData[16] == '3') {
              /* Possibly encoding method > 2 */
  
              if (inputData.length >= 26 && inputData[17] == '1') {
                  /* Methods 3, 7, 9, 11 and 13 */
  
                  if (inputData[18] == '0') {
                      /* (01) and (310x) */
                      /* In kilos */
  
                      weight = 0.0;
                      for (i = 0; i < 6; i++) {
                          weight *= 10;
                          weight += (inputData[20 + i] - '0');
                      }
  
                      if (weight < 99999.0) { /* Maximum weight = 99999 */
  
                          if (inputData[19] == '3' && inputData.length == 26) {
                              /* (01) and (3103) */
                              weight /= 1000.0;
                              if (weight <= 32.767) {
                                  encoding_method = 3;
                              }
                          }
  
                          if (inputData.length == 34) {
                              if (inputData[26] == '1' && inputData[27] == '1') {
                                  /* (01), (310x) and (11) - metric weight and production date */
                                  encoding_method = 7;
                              }
                              if (inputData[26] == '1' && inputData[27] == '3') {
                                  /* (01), (310x) and (13) - metric weight and packaging date */
                                  encoding_method = 9;
                              }
                              if (inputData[26] == '1' && inputData[27] == '5') {
                                  /* (01), (310x) and (15) - metric weight and "best before" date */
                                  encoding_method = 11;
                              }
                              if (inputData[26] == '1' && inputData[27] == '7') {
                                  /* (01), (310x) and (17) - metric weight and expiration date */
                                  encoding_method = 13;
                              }
                          }
                      }
                  }
              }
  
              if (inputData.length >= 26 && inputData[17] == '2') {
                  /* Methods 4, 8, 10, 12 and 14 */
  
                  if (inputData[18] == '0') {
                      /* (01) and (320x) */
                      /* In pounds */
  
                      weight = 0.0;
                      for (i = 0; i < 6; i++) {
                          weight *= 10;
                          weight += (inputData[20 + i] - '0');
                      }
  
                      if (weight < 99999.0) { /* Maximum weight = 99999 */
  
                          if (((inputData[19] == '2') || (inputData[19] == '3'))
                                  && (inputData.length == 26)) {
                              /* (01) and (3202)/(3203) */
  
                              if (inputData[19] == '3') {
                                  weight /= 1000.0;
                                  if (weight <= 22.767) {
                                      encoding_method = 4;
                                  }
                              } else {
                                  weight /= 100.0;
                                  if (weight <= 99.99) {
                                      encoding_method = 4;
                                  }
                              }
  
                          }
  
                          if (inputData.length == 34) {
                              if (inputData[26] == '1' && inputData[27] == '1') {
                                  /* (01), (320x) and (11) - English weight and production date */
                                  encoding_method = 8;
                              }
                              if (inputData[26] == '1' && inputData[27] == '3') {
                                  /* (01), (320x) and (13) - English weight and packaging date */
                                  encoding_method = 10;
                              }
                              if (inputData[26] == '1' && inputData[27] == '5') {
                                  /* (01), (320x) and (15) - English weight and "best before" date */
                                  encoding_method = 12;
                              }
                              if (inputData[26] == '1' && inputData[27] == '7') {
                                  /* (01), (320x) and (17) - English weight and expiration date */
                                  encoding_method = 14;
                              }
                          }
                      }
                  }
              }
  
              if (inputData[17] == '9') {
                  /* Methods 5 and 6 */
                  if (inputData[18] == '2' && inputData[19] >= '0' && inputData[19] <= '3') {
                      /* (01) and (392x) */
                      encoding_method = 5;
                  }
                  if (inputData[18] == '3' && inputData[19] >= '0' && inputData[19] <= '3') {
                      /* (01) and (393x) */
                      encoding_method = 6;
                  }
              }
          }
  
          switch (encoding_method) { /* Encoding method - Table 10 */
          case 1:
              binaryString.append("1XX");
              read_posn = 16;
              break;
          case 2:
              binaryString.append("00XX");
              read_posn = 0;
              break;
          case 3:
              binaryString.append("0100");
              read_posn = inputData.length;
              break;
          case 4:
              binaryString.append("0101");
              read_posn = inputData.length;
              break;
          case 5:
              binaryString.append("01100XX");
              read_posn = 20;
              break;
          case 6:
              binaryString.append("01101XX");
              read_posn = 23;
              break;
          case 7:
              binaryString.append("0111000");
              read_posn = inputData.length;
              break;
          case 8:
              binaryString.append("0111001");
              read_posn = inputData.length;
              break;
          case 9:
              binaryString.append("0111010");
              read_posn = inputData.length;
              break;
          case 10:
              binaryString.append("0111011");
              read_posn = inputData.length;
              break;
          case 11:
              binaryString.append("0111100");
              read_posn = inputData.length;
              break;
          case 12:
              binaryString.append("0111101");
              read_posn = inputData.length;
              break;
          case 13:
              binaryString.append("0111110");
              read_posn = inputData.length;
              break;
          case 14:
              binaryString.append("0111111");
              read_posn = inputData.length;
              break;
          }
  
          /* Variable length symbol bit field is just given a place holder (XX) for the time being */
  
          /* Verify that the data to be placed in the compressed data field is all numeric data before carrying out compression */
          for (i = 0; i < read_posn; i++) {
              if (inputData[i] < '0' || inputData[i] > '9') {
                  /* Something is wrong */
                  throw new OkapiException("Invalid characters in input data");
              }
          }
  
          /* Now encode the compressed data field */
          if (encoding_method == 1) {
              /* Encoding method field "1" - general item identification data */
              group_val = inputData[2] - '0';
  
              for (j = 0; j < 4; j++) {
                  if ((group_val & (0x08 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += inputData[(i * 3) + 2] - '0';
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
          }
  
          if (encoding_method == 3) {
              /* Encoding method field "0100" - variable weight item (0,001 kilogram increments) */
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += (inputData[(i * 3) + 2] - '0');
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
  
              group_val = 0;
              for (i = 0; i < 6; i++) {
                  group_val *= 10;
                  group_val += inputData[20 + i] - '0';
              }
  
              for (j = 0; j < 15; j++) {
                  if ((group_val & (0x4000 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
          }
  
          if (encoding_method == 4) {
              /* Encoding method field "0101" - variable weight item (0,01 or 0,001 pound increment) */
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += (inputData[(i * 3) + 2] - '0');
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
  
  
              group_val = 0;
              for (i = 0; i < 6; i++) {
                  group_val *= 10;
                  group_val += inputData[20 + i] - '0';
              }
  
              if (inputData[19] == '3') {
                  group_val = group_val + 10000;
              }
  
              for (j = 0; j < 15; j++) {
                  if ((group_val & (0x4000 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
          }
  
          if (encoding_method >= 7 && encoding_method <= 14) {
              /* Encoding method fields "0111000" through "0111111" - variable weight item plus date */
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += (inputData[(i * 3) + 2] - '0');
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
  
              group_val = inputData[19] - '0';
  
              for (i = 0; i < 5; i++) {
                  group_val *= 10;
                  group_val += inputData[21 + i] - '0';
              }
  
              for (j = 0; j < 20; j++) {
                  if ((group_val & (0x80000 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
  
              if (inputData.length == 34) {
                  /* Date information is included */
                  group_val = ((10 * (inputData[28] - '0')) + (inputData[29] - '0')) * 384;
                  group_val += (((10 * (inputData[30] - '0')) + (inputData[31] - '0')) - 1) * 32;
                  group_val += (10 * (inputData[32] - '0')) + (inputData[33] - '0');
              } else {
                  group_val = 38400;
              }
  
              for (j = 0; j < 16; j++) {
                  if ((group_val & (0x8000 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
          }
  
          if (encoding_method == 5) {
              /* Encoding method field "01100" - variable measure item and price */
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += (inputData[(i * 3) + 2] - '0');
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
  
              switch (inputData[19]) {
                  case '0':
                      binaryString.append("00");
                      break;
                  case '1':
                      binaryString.append("01");
                      break;
                  case '2':
                      binaryString.append("10");
                      break;
                  case '3':
                      binaryString.append("11");
                      break;
              }
          }
  
          if (encoding_method == 6) {
              /* Encoding method "01101" - variable measure item and price with ISO 4217 currency code */
  
              for (i = 1; i < 5; i++) {
                  group_val = 100 * (inputData[i * 3] - '0');
                  group_val += 10 * (inputData[(i * 3) + 1] - '0');
                  group_val += (inputData[(i * 3) + 2] - '0');
  
                  for (j = 0; j < 10; j++) {
                      if ((group_val & (0x200 >> j)) == 0) {
                          binaryString.append('0');
                      } else {
                          binaryString.append('1');
                      }
                  }
              }
  
              switch (inputData[19]) {
                  case '0':
                      binaryString.append("00");
                      break;
                  case '1':
                      binaryString.append("01");
                      break;
                  case '2':
                      binaryString.append("10");
                      break;
                  case '3':
                      binaryString.append("11");
                      break;
              }
  
              group_val = 0;
              for (i = 0; i < 3; i++) {
                  group_val *= 10;
                  group_val += inputData[20 + i] - '0';
              }
  
              for (j = 0; j < 10; j++) {
                  if ((group_val & (0x200 >> j)) == 0) {
                      binaryString.append('0');
                  } else {
                      binaryString.append('1');
                  }
              }
          }
  
          /* The compressed data field has been processed if appropriate - the rest of the data (if any) goes into a general-purpose data compaction field */
  
          int[] generalField = Arrays.copyOfRange(inputData, read_posn, inputData.length);
          EncodeMode[] generalFieldType = new EncodeMode[generalField.length];
  
          if (generalField.length != 0) {
  
              latch = false;
              for (i = 0; i < generalField.length; i++) {
                  /* Tables 11, 12, 13 - ISO/IEC 646 encodation */
                  int c = generalField[i];
                  EncodeMode mode;
                  if (c == FNC1) {
                      // FNC1 can be encoded in any system
                      mode = EncodeMode.ANY_ENC;
                  } else if (c >= '0' && c <= '9') {
                      // numbers can be encoded in any system, but will usually narrow down to numeric encodation
                      mode = EncodeMode.ANY_ENC;
                  } else if ((c >= 'A' && c <= 'Z') || c == '*' || c == ',' || c == '-' || c == '.' || c == '/') {
                      // alphanumeric encodation or ISO/IEC encodation
                      mode = EncodeMode.ALPHA_OR_ISO;
                  } else if ((c >= 'a' && c <= 'z') || c == '!' || c == '"' || c == '%' || c == '&' || c == '\'' ||
                              c == '(' || c == ')' || c == '+' || c == ':' || c == ';' || c == '<' || c == '=' ||
                              c == '>' || c == '?' || c == '_' || c == ' ') {
                      // ISO/IEC encodation
                      mode = EncodeMode.ISOIEC;
                  } else {
                      // unable to encode this character
                      mode = EncodeMode.INVALID_CHAR;
                      latch = true;
                  }
                  generalFieldType[i] = mode;
              }
  
              if (latch) {
                  throw new OkapiException("Invalid characters in input data");
              }
  
              for (i = 0; i < generalField.length - 1; i++) {
                  if (generalFieldType[i] == EncodeMode.ISOIEC && generalField[i + 1] == FNC1) {
                      generalFieldType[i + 1] = EncodeMode.ISOIEC;
                  }
              }
  
              for (i = 0; i < generalField.length - 1; i++) {
                  if (generalFieldType[i] == EncodeMode.ALPHA_OR_ISO && generalField[i + 1] == FNC1) {
                      generalFieldType[i + 1] = EncodeMode.ALPHA_OR_ISO;
                  }
              }
  
              latch = applyGeneralFieldRules(generalFieldType); // modifies generalFieldType
  
              /* Set initial mode if not NUMERIC */
              if (generalFieldType[0] == EncodeMode.ALPHA) {
                  binaryString.append("0000"); /* Alphanumeric latch */
                  last_mode = EncodeMode.ALPHA;
              }
              if (generalFieldType[0] == EncodeMode.ISOIEC) {
                  binaryString.append("0000"); /* Alphanumeric latch */
                  binaryString.append("00100"); /* ISO/IEC 646 latch */
                  last_mode = EncodeMode.ISOIEC;
              }
  
              i = 0;
              do {
                  switch (generalFieldType[i]) {
                  case NUMERIC:
                      if (last_mode != EncodeMode.NUMERIC) {
                          binaryString.append("000"); /* Numeric latch */
                      }
  
                      if (generalField[i] != FNC1) {
                          d1 = generalField[i] - '0';
                      } else {
                          d1 = 10;
                      }
  
                      if (generalField[i + 1] != FNC1) {
                          d2 = generalField[i + 1] - '0';
                      } else {
                          d2 = 10;
                      }
  
                      value = (11 * d1) + d2 + 8;
  
                      for (j = 0; j < 7; j++) {
                          if ((value & (0x40 >> j)) != 0) {
                              binaryString.append('1');
                          } else {
                              binaryString.append('0');
                          }
                      }
  
                      i += 2;
                      last_mode = EncodeMode.NUMERIC;
                      break;
  
                  case ALPHA:
                      if (i != 0) {
                          if (last_mode == EncodeMode.NUMERIC) {
                              binaryString.append("0000"); /* Alphanumeric latch */
                          }
                          if (last_mode == EncodeMode.ISOIEC) {
                              binaryString.append("00100"); /* Alphanumeric latch */
                          }
                      }
  
                      if (generalField[i] >= '0' && generalField[i] <= '9') {
  
                          value = generalField[i] - 43;
  
                          for (j = 0; j < 5; j++) {
                              if ((value & (0x10 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
  
                      if (generalField[i] >= 'A' && generalField[i] <= 'Z') {
  
                          value = generalField[i] - 33;
  
                          for (j = 0; j < 6; j++) {
                              if ((value & (0x20 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
  
                      last_mode = EncodeMode.ALPHA;
                      if (generalField[i] == FNC1) {
                          binaryString.append("01111");
                      } /* FNC1 / Numeric latch */
  
                      if (generalField[i] == '*') binaryString.append("111010"); /* asterisk */
                      if (generalField[i] == ',') binaryString.append("111011"); /* comma */
                      if (generalField[i] == '-') binaryString.append("111100"); /* minus or hyphen */
                      if (generalField[i] == '.') binaryString.append("111101"); /* period or full stop */
                      if (generalField[i] == '/') binaryString.append("111110"); /* slash or solidus */
  
                      i++;
                      break;
  
                  case ISOIEC:
                      if (i != 0) {
                          if (last_mode == EncodeMode.NUMERIC) {
                              binaryString.append("0000"); /* Alphanumeric latch */
                              binaryString.append("00100"); /* ISO/IEC 646 latch */
                          }
                          if (last_mode == EncodeMode.ALPHA) {
                              binaryString.append("00100"); /* ISO/IEC 646 latch */
                          }
                      }
  
                      if (generalField[i] >= '0' && generalField[i] <= '9') {
  
                          value = generalField[i] - 43;
  
                          for (j = 0; j < 5; j++) {
                              if ((value & (0x10 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
  
                      if (generalField[i] >= 'A' && generalField[i] <= 'Z') {
  
                          value = generalField[i] - 1;
  
                          for (j = 0; j < 7; j++) {
                              if ((value & (0x40 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
  
                      if (generalField[i] >= 'a' && generalField[i] <= 'z') {
  
                          value = generalField[i] - 7;
  
                          for (j = 0; j < 7; j++) {
                              if ((value & (0x40 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
  
                      last_mode = EncodeMode.ISOIEC;
                      if (generalField[i] == FNC1) {
                          binaryString.append("01111");
                      } /* FNC1 / Numeric latch */
  
                      if (generalField[i] == '!') binaryString.append("11101000"); /* exclamation mark */
                      if (generalField[i] == 34)  binaryString.append("11101001"); /* quotation mark */
                      if (generalField[i] == 37)  binaryString.append("11101010"); /* percent sign */
                      if (generalField[i] == '&') binaryString.append("11101011"); /* ampersand */
                      if (generalField[i] == 39)  binaryString.append("11101100"); /* apostrophe */
                      if (generalField[i] == '(') binaryString.append("11101101"); /* left parenthesis */
                      if (generalField[i] == ')') binaryString.append("11101110"); /* right parenthesis */
                      if (generalField[i] == '*') binaryString.append("11101111"); /* asterisk */
                      if (generalField[i] == '+') binaryString.append("11110000"); /* plus sign */
                      if (generalField[i] == ',') binaryString.append("11110001"); /* comma */
                      if (generalField[i] == '-') binaryString.append("11110010"); /* minus or hyphen */
                      if (generalField[i] == '.') binaryString.append("11110011"); /* period or full stop */
                      if (generalField[i] == '/') binaryString.append("11110100"); /* slash or solidus */
                      if (generalField[i] == ':') binaryString.append("11110101"); /* colon */
                      if (generalField[i] == ';') binaryString.append("11110110"); /* semicolon */
                      if (generalField[i] == '<') binaryString.append("11110111"); /* less-than sign */
                      if (generalField[i] == '=') binaryString.append("11111000"); /* equals sign */
                      if (generalField[i] == '>') binaryString.append("11111001"); /* greater-than sign */
                      if (generalField[i] == '?') binaryString.append("11111010"); /* question mark */
                      if (generalField[i] == '_') binaryString.append("11111011"); /* underline or low line */
                      if (generalField[i] == ' ') binaryString.append("11111100"); /* space */
  
                      i++;
                      break;
                  }
                  current_length = i;
                  if (latch) {
                      current_length++;
                  }
              } while (current_length < generalField.length);
  
              remainder = calculateRemainder(binaryString.length());
  
              if (latch) {
                  /* There is still one more numeric digit to encode */
                  if (last_mode == EncodeMode.NUMERIC) {
                      if ((remainder >= 4) && (remainder <= 6)) {
                          value = generalField[i] - '0';
                          value++;
  
                          for (j = 0; j < 4; j++) {
                              if ((value & (0x08 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      } else {
                          d1 = generalField[i] - '0';
                          d2 = 10;
  
                          value = (11 * d1) + d2 + 8;
  
                          for (j = 0; j < 7; j++) {
                              if ((value & (0x40 >> j)) != 0) {
                                  binaryString.append('1');
                              } else {
                                  binaryString.append('0');
                              }
                          }
                      }
                  } else {
                      value = generalField[i] - 43;
  
                      for (j = 0; j < 5; j++) {
                          if ((value & (0x10 >> j)) != 0) {
                              binaryString.append('1');
                          } else {
                              binaryString.append('0');
                          }
                      }
                  }
              }
          }
  
          if (binaryString.length() > 252) {
              throw new OkapiException("Input too long");
          }
  
          remainder = calculateRemainder(binaryString.length());
  
          /* Now add padding to binary string (7.2.5.5.4) */
          i = remainder;
          if ((generalField.length != 0) && (last_mode == EncodeMode.NUMERIC)) {
              padstring = "0000";
              i -= 4;
          } else {
              padstring = "";
          }
          for (; i > 0; i -= 5) {
              padstring += "00100";
          }
  
          binaryString.append(padstring.substring(0, remainder));
  
          /* Patch variable length symbol bit field */
          char patchEvenOdd, patchSize;
          if ((((binaryString.length() / 12) + 1) & 1) == 0) {
              patchEvenOdd = '0';
          } else {
              patchEvenOdd = '1';
          }
          if (binaryString.length() <= 156) {
              patchSize = '0';
          } else {
              patchSize = '1';
          }
  
          if (encoding_method == 1) {
              binaryString.setCharAt(2, patchEvenOdd);
              binaryString.setCharAt(3, patchSize);
          }
          if (encoding_method == 2) {
              binaryString.setCharAt(3, patchEvenOdd);
              binaryString.setCharAt(4, patchSize);
          }
          if (encoding_method == 5 || encoding_method == 6) {
              binaryString.setCharAt(6, patchEvenOdd);
              binaryString.setCharAt(7, patchSize);
          }
  
          return encoding_method;
      }