private void flushLineBuffer() throws IOException {
   int rest = lineBuffer.length();
   int cursor = 0;
   while (rest > 0) {
     int chunkSize = Math.min(rest, writeBuffer.length);
     lineBuffer.getChars(cursor, cursor + chunkSize, writeBuffer, 0);
     writer.write(writeBuffer, 0, chunkSize);
     rest -= chunkSize;
     cursor += chunkSize;
   }
   lineBuffer.setLength(0);
 }
 private void emitTime(int sec) {
   fill('0', HOUR_FIELD_LENGTH, sec / (60 * 60));
   lineBuffer.append(TIME_FIELD_SEPARATOR);
   fill('0', MINUTE_FIELD_LENGTH, sec / 60 % 60);
   lineBuffer.append(TIME_FIELD_SEPARATOR);
   fill('0', SECOND_FIELD_LENGTH, sec % 60);
 }
 private boolean emitNull(ValueOption<?> option) {
   if (option.isNull()) {
     lineBuffer.append(ESCAPE_CHAR);
     lineBuffer.append(ESCAPE_NULL_COLUMN);
     return true;
   }
   return false;
 }
  private void emitDate(int days) {
    int year = DateUtil.getYearFromDay(days);
    int daysInYear = days - DateUtil.getDayFromYear(year);
    boolean leap = DateUtil.isLeap(year);
    int month = DateUtil.getMonthOfYear(daysInYear, leap);
    int day = DateUtil.getDayOfMonth(daysInYear, leap);

    fill('0', YEAR_FIELD_LENGTH, year);
    lineBuffer.append(DATE_FIELD_SEPARATOR);
    fill('0', MONTH_FIELD_LENGTH, month);
    lineBuffer.append(DATE_FIELD_SEPARATOR);
    fill('0', DATE_FIELD_LENGTH, day);
  }
 @Override
 public void emit(DoubleOption option) throws IOException {
   startCell();
   if (emitNull(option)) {
     return;
   }
   lineBuffer.append(option.get());
 }
 @Override
 public void emit(BooleanOption option) throws IOException {
   startCell();
   if (emitNull(option)) {
     return;
   }
   lineBuffer.append(option.get() ? BOOLEAN_TRUE : BOOLEAN_FALSE);
 }
 @Override
 public void emit(DecimalOption option) throws IOException {
   startCell();
   if (emitNull(option)) {
     return;
   }
   // TODO BigDecimal
   lineBuffer.append(option.get());
 }
  @Override
  public void emit(DateTimeOption option) throws IOException {
    startCell();
    if (emitNull(option)) {
      return;
    }
    long seconds = option.get().getElapsedSeconds();
    int days = DateUtil.getDayFromSeconds(seconds);
    emitDate(days);

    lineBuffer.append(DATE_TIME_SEPARATOR);

    int sec = DateUtil.getSecondOfDay(seconds);
    emitTime(sec);
  }
 private void consumeDecoded() {
   decodeBuffer.flip();
   if (decodeBuffer.hasRemaining()) {
     char[] array = decodeBuffer.array();
     for (int i = decodeBuffer.position(), n = decodeBuffer.limit(); i < n; i++) {
       char c = array[i];
       if (c == '\t') {
         lineBuffer.append(ESCAPE_CHAR);
         lineBuffer.append(ESCAPE_HT);
       } else if (c == '\n') {
         lineBuffer.append(ESCAPE_CHAR);
         lineBuffer.append(ESCAPE_LF);
       } else if (c == '\\') {
         lineBuffer.append(ESCAPE_CHAR);
         lineBuffer.append(ESCAPE_CHAR);
       } else {
         lineBuffer.append(c);
       }
     }
   }
   decodeBuffer.clear();
 }
 private void fill(char filler, int columns, int value) {
   for (int i = 0, n = countToFill(columns, value); i < n; i++) {
     lineBuffer.append(filler);
   }
   lineBuffer.append(value);
 }
 private void startCell() {
   if (headOfLine == false) {
     lineBuffer.append(CELL_SEPARATOR);
   }
   headOfLine = false;
 }