namespace mozc {
using commands::KeyEvent;

namespace {

using config::Config;

vector<KeyInformation> ExtractSortedDirectModeKeysFromStream(istream *ifs) {
  const char kModeDirect[] = "Direct";
  const char kModeDirectInput[] = "DirectInput";

  vector<KeyInformation> result;

  string line;
  getline(*ifs, line);  // Skip the first line.
  while (!ifs->eof()) {
    getline(*ifs, line);
    Util::ChopReturns(&line);
    if (line.empty() || line[0] == '#') {
      // empty or comment
      continue;
    }
    vector<string> rules;
    Util::SplitStringUsing(line, "\t", &rules);
    if (rules.size() != 3) {
      LOG(ERROR) << "Invalid format: " << line;
      continue;
    }
    if (!(rules[0] == kModeDirect || rules[0] == kModeDirectInput)) {
      continue;
    }
    commands::KeyEvent key_event;
    if (KeyParser::ParseKey(rules[1], &key_event)) {
      KeyInformation info;
      if (KeyEventUtil::GetKeyInformation(key_event, &info)) {
        result.push_back(info);
      }
    }
  }

  sort(result.begin(), result.end());
  return result;
}

vector<KeyInformation> ExtractSortedDirectModeKeysFromFile(
      const string &filename) {
  scoped_ptr<istream> ifs(ConfigFileStream::LegacyOpen(filename));
  if (ifs.get() == NULL) {
    DLOG(FATAL) << "could not open file: " << filename;
    return vector<KeyInformation>();
  }
  return ExtractSortedDirectModeKeysFromStream(ifs.get());
}

}  // namespace

vector<KeyInformation> KeyInfoUtil::ExtractSortedDirectModeKeys(
    const config::Config &config) {
  const config::Config::SessionKeymap &keymap = config.session_keymap();
  if (keymap == Config::CUSTOM) {
    const string &custom_keymap_table = config.custom_keymap_table();
    if (custom_keymap_table.empty()) {
      LOG(WARNING) << "custom_keymap_table is empty. use default setting";
      const char *default_keymapfile = keymap::KeyMapManager::GetKeyMapFileName(
          config::ConfigHandler::GetDefaultKeyMap());
      return ExtractSortedDirectModeKeysFromFile(default_keymapfile);
    }
    istringstream ifs(custom_keymap_table);
    return ExtractSortedDirectModeKeysFromStream(&ifs);
  }
  const char *keymap_file = keymap::KeyMapManager::GetKeyMapFileName(keymap);
  return ExtractSortedDirectModeKeysFromFile(keymap_file);
}

bool KeyInfoUtil::ContainsKey(const vector<KeyInformation> &sorted_keys,
                              const commands::KeyEvent &key_event) {
  KeyInformation key_info;
  if (!KeyEventUtil::GetKeyInformation(key_event, &key_info)) {
    return false;
  }
  return binary_search(sorted_keys.begin(), sorted_keys.end(), key_info);
}

}  // namespace mozc
