// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
#pragma once

#include <string>

#include <rapidjson/document.h>

#include "kudu/gutil/ref_counted.h"

namespace kudu {

// A wrapper around rapidjson Value objects, to simplify usage.
// Intended solely for building json objects, not writing/parsing.
//
// Simplifies code like this:
//
//   rapidjson::Document d;
//   rapidjson::Value v;
//   v.SetObject();
//   rapidjson::Value list;
//   list.SetArray();
//   v.AddMember("list", list, d.GetAllocator());
//   v["list"].PushBack(rapidjson::Value().SetString("element"), d.GetAllocator());
//
// To this:
//
//   EasyJson ej;
//   ej["list"][0] = "element";
//
// Client code should build objects as demonstrated above,
// then call EasyJson::value() to obtain a reference to the
// built rapidjson Value.
class EasyJson {
 public:
  // Used for initializing EasyJson's with complex types.
  // For example:
  //
  //  EasyJson array;
  //  EasyJson nested = array.PushBack(EasyJson::kObject);
  //  nested["attr"] = "val";
  //  // array = [ { "attr": "val" } ]
  enum ComplexTypeInitializer {
    kObject,
    kArray
  };

  EasyJson();
  // Initializes the EasyJson object with the given type.
  explicit EasyJson(ComplexTypeInitializer type);
  ~EasyJson() = default;

  // Returns the child EasyJson associated with key.
  //
  // Note: this method can mutate the EasyJson object
  // as follows:
  //
  // If this EasyJson's underlying Value is not an object
  // (i.e. !this->value().IsObject()), then its Value is
  // coerced to an object, overwriting the old Value.
  // If the given key does not exist, a Null-valued
  // EasyJson associated with key is created.
  EasyJson Get(const std::string& key);

  // Returns the child EasyJson at index.
  //
  // Note: this method can mutate the EasyJson object
  // as follows:
  //
  // If this EasyJson's underlying Value is not an array
  // (i.e. !this->value().IsArray()), then its Value is
  // coerced to an array, overwriting the old Value.
  // If index >= this->value().Size(), then the underlying
  // array's size is increased to index + 1 (new indices
  // are filled with Null values).
  EasyJson Get(int index);

  // Same as Get(key).
  EasyJson operator[](const std::string& key);
  // Same as Get(index).
  EasyJson operator[](int index);

  // Sets the underlying Value equal to val.
  // Returns a reference to the object itself.
  //
  // 'val' can be a bool, int32_t, int64_t, double,
  // char*, string, or ComplexTypeInitializer.
  EasyJson& operator=(const std::string& val);
  template<typename T>
  EasyJson& operator=(T val);

  // Sets the underlying Value to an object.
  // Returns a reference to the object itself.
  //
  // i.e. after calling SetObject(),
  // value().IsObject() == true
  EasyJson& SetObject();
  // Sets the underlying Value to an array.
  // Returns a reference to the object itself.
  //
  // i.e. after calling SetArray(),
  // value().IsArray() == true
  EasyJson& SetArray();

  // Associates val with key.
  // Returns the child object.
  //
  // If this EasyJson's underlying Value is not an object
  // (i.e. !this->value().IsObject()), then its Value is
  // coerced to an object, overwriting the old Value.
  // If the given key does not exist, a new child entry
  // is created with the given value.
  EasyJson Set(const std::string& key, const std::string& val);
  template<typename T>
  EasyJson Set(const std::string& key, T val);

  // Stores val at index.
  // Returns the child object.
  //
  // If this EasyJson's underlying Value is not an array
  // (i.e. !this->value().IsArray()), then its Value is
  // coerced to an array, overwriting the old Value.
  // If index >= this->value().Size(), then the underlying
  // array's size is increased to index + 1 (new indices
  // are filled with Null values).
  EasyJson Set(int index, const std::string& val);
  template<typename T>
  EasyJson Set(int index, T val);

  // Appends val to the underlying array.
  // Returns a reference to the new child object.
  //
  // If this EasyJson's underlying Value is not an array
  // (i.e. !this->value().IsArray()), then its Value is
  // coerced to an array, overwriting the old Value.
  EasyJson PushBack(const std::string& val);
  template<typename T>
  EasyJson PushBack(T val);

  // Returns a reference to the underlying Value.
  rapidjson::Value& value() const { return *value_; }

  // Returns a string representation of the underlying json.
  std::string ToString() const;

 private:
  // One instance of EasyJsonAllocator is shared among a root
  // EasyJson object and all of its descendants. The allocator
  // owns the underlying rapidjson Value, and a rapidjson
  // allocator (via a rapidjson::Document).
  class EasyJsonAllocator : public RefCounted<EasyJsonAllocator> {
   public:
    rapidjson::Value& value() { return value_; }
    rapidjson::Document::AllocatorType& allocator() { return value_.GetAllocator(); }
   private:
    friend class RefCounted<EasyJsonAllocator>;
    ~EasyJsonAllocator() = default;

    // The underlying rapidjson::Value object (Document is
    // a subclass of Value that has its own allocator).
    rapidjson::Document value_;
  };

  // Used to instantiate descendant objects.
  EasyJson(rapidjson::Value* value, scoped_refptr<EasyJsonAllocator> alloc);

  // One allocator is shared among an EasyJson object and
  // all of its descendants.
  scoped_refptr<EasyJsonAllocator> alloc_;

  // A pointer to the underlying Value in the object
  // tree owned by alloc_.
  rapidjson::Value* value_;
};

} // namespace kudu
