/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "../include/utf16reader.h"

namespace ime_pinyin {

#define MIN_BUF_LEN 128
#define MAX_BUF_LEN 65535

Utf16Reader::Utf16Reader() {
  fp_ = NULL;
  buffer_ = NULL;
  buffer_total_len_ = 0;
  buffer_next_pos_ = 0;
  buffer_valid_len_ = 0;
}

Utf16Reader::~Utf16Reader() {
  if (NULL != fp_)
    fclose(fp_);

  if (NULL != buffer_)
    delete [] buffer_;
}


bool Utf16Reader::open(const char* filename, size_t buffer_len) {
  if (filename == NULL)
    return false;

  if (buffer_len < MIN_BUF_LEN)
    buffer_len = MIN_BUF_LEN;
  else if (buffer_len > MAX_BUF_LEN)
    buffer_len = MAX_BUF_LEN;

  buffer_total_len_ = buffer_len;

  if (NULL != buffer_)
    delete [] buffer_;
  buffer_ = new char16[buffer_total_len_];
  if (NULL == buffer_)
    return false;

  if ((fp_ = fopen(filename, "rb")) == NULL)
    return false;

  // the UTF16 file header, skip
  char16 header;
  if (fread(&header, sizeof(header), 1, fp_) != 1 || header != 0xfeff) {
    fclose(fp_);
    fp_ = NULL;
    return false;
  }

  return true;
}

char16* Utf16Reader::readline(char16* read_buf, size_t max_len) {
  if (NULL == fp_ || NULL == read_buf || 0 == max_len)
    return NULL;

  size_t ret_len = 0;

  do {
    if (buffer_valid_len_ == 0) {
      buffer_next_pos_ = 0;
      buffer_valid_len_ = fread(buffer_, sizeof(char16),
                                buffer_total_len_, fp_);
      if (buffer_valid_len_ == 0) {
        if (0 == ret_len)
          return NULL;
        read_buf[ret_len] = (char16)'\0';
        return read_buf;
      }
    }

    for (size_t i = 0; i < buffer_valid_len_; i++) {
      if (i == max_len - 1 ||
          buffer_[buffer_next_pos_ + i] == (char16)'\n') {
        if (ret_len + i > 0 && read_buf[ret_len + i - 1] == (char16)'\r') {
          read_buf[ret_len + i - 1] = (char16)'\0';
        } else {
          read_buf[ret_len + i] = (char16)'\0';
        }

        i++;
        buffer_next_pos_ += i;
        buffer_valid_len_ -= i;
        if (buffer_next_pos_ == buffer_total_len_) {
          buffer_next_pos_ = 0;
          buffer_valid_len_ = 0;
        }
        return read_buf;
      } else {
        read_buf[ret_len + i] = buffer_[buffer_next_pos_ + i];
      }
    }

    ret_len += buffer_valid_len_;
    buffer_valid_len_ = 0;
  } while (true);

  // Never reach here
  return NULL;
}

bool Utf16Reader::close() {
  if (NULL != fp_)
    fclose(fp_);
  fp_ = NULL;

  if (NULL != buffer_)
    delete [] buffer_;
  buffer_ = NULL;
  return true;
}
}  // namespace ime_pinyin
