@SuppressWarnings("null")
  protected void autoAdjustWidthOfColumns(ColumnState[] columnStates, TextTableInfo tableInfo) {

    int tableWidth = tableInfo.getWidth();
    if (tableWidth == TextColumnInfo.WIDTH_AUTO_ADJUST) {
      // if table width is not set (auto adjust) then the width of all columns
      // have to be set...
      for (int i = 0; i < columnStates.length; i++) {
        if (columnStates[i].width == TextColumnInfo.WIDTH_AUTO_ADJUST) {
          // better exception message?
          throw new IllegalArgumentException("Width of table info and column states (" + i + ") can not both be set to auto adjust.");
        }
      }
      return;
    }
    if (tableWidth <= 0) {
      throw new IllegalArgumentException("tableInfo.width==" + tableWidth);
    }
    int autoAdjustColumnCount = 0;
    int staticTableWidth = 0;
    ColumnState lastAutoAdjustColumn = null;
    long autoAdjustColumnTotalTextLength = 0;
    // find columns that need auto adjustment and determine static width
    for (int i = 0; i < columnStates.length; i++) {
      TextColumnInfo columnInfo = columnStates[i].getColumnInfo();
      staticTableWidth = staticTableWidth + columnInfo.getBorderWidth();
      int width = columnStates[i].width;
      if (width == TextColumnInfo.WIDTH_AUTO_ADJUST) {
        autoAdjustColumnCount++;
        lastAutoAdjustColumn = columnStates[i];
        autoAdjustColumnTotalTextLength = autoAdjustColumnTotalTextLength + columnStates[i].getText().length();
      } else {
        staticTableWidth = staticTableWidth + width;
      }
    }

    // remaining width to be divided over the auto-adjust columns
    int widthRemaining = tableWidth - staticTableWidth;
    if (widthRemaining < autoAdjustColumnCount) {
      // there is less than 1 character left for each auto-adjust columns (or
      // less than 0 for no such column).
      throw new IllegalArgumentException(
          "Table width (" + tableWidth + ") may not be less than static width + auto adjust column count (" + (staticTableWidth + autoAdjustColumnCount) + ")");
    }

    // perform auto adjustment...
    if (autoAdjustColumnCount > 0) {
      if (autoAdjustColumnCount == 1) {
        // easy case: single column gets the remaining space
        lastAutoAdjustColumn.width = widthRemaining;
      } else {
        // actual adjustment algorithm ...
        AutoAdjustInfo[] autoAdjustInfoArray = new AutoAdjustInfo[autoAdjustColumnCount];
        int autoAdjustInfoIndex = 0;
        // pass 1
        int widthUsed = 0;
        for (int i = 0; i < columnStates.length; i++) {
          if (columnStates[i].getColumnInfo().getWidth() == TextColumnInfo.WIDTH_AUTO_ADJUST) {
            AutoAdjustInfo autoAdjustInfo = new AutoAdjustInfo(columnStates[i]);
            autoAdjustInfoArray[autoAdjustInfoIndex] = autoAdjustInfo;
            double ratio = autoAdjustInfo.getTextLengthRation(autoAdjustColumnTotalTextLength);
            int calculatedWidth = (int) (widthRemaining * ratio);
            if ((calculatedWidth < 1) && (ratio > 0)) {
              // 0 is simply too small :)
              calculatedWidth = 1;
            }
            if (calculatedWidth > autoAdjustInfo.lineLengthMax) {
              // width of column should never be greater than maximum line
              calculatedWidth = autoAdjustInfo.lineLengthMax;
            }
            autoAdjustInfo.columnState.setWidth(calculatedWidth);
            widthUsed = widthUsed + calculatedWidth;
            autoAdjustInfoIndex++;
          }
        }
        int delta = widthUsed - widthRemaining;
        if (delta != 0) {
          SortedSet<AutoAdjustInfo> autoAdjustInfoSet = new TreeSet<>();
          if (delta > 0) {
            // width is too high because of rounding errors,
            // delta should typically be 1
            for (AutoAdjustInfo autoAdjustInfo : autoAdjustInfoArray) {
              if (autoAdjustInfo.columnState.width >= 2) {
                autoAdjustInfoSet.add(autoAdjustInfo);
              }
            }
            while (delta > 0) {
              Iterator<AutoAdjustInfo> iterator = autoAdjustInfoSet.iterator();
              if (!iterator.hasNext()) {
                throw new IllegalStateException();
              }
              while (iterator.hasNext()) {
                AutoAdjustInfo autoAdjustInfo = iterator.next();
                autoAdjustInfo.columnState.width--;
                delta--;
                if (delta == 0) {
                  return;
                }
                if (autoAdjustInfo.columnState.width < 2) {
                  iterator.remove();
                }
              }
            }
          } else {
            // we have chars left to divide ...
            for (AutoAdjustInfo autoAdjustInfo : autoAdjustInfoArray) {
              if (autoAdjustInfo.columnState.width < autoAdjustInfo.lineLengthMax) {
                autoAdjustInfoSet.add(autoAdjustInfo);
              }
            }
            while (delta < 0) {
              Iterator<AutoAdjustInfo> iterator = autoAdjustInfoSet.iterator();
              if (!iterator.hasNext()) {
                return;
              }
              while (iterator.hasNext()) {
                AutoAdjustInfo autoAdjustInfo = iterator.next();
                autoAdjustInfo.columnState.width++;
                delta++;
                if (delta == 0) {
                  return;
                }
                if (autoAdjustInfo.columnState.width >= autoAdjustInfo.lineLengthMax) {
                  iterator.remove();
                }
              }
            }
          }
        }
      }
    }
  }
