#ifndef MARISA_ALPHA_STRING_H_
#define MARISA_ALPHA_STRING_H_

#include "base.h"

namespace marisa_alpha {

class String {
 public:
  String() : ptr_(NULL), length_(0) {}
  explicit String(const char *str) : ptr_(str), length_(0) {
    while (str[length_] != '\0') {
      ++length_;
    }
  }
  String(const char *ptr, std::size_t length)
      : ptr_(ptr), length_(length) {}
  String(const String &str) : ptr_(str.ptr_), length_(str.length_) {}

  String substr(std::size_t pos, std::size_t length) const {
    MARISA_ALPHA_DEBUG_IF(pos + length > length_, MARISA_ALPHA_PARAM_ERROR);
    return String(ptr_ + pos, length);
  }

  String &operator=(const String &str) {
    ptr_ = str.ptr_;
    length_ = str.length_;
    return *this;
  }

  UInt8 operator[](std::size_t i) const {
    MARISA_ALPHA_DEBUG_IF(i >= length_, MARISA_ALPHA_PARAM_ERROR);
    return ptr_[i];
  }

  const char *ptr() const {
    return ptr_;
  }
  std::size_t length() const {
    return length_;
  }

 private:
  const char *ptr_;
  std::size_t length_;
};

inline bool operator==(const String &lhs, const String &rhs) {
  if (lhs.length() != rhs.length()) {
    return false;
  }
  for (std::size_t i = 0; i < lhs.length(); ++i) {
    if (lhs[i] != rhs[i]) {
      return false;
    }
  }
  return true;
}

inline bool operator!=(const String &lhs, const String &rhs) {
  return !(lhs == rhs);
}

inline bool operator<(const String &lhs, const String &rhs) {
  for (std::size_t i = 0; i < lhs.length(); ++i) {
    if (i == rhs.length()) {
      return false;
    }
    if (lhs[i] != rhs[i]) {
      return lhs[i] < rhs[i];
    }
  }
  return lhs.length() < rhs.length();
}

inline bool operator>(const String &lhs, const String &rhs) {
  return rhs < lhs;
}

class RString {
 public:
  RString()
      : ptr_(static_cast<const char *>(NULL) - 1), length_(0) {}
  explicit RString(const String &str)
      : ptr_(str.ptr() + str.length() - 1), length_(str.length()) {}
  RString(const RString &str)
      : ptr_(str.ptr_), length_(str.length_) {}

  RString substr(std::size_t pos, std::size_t length) const {
    MARISA_ALPHA_DEBUG_IF(pos + length > length_, MARISA_ALPHA_PARAM_ERROR);
    RString str(*this);
    str.ptr_ -= pos;
    str.length_ = length;
    return str;
  }

  RString &operator=(const RString &str) {
    ptr_ = str.ptr_;
    length_ = str.length_;
    return *this;
  }

  UInt8 operator[](std::size_t i) const {
    MARISA_ALPHA_DEBUG_IF(i >= length_, MARISA_ALPHA_PARAM_ERROR);
    return *(ptr_ - i);
  }

  const char *ptr() const {
    return ptr_ - length_ + 1;
  }
  std::size_t length() const {
    return length_;
  }

 private:
  const char *ptr_;
  std::size_t length_;
};

inline bool operator==(const RString &lhs, const RString &rhs) {
  if (lhs.length() != rhs.length()) {
    return false;
  }
  for (std::size_t i = 0; i < lhs.length(); ++i) {
    if (lhs[i] != rhs[i]) {
      return false;
    }
  }
  return true;
}

inline bool operator!=(const RString &lhs, const RString &rhs) {
  return !(lhs == rhs);
}

inline bool operator<(const RString &lhs, const RString &rhs) {
  for (std::size_t i = 0; i < lhs.length(); ++i) {
    if (i == rhs.length()) {
      return false;
    }
    if (lhs[i] != rhs[i]) {
      return lhs[i] < rhs[i];
    }
  }
  return lhs.length() < rhs.length();
}

inline bool operator>(const RString &lhs, const RString &rhs) {
  return rhs < lhs;
}

}  // namespace marisa_alpha

#endif  // MARISA_ALPHA_STRING_H_