#include "json_array.h"

#include <fstream>
#include <sstream>
#include "rapidjson/stringbuffer.h"
#include "rapidjson/allocators.h"
#include "rapidjson/writer.h"

#include "utils/Log.h"

#define  JSONARRAY_CHECK_RANGE \
   if (rapidjson::SizeType(index) >= doc_.Size()) { \
     LOGE("%s index out of range", __FUNCTION__); \
     RAPIDJSON_ASSERT(0); \
   } \

namespace base {

JSONArray::JSONArray() {
  doc_.SetArray();
}

JSONArray::~JSONArray() {
}

JSONArray::JSONArray(const rapidjson::Value::Array& array) {
  doc_.SetArray();
  for (rapidjson::SizeType i = 0; i < array.Size(); ++i) {
    doc_.PushBack(rapidjson::Value(array[i], doc_.GetAllocator()).Move(),
        doc_.GetAllocator());
  }
}

JSONArray::JSONArray(const rapidjson::Value::ConstArray& array) {
  doc_.SetArray();
  for (rapidjson::SizeType i = 0; i < array.Size(); ++i) {
    doc_.PushBack(rapidjson::Value(array[i], doc_.GetAllocator()).Move(),
        doc_.GetAllocator());
  }
}

JSONArray::JSONArray(JSONArray&& array) {
  doc_.SetArray();
  doc_.Swap(array.doc_);
}

int JSONArray::GetInt(int index) {
  JSONARRAY_CHECK_RANGE;
  return (doc_.Begin()[index]).GetInt();
}

uint32_t JSONArray::GetUint(int index) {
  JSONARRAY_CHECK_RANGE;
  return (doc_.Begin()[index]).GetUint();
}

std::string JSONArray::GetString(int index) {
  JSONARRAY_CHECK_RANGE;
  return (doc_.Begin()[index]).GetString();
}

int64_t JSONArray::GetInt64(int index) {
  JSONARRAY_CHECK_RANGE;
  return (doc_.Begin()[index]).GetInt64();
}

uint64_t JSONArray::GetUint64(int index) {
  JSONARRAY_CHECK_RANGE;
  return (doc_.Begin()[index]).GetUint64();
}

JSONArray JSONArray::GetArray(int index) {
  JSONARRAY_CHECK_RANGE;
  if (!doc_[index].IsArray()) {
    JSONArray arr;
    return arr;
  }
  return doc_[index].GetArray();
}

JSONObject JSONArray::GetObject(int index) const {
  JSONARRAY_CHECK_RANGE;
  if (!doc_.Begin()[index].IsObject()) {
    JSONObject obj;
    return obj;
  }
  return (doc_.Begin()[index]).GetObject();
}

JSONArray& JSONArray::Add(int32_t value) {
  doc_.PushBack(value, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(uint32_t value) {
  doc_.PushBack(value, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(int64_t value) {
  doc_.PushBack(value, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(uint64_t value) {
  doc_.PushBack(value, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(bool value) {
  doc_.PushBack(value, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(const JSONArray& array) {
  rapidjson::Value v;
  v.CopyFrom(array.doc_, doc_.GetAllocator());
  doc_.PushBack(v, doc_.GetAllocator());
  return *this;
}

JSONArray& JSONArray::Add(const JSONObject& object) {
  rapidjson::Value v;
  v.CopyFrom(object.doc_, doc_.GetAllocator());
  doc_.PushBack(v, doc_.GetAllocator());
  return *this;
}

int JSONArray::Size() const {
  return doc_.Size();
}

bool JSONArray::ParseArray(const std::string& json_str) {
  doc_.Parse(json_str.c_str());
  return !doc_.HasParseError() && doc_.IsArray();
}

bool JSONArray::ParseArrayFromFile(const std::string& file_path) {
  std::ifstream ifs(file_path.c_str(), std::ios::in | std::ios::binary);
  if (!ifs.is_open()) {
    return false;
  }
  std::stringstream ss;
  ss << ifs.rdbuf();
  ifs.close();
  return ParseArray(ss.str());
}

std::string JSONArray::ToString() const {
  return rapidjson_to_string(doc_);
}

std::string JSONArray::ToPrettyString() const {
  return rapidjson_to_pretty_string(doc_);
}

} /* namespace rapidjson */