@ SuppressWarnings ( "null" ) protected void autoAdjustWidthOfColumns ( ColumnState [ ] columnStates , TextTableInfo tableInfo ) { int tableWidth = tableInfo . getWidth ( ) ; if ( tableWidth == TextColumnInfo . WIDTH_AUTO_ADJUST ) { for ( int i = 0 ; i < columnStates . length ; i ++ ) { if ( columnStates [ i ] . width == TextColumnInfo . WIDTH_AUTO_ADJUST ) { throw new IllegalArgumentException ( "Width of table info and column states (" + i + ") can not both be set to auto adjust." ) ; } } return ; } if ( tableWidth <= 0 ) { throw new IllegalArgumentException ( "tableInfo.width==" + tableWidth ) ; } int autoAdjustColumnCount = 0 ; int staticTableWidth = 0 ; ColumnState lastAutoAdjustColumn = null ; long autoAdjustColumnTotalTextLength = 0 ; for ( int i = 0 ; i < columnStates . length ; i ++ ) { TextColumnInfo columnInfo = columnStates [ i ] . getColumnInfo ( ) ; staticTableWidth = staticTableWidth + columnInfo . getBorderWidth ( ) ; int width = columnStates [ i ] . width ; if ( width == TextColumnInfo . WIDTH_AUTO_ADJUST ) { autoAdjustColumnCount ++ ; lastAutoAdjustColumn = columnStates [ i ] ; autoAdjustColumnTotalTextLength = autoAdjustColumnTotalTextLength + columnStates [ i ] . getText ( ) . length ( ) ; } else { staticTableWidth = staticTableWidth + width ; } } int widthRemaining = tableWidth - staticTableWidth ; if ( widthRemaining < autoAdjustColumnCount ) { throw new IllegalArgumentException ( "Table width (" + tableWidth + ") may not be less than static width + auto adjust column count (" + ( staticTableWidth + autoAdjustColumnCount ) + ")" ) ; } if ( autoAdjustColumnCount > 0 ) { if ( autoAdjustColumnCount == 1 ) { lastAutoAdjustColumn . width = widthRemaining ; } else { AutoAdjustInfo [ ] autoAdjustInfoArray = new AutoAdjustInfo [ autoAdjustColumnCount ] ; int autoAdjustInfoIndex = 0 ; int widthUsed = 0 ; for ( int i = 0 ; i < columnStates . length ; i ++ ) { if ( columnStates [ i ] . getColumnInfo ( ) . getWidth ( ) == TextColumnInfo . WIDTH_AUTO_ADJUST ) { AutoAdjustInfo autoAdjustInfo = new AutoAdjustInfo ( columnStates [ i ] ) ; autoAdjustInfoArray [ autoAdjustInfoIndex ] = autoAdjustInfo ; double ratio = autoAdjustInfo . getTextLengthRation ( autoAdjustColumnTotalTextLength ) ; int calculatedWidth = ( int ) ( widthRemaining * ratio ) ; if ( ( calculatedWidth < 1 ) && ( ratio > 0 ) ) { calculatedWidth = 1 ; } if ( calculatedWidth > autoAdjustInfo . lineLengthMax ) { calculatedWidth = autoAdjustInfo . lineLengthMax ; } autoAdjustInfo . columnState . setWidth ( calculatedWidth ) ; widthUsed = widthUsed + calculatedWidth ; autoAdjustInfoIndex ++ ; } } int delta = widthUsed - widthRemaining ; if ( delta != 0 ) { SortedSet < AutoAdjustInfo > autoAdjustInfoSet = new TreeSet < > ( ) ; if ( delta > 0 ) { for ( AutoAdjustInfo autoAdjustInfo : autoAdjustInfoArray ) { if ( autoAdjustInfo . columnState . width >= 2 ) { autoAdjustInfoSet . add ( autoAdjustInfo ) ; } } while ( delta > 0 ) { Iterator < AutoAdjustInfo > iterator = autoAdjustInfoSet . iterator ( ) ; if ( ! iterator . hasNext ( ) ) { throw new IllegalStateException ( ) ; } while ( iterator . hasNext ( ) ) { AutoAdjustInfo autoAdjustInfo = iterator . next ( ) ; autoAdjustInfo . columnState . width -- ; delta -- ; if ( delta == 0 ) { return ; } if ( autoAdjustInfo . columnState . width < 2 ) { iterator . remove ( ) ; } } } } else { for ( AutoAdjustInfo autoAdjustInfo : autoAdjustInfoArray ) { if ( autoAdjustInfo . columnState . width < autoAdjustInfo . lineLengthMax ) { autoAdjustInfoSet . add ( autoAdjustInfo ) ; } } while ( delta < 0 ) { Iterator < AutoAdjustInfo > iterator = autoAdjustInfoSet . iterator ( ) ; if ( ! iterator . hasNext ( ) ) { return ; } while ( iterator . hasNext ( ) ) { AutoAdjustInfo autoAdjustInfo = iterator . next ( ) ; autoAdjustInfo . columnState . width ++ ; delta ++ ; if ( delta == 0 ) { return ; } if ( autoAdjustInfo . columnState . width >= autoAdjustInfo . lineLengthMax ) { iterator . remove ( ) ; } } } } } } } }
This method calculates the {@link ColumnState#getWidth() width} of the columns to
{@link TextColumnInfo#WIDTH_AUTO_ADJUST auto-adjust}.

@param columnStates are the {@link ColumnState}s.
@param tableInfo is the {@link TextTableInfo} containing the available {@link TextTableInfo#getWidth()
width}.