/**
   * @param clazz the class to be handled (read from and wrote to)
   * @param file the file to be processed
   */
  public void handleConfig(Class<?> clazz, File file) {
    if (!hasRun) {
      hasRun = true;
      for (Field field : clazz.getDeclaredFields()) {
        for (Annotation annotation : field.getAnnotations()) {
          if (annotation.annotationType() == Config.String.class)
            handleString(clazz, field, (Config.String) annotation);
          else if (annotation.annotationType() == Config.Integer.class)
            handleInteger(clazz, field, (Config.Integer) annotation);
          else if (annotation.annotationType() == Config.Boolean.class)
            handleBoolean(clazz, field, (Config.Boolean) annotation);
          else if (annotation.annotationType() == Config.List.class)
            handleList(clazz, field, (Config.List) annotation);
          else if (annotation.annotationType() == Config.Map.class)
            handleMap(clazz, field, (Config.Map) annotation);
          else if (annotation.annotationType() == Config.Long.class)
            handleLong(clazz, field, (Config.Long) annotation);
          else if (annotation.annotationType() == Config.Float.class)
            handleFloat(clazz, field, (Config.Float) annotation);
          else if (annotation.annotationType() == Config.Double.class)
            handleDouble(clazz, field, (Config.Double) annotation);
          else if (annotation.annotationType() == Config.Character.class)
            handleCharacter(clazz, field, (Config.Character) annotation);
        }
      }
    }

    try (BufferedReader reader =
        new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
      String line;
      while ((line = reader.readLine()) != null) {
        if (line.contains("{")) {
          char[] chars = line.toCharArray();
          boolean hasNotEncounteredText = true;
          StringBuilder stringBuilder = new StringBuilder();
          for (Character character : chars) {
            if ((!character.equals(' ') && !character.equals('\t')) || hasNotEncounteredText) {
              hasNotEncounteredText = false;
              stringBuilder.append(character);
            } else if (character.equals(' ')) break;
          }
          categories
              .getOrDefault(stringBuilder.toString(), categories.get("General"))
              .read(clazz, reader);
        }
      }
    } catch (IOException ignored) {
    }

    StringBuilder stringBuilder = new StringBuilder();
    categories.values().forEach(category -> category.write(stringBuilder));
    String fileString = stringBuilder.toString();

    try (BufferedWriter writer =
        new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
      writer.append(fileString);
    } catch (IOException ignored) {
    }
  }
  /**
   * Move the cursor <i>where</i> characters, withough checking the current buffer.
   *
   * @see #where
   * @param where the number of characters to move to the right or left.
   */
  private final void moveInternal(final int where) throws IOException {
    // debug ("move cursor " + where + " ("
    // + buf.cursor + " => " + (buf.cursor + where) + ")");
    buf.cursor += where;

    char c;

    if (where < 0) {
      int len = 0;
      for (int i = buf.cursor; i < buf.cursor - where; i++) {
        if (buf.getBuffer().charAt(i) == '\t') len += TAB_WIDTH;
        else len++;
      }

      char cbuf[] = new char[len];
      Arrays.fill(cbuf, BACKSPACE);
      out.write(cbuf);

      return;
    } else if (buf.cursor == 0) {
      return;
    } else if (mask != null) {
      c = mask.charValue();
    } else {
      printCharacters(buf.buffer.substring(buf.cursor - where, buf.cursor).toCharArray());
      return;
    }

    // null character mask: don't output anything
    if (NULL_MASK.equals(mask)) {
      return;
    }

    printCharacters(c, Math.abs(where));
  }