namespace windycode {
class INIConfig {
  typedef std::unordered_map<std::string,
                             std::unordered_map<std::string, std::string>>
      StorageType;

public:
  INIConfig();
  ~INIConfig();
  bool parse(string_ref FileName);
  bool save(string_ref FileName);

  bool has(const string_ref SectionName, const string_ref &Key) const {
    return find(SectionName, Key);
  }

  string_ref get(const string_ref SectionName, const string_ref &Key) const {
    auto Pos = find(SectionName, Key);
    if (!Pos)
      return string_ref();
    return string_ref(*Pos);
  }

  void set(const string_ref SectionName, const string_ref &Key,
           const string_ref &Value) {
    auto SectionPos = Storage.find(SectionName);
    if (SectionPos == Storage.end()) {
      std::unordered_map<std::string, std::string> KeyValueMap{
          std::make_pair<std::string, std::string>(Key, Value)};
      Storage.emplace(SectionName.str(), std::move(KeyValueMap));
      return;
    }
    auto &SectionStorage = SectionPos->second;
    auto Pos = SectionStorage.find(Key);
    if (Pos == SectionStorage.end())
      SectionStorage.emplace(
          std::make_pair<std::string, std::string>(Key, Value));
    else
      Pos->second = Value;
  }

  // extension
  bool hasAddress();
  bool getAddress(string_ref *Addr);
  bool hasPort();
  bool getPort(unsigned short *PortNum);

private:
  INIConfig(const string_ref &) = delete;
  INIConfig &operator=(const string_ref &) = delete;

  const std::string *find(const string_ref SectionName,
                          const string_ref &Key) const {
    auto SectionPos = Storage.find(SectionName);
    if (SectionPos == Storage.end())
      return nullptr;
    const auto &SectionStorage = SectionPos->second;
    auto Pos = SectionStorage.find(Key);
    if (Pos == SectionStorage.end())
      return nullptr;
    return &Pos->second;
  }
  bool parseImpl(string_ref Ref);

  StorageType Storage;
};
} // namespace windycode
#endif // WINDYCODE_INICONFIG_H
