// Copyright 2015 The Weave Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/commands/prop_types.h"

#include <algorithm>
#include <limits>
#include <set>

#include <base/json/json_writer.h>
#include <base/logging.h>
#include <base/values.h>

#include "src/commands/object_schema.h"
#include "src/commands/prop_values.h"
#include "src/commands/schema_constants.h"

namespace weave {

// PropType -------------------------------------------------------------------
PropType::PropType() {}

PropType::~PropType() {}

std::string PropType::GetTypeAsString() const {
  return GetTypeStringFromType(GetType());
}

bool PropType::HasOverriddenAttributes() const {
  if (default_.value && !default_.is_inherited)
    return true;

  for (const auto& pair : constraints_) {
    if (pair.second->HasOverriddenAttributes())
      return true;
  }
  return false;
}

bool PropType::IsRequired() const {
  return required_.value;
}

void PropType::MakeRequired(bool required) {
  required_.value = required;
  required_.is_inherited = false;
}

std::unique_ptr<base::Value> PropType::ToJson(bool full_schema,
                                              bool in_command_def) const {
  // Determine if we need to output "isRequired" attribute.
  const bool include_required = in_command_def && !required_.is_inherited;

  // If we must include "isRequired" attribute, then treat this as "full schema"
  // request because there could be cases where we have just this attribute and
  // won't be able to infer the type from the constraints only.
  if (include_required)
    full_schema = true;

  if (!full_schema && !HasOverriddenAttributes()) {
    if (based_on_schema_)
      return std::unique_ptr<base::Value>(new base::DictionaryValue);
    return TypedValueToJson(GetTypeAsString());
  }

  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
  if (full_schema) {
    // If we are asked for full_schema definition, then we need to output every
    // parameter property, including the "type", and any constraints.
    // So, we write the "type" only if asked for full schema.
    // Otherwise we will be able to infer the parameter type based on
    // the constraints and their types.
    // That is, the following JSONs could possibly define a parameter:
    // {'type':'integer'} -> explicit "integer" with no constraints
    // {'minimum':10} -> no type specified, but since we have "minimum"
    //                   and 10 is integer, than this is an integer
    //                   parameter with min constraint.
    // {'enum':[1,2,3]} -> integer with OneOf constraint.
    // And so is this: [1,2,3] -> an array of ints assume it's an "int" enum.
    dict->SetString(commands::attributes::kType, GetTypeAsString());
  }

  if (!full_schema && constraints_.size() == 1) {
    // If we are not asked for full schema, and we have only one constraint
    // which is OneOf, we short-circuit the whole thing and return just
    // the array [1,2,3] instead of an object with "enum" property like:
    // {'enum':[1,2,3]}
    auto p = constraints_.find(ConstraintType::OneOf);
    if (p != constraints_.end()) {
      return p->second->ToJson();
    }
  }

  for (const auto& pair : constraints_)
    pair.second->AddToJsonDict(dict.get(), !full_schema);

  if (default_.value && (full_schema || !default_.is_inherited)) {
    auto def_val = default_.value->ToJson();
    CHECK(def_val);
    dict->Set(commands::attributes::kDefault, def_val.release());
  }

  if (include_required)
    dict->SetBoolean(commands::attributes::kIsRequired, required_.value);
  return std::unique_ptr<base::Value>(dict.release());
}

std::unique_ptr<PropType> PropType::Clone() const {
  auto cloned = PropType::Create(GetType());
  cloned->based_on_schema_ = based_on_schema_;
  for (const auto& pair : constraints_) {
    cloned->constraints_.emplace(pair.first, pair.second->Clone());
  }
  cloned->default_.is_inherited = default_.is_inherited;
  if (default_.value)
    cloned->default_.value = default_.value->Clone();
  cloned->required_ = required_;
  return cloned;
}

bool PropType::FromJson(const base::DictionaryValue* value,
                        const PropType* base_schema,
                        ErrorPtr* error) {
  if (base_schema && base_schema->GetType() != GetType()) {
    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                       errors::commands::kPropTypeChanged,
                       "Redefining a property of type %s as %s",
                       base_schema->GetTypeAsString().c_str(),
                       GetTypeAsString().c_str());
    return false;
  }
  based_on_schema_ = (base_schema != nullptr);
  constraints_.clear();
  // Add the well-known object properties first (like "type", "displayName",
  // "default") to the list of "processed" keys so we do not complain about them
  // when we check for unknown/unexpected keys below.
  std::set<std::string> processed_keys{
      commands::attributes::kType, commands::attributes::kDisplayName,
      commands::attributes::kDefault, commands::attributes::kIsRequired,
  };
  if (!ObjectSchemaFromJson(value, base_schema, &processed_keys, error))
    return false;
  if (base_schema) {
    for (const auto& pair : base_schema->GetConstraints()) {
      constraints_.emplace(pair.first, pair.second->CloneAsInherited());
    }
  }
  if (!ConstraintsFromJson(value, &processed_keys, error))
    return false;

  // Now make sure there are no unexpected/unknown keys in the property schema
  // definition object.
  base::DictionaryValue::Iterator iter(*value);
  while (!iter.IsAtEnd()) {
    std::string key = iter.key();
    if (processed_keys.find(key) == processed_keys.end()) {
      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                         errors::commands::kUnknownProperty,
                         "Unexpected property '%s'", key.c_str());
      return false;
    }
    iter.Advance();
  }

  // Read the "isRequired" attribute, if specified.
  bool required = false;
  if (value->GetBoolean(commands::attributes::kIsRequired, &required)) {
    required_.value = required;
    required_.is_inherited = false;
  } else if (base_schema) {
    // If we have the base schema, inherit the type's required value from it.
    if (base_schema->required_.value)
      required_.value = base_schema->required_.value;
    required_.is_inherited = true;
  }

  // Read the default value, if specified.
  // We need to do this last since the current type definition must be complete,
  // so we can parse and validate the value of the default.
  const base::Value* defval = nullptr;  // Owned by value
  if (value->GetWithoutPathExpansion(commands::attributes::kDefault, &defval)) {
    std::unique_ptr<PropValue> prop_value = CreatePropValue(*defval, error);
    if (!prop_value) {
      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                         errors::commands::kInvalidPropValue,
                         "Invalid value for property '%s'",
                         commands::attributes::kDefault);
      return false;
    }
    default_.value = std::move(prop_value);
    default_.is_inherited = false;
  } else if (base_schema) {
    // If we have the base schema, inherit the type's default value from it.
    // It doesn't matter if the base schema actually has a default value
    // specified or not. If it doesn't, then the current type definition will
    // have no default value set either (|default_.value| is a unique_ptr to
    // PropValue, which can be set to nullptr).
    if (base_schema->default_.value)
      default_.value = base_schema->default_.value->Clone();
    default_.is_inherited = true;
  }
  return true;
}

void PropType::AddConstraint(std::unique_ptr<Constraint> constraint) {
  constraints_[constraint->GetType()] = std::move(constraint);
}

void PropType::RemoveConstraint(ConstraintType constraint_type) {
  constraints_.erase(constraint_type);
}

void PropType::RemoveAllConstraints() {
  constraints_.clear();
}

const Constraint* PropType::GetConstraint(
    ConstraintType constraint_type) const {
  auto p = constraints_.find(constraint_type);
  return p != constraints_.end() ? p->second.get() : nullptr;
}

Constraint* PropType::GetConstraint(ConstraintType constraint_type) {
  auto p = constraints_.find(constraint_type);
  return p != constraints_.end() ? p->second.get() : nullptr;
}

bool PropType::ValidateConstraints(const PropValue& value,
                                   ErrorPtr* error) const {
  for (const auto& pair : constraints_) {
    if (!pair.second->Validate(value, error))
      return false;
  }
  return true;
}

const PropType::TypeMap& PropType::GetTypeMap() {
  static TypeMap map = {
      {ValueType::Int, "integer"},   {ValueType::Double, "number"},
      {ValueType::String, "string"}, {ValueType::Boolean, "boolean"},
      {ValueType::Object, "object"}, {ValueType::Array, "array"},
  };
  return map;
}

std::string PropType::GetTypeStringFromType(ValueType type) {
  for (const auto& pair : GetTypeMap()) {
    if (pair.first == type)
      return pair.second;
  }
  LOG(FATAL) << "Type map is missing a type";
  return std::string();
}

bool PropType::GetTypeFromTypeString(const std::string& name, ValueType* type) {
  for (const auto& pair : GetTypeMap()) {
    if (pair.second == name) {
      *type = pair.first;
      return true;
    }
  }
  return false;
}

std::unique_ptr<PropType> PropType::Create(ValueType type) {
  PropType* prop = nullptr;
  switch (type) {
    case ValueType::Int:
      prop = new IntPropType;
      break;
    case ValueType::Double:
      prop = new DoublePropType;
      break;
    case ValueType::String:
      prop = new StringPropType;
      break;
    case ValueType::Boolean:
      prop = new BooleanPropType;
      break;
    case ValueType::Object:
      prop = new ObjectPropType;
      break;
    case ValueType::Array:
      prop = new ArrayPropType;
      break;
  }
  return std::unique_ptr<PropType>(prop);
}

template <typename T>
static std::unique_ptr<Constraint> LoadOneOfConstraint(
    const base::DictionaryValue* value,
    const PropType* prop_type,
    ErrorPtr* error) {
  std::unique_ptr<Constraint> constraint;
  const base::Value* list = nullptr;  // Owned by |value|
  CHECK(value->Get(commands::attributes::kOneOf_Enum, &list))
      << "'enum' property missing in JSON dictionary";
  ValueVector choice_list;
  ArrayPropType array_type;
  array_type.SetItemType(prop_type->Clone());
  if (!TypedValueFromJson(list, &array_type, &choice_list, error))
    return constraint;
  InheritableAttribute<ValueVector> val(std::move(choice_list), false);
  constraint.reset(new ConstraintOneOf{std::move(val)});
  return constraint;
}

template <class ConstraintClass, typename T>
static std::unique_ptr<Constraint> LoadMinMaxConstraint(
    const char* dict_key,
    const base::DictionaryValue* value,
    ErrorPtr* error) {
  std::unique_ptr<Constraint> constraint;
  InheritableAttribute<T> limit;

  const base::Value* src_val = nullptr;
  CHECK(value->Get(dict_key, &src_val)) << "Unable to get min/max constraints";
  if (!TypedValueFromJson(src_val, nullptr, &limit.value, error))
    return constraint;
  limit.is_inherited = false;

  constraint.reset(new ConstraintClass{limit});
  return constraint;
}

// PropTypeBase ----------------------------------------------------------------

template <class Derived, class Value, typename T>
bool PropTypeBase<Derived, Value, T>::ConstraintsFromJson(
    const base::DictionaryValue* value,
    std::set<std::string>* processed_keys,
    ErrorPtr* error) {
  if (!PropType::ConstraintsFromJson(value, processed_keys, error))
    return false;

  if (value->HasKey(commands::attributes::kOneOf_Enum)) {
    auto type = Clone();
    type->RemoveAllConstraints();
    auto constraint = LoadOneOfConstraint<T>(value, type.get(), error);
    if (!constraint)
      return false;
    this->AddConstraint(std::move(constraint));
    this->RemoveConstraint(ConstraintType::Min);
    this->RemoveConstraint(ConstraintType::Max);
    processed_keys->insert(commands::attributes::kOneOf_Enum);
  }

  return true;
}

// NumericPropTypeBase ---------------------------------------------------------

template <class Derived, class Value, typename T>
bool NumericPropTypeBase<Derived, Value, T>::ConstraintsFromJson(
    const base::DictionaryValue* value,
    std::set<std::string>* processed_keys,
    ErrorPtr* error) {
  if (!Base::ConstraintsFromJson(value, processed_keys, error))
    return false;

  if (processed_keys->find(commands::attributes::kOneOf_Enum) ==
      processed_keys->end()) {
    // Process min/max constraints only if "enum" constraint wasn't already
    // specified.
    if (value->HasKey(commands::attributes::kNumeric_Min)) {
      auto constraint = LoadMinMaxConstraint<ConstraintMin<T>, T>(
          commands::attributes::kNumeric_Min, value, error);
      if (!constraint)
        return false;
      this->AddConstraint(std::move(constraint));
      this->RemoveConstraint(ConstraintType::OneOf);
      processed_keys->insert(commands::attributes::kNumeric_Min);
    }
    if (value->HasKey(commands::attributes::kNumeric_Max)) {
      auto constraint = LoadMinMaxConstraint<ConstraintMax<T>, T>(
          commands::attributes::kNumeric_Max, value, error);
      if (!constraint)
        return false;
      this->AddConstraint(std::move(constraint));
      this->RemoveConstraint(ConstraintType::OneOf);
      processed_keys->insert(commands::attributes::kNumeric_Max);
    }
  }

  return true;
}

// StringPropType -------------------------------------------------------------

bool StringPropType::ConstraintsFromJson(const base::DictionaryValue* value,
                                         std::set<std::string>* processed_keys,
                                         ErrorPtr* error) {
  if (!Base::ConstraintsFromJson(value, processed_keys, error))
    return false;

  if (processed_keys->find(commands::attributes::kOneOf_Enum) ==
      processed_keys->end()) {
    // Process min/max constraints only if "enum" constraint wasn't already
    // specified.
    if (value->HasKey(commands::attributes::kString_MinLength)) {
      auto constraint = LoadMinMaxConstraint<ConstraintStringLengthMin, int>(
          commands::attributes::kString_MinLength, value, error);
      if (!constraint)
        return false;
      AddConstraint(std::move(constraint));
      RemoveConstraint(ConstraintType::OneOf);
      processed_keys->insert(commands::attributes::kString_MinLength);
    }
    if (value->HasKey(commands::attributes::kString_MaxLength)) {
      auto constraint = LoadMinMaxConstraint<ConstraintStringLengthMax, int>(
          commands::attributes::kString_MaxLength, value, error);
      if (!constraint)
        return false;
      AddConstraint(std::move(constraint));
      RemoveConstraint(ConstraintType::OneOf);
      processed_keys->insert(commands::attributes::kString_MaxLength);
    }
  }
  return true;
}

void StringPropType::AddLengthConstraint(int min_len, int max_len) {
  InheritableAttribute<int> min_attr(min_len, false);
  InheritableAttribute<int> max_attr(max_len, false);
  AddConstraint(std::unique_ptr<ConstraintStringLengthMin>{
      new ConstraintStringLengthMin{min_attr}});
  AddConstraint(std::unique_ptr<ConstraintStringLengthMax>{
      new ConstraintStringLengthMax{max_attr}});
}

int StringPropType::GetMinLength() const {
  auto slc = static_cast<const ConstraintStringLength*>(
      GetConstraint(ConstraintType::StringLengthMin));
  return slc ? slc->limit_.value : 0;
}

int StringPropType::GetMaxLength() const {
  auto slc = static_cast<const ConstraintStringLength*>(
      GetConstraint(ConstraintType::StringLengthMax));
  return slc ? slc->limit_.value : std::numeric_limits<int>::max();
}

// ObjectPropType -------------------------------------------------------------

ObjectPropType::ObjectPropType()
    : object_schema_{ObjectSchema::Create(), false} {}

bool ObjectPropType::HasOverriddenAttributes() const {
  return PropType::HasOverriddenAttributes() || !object_schema_.is_inherited;
}

std::unique_ptr<PropType> ObjectPropType::Clone() const {
  auto cloned = Base::Clone();

  cloned->GetObject()->object_schema_.is_inherited =
      object_schema_.is_inherited;
  cloned->GetObject()->object_schema_.value = object_schema_.value->Clone();
  return cloned;
}

std::unique_ptr<base::Value> ObjectPropType::ToJson(bool full_schema,
                                                    bool in_command_def) const {
  std::unique_ptr<base::Value> value =
      PropType::ToJson(full_schema, in_command_def);
  CHECK(value);
  base::DictionaryValue* dict = nullptr;
  CHECK(value->GetAsDictionary(&dict)) << "Expecting a JSON object";
  if (!object_schema_.is_inherited || full_schema) {
    auto object_schema = object_schema_.value->ToJson(full_schema, false);
    CHECK(object_schema);

    dict->SetWithoutPathExpansion(commands::attributes::kObject_Properties,
                                  object_schema.release());
    dict->SetBooleanWithoutPathExpansion(
        commands::attributes::kObject_AdditionalProperties,
        object_schema_.value->GetExtraPropertiesAllowed());
    std::unique_ptr<base::ListValue> required{new base::ListValue};
    for (const auto& pair : object_schema_.value->GetProps()) {
      if (pair.second->IsRequired())
        required->AppendString(pair.first);
    }
    if (required->GetSize() > 0) {
      dict->Set(commands::attributes::kObject_Required, required.release());
    }
  }
  return value;
}

bool ObjectPropType::ObjectSchemaFromJson(const base::DictionaryValue* value,
                                          const PropType* base_schema,
                                          std::set<std::string>* processed_keys,
                                          ErrorPtr* error) {
  if (!Base::ObjectSchemaFromJson(value, base_schema, processed_keys, error))
    return false;

  using commands::attributes::kObject_Properties;
  using commands::attributes::kObject_AdditionalProperties;

  const ObjectSchema* base_object_schema = nullptr;
  if (base_schema)
    base_object_schema = base_schema->GetObject()->GetObjectSchemaPtr();

  const base::DictionaryValue* props = nullptr;
  std::unique_ptr<ObjectSchema> object_schema;
  bool inherited = false;
  if (value->GetDictionaryWithoutPathExpansion(kObject_Properties, &props)) {
    processed_keys->insert(kObject_Properties);
    object_schema.reset(new ObjectSchema);
    if (!object_schema->FromJson(props, base_object_schema, error)) {
      Error::AddTo(error, FROM_HERE, errors::commands::kDomain,
                   errors::commands::kInvalidObjectSchema,
                   "Error parsing object property schema");
      return false;
    }
  } else if (base_object_schema) {
    object_schema = base_object_schema->Clone();
    inherited = true;
  } else {
    Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                       errors::commands::kInvalidObjectSchema,
                       "Object type definition must include the "
                       "object schema ('%s' field not found)",
                       kObject_Properties);
    return false;
  }
  bool extra_properties_allowed = false;
  if (value->GetBooleanWithoutPathExpansion(kObject_AdditionalProperties,
                                            &extra_properties_allowed)) {
    processed_keys->insert(kObject_AdditionalProperties);
    object_schema->SetExtraPropertiesAllowed(extra_properties_allowed);
    inherited = false;
  }
  const base::Value* required = nullptr;
  if (value->Get(commands::attributes::kObject_Required, &required)) {
    processed_keys->insert(commands::attributes::kObject_Required);
    const base::ListValue* required_list = nullptr;
    if (!required->GetAsList(&required_list)) {
      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                         errors::commands::kInvalidObjectSchema,
                         "Property '%s' must be an array",
                         commands::attributes::kObject_Required);
      return false;
    }
    for (const base::Value* value : *required_list) {
      std::string name;
      if (!value->GetAsString(&name)) {
        std::string json_value;
        CHECK(base::JSONWriter::Write(*value, &json_value));
        Error::AddToPrintf(
            error, FROM_HERE, errors::commands::kDomain,
            errors::commands::kInvalidObjectSchema,
            "Property '%s' contains invalid element (%s). String expected",
            commands::attributes::kObject_Required, json_value.c_str());
        return false;
      }
      if (!object_schema->MarkPropRequired(name, error))
        return false;
      inherited = false;
    }
  }
  object_schema_.value = std::move(object_schema);
  object_schema_.is_inherited = inherited;

  return true;
}

void ObjectPropType::SetObjectSchema(
    std::unique_ptr<const ObjectSchema> schema) {
  object_schema_.value = std::move(schema);
  object_schema_.is_inherited = false;
}

// ArrayPropType -------------------------------------------------------------

ArrayPropType::ArrayPropType() {}

bool ArrayPropType::HasOverriddenAttributes() const {
  return PropType::HasOverriddenAttributes() || !item_type_.is_inherited;
}

std::unique_ptr<PropType> ArrayPropType::Clone() const {
  auto cloned = Base::Clone();

  cloned->GetArray()->item_type_.is_inherited = item_type_.is_inherited;
  cloned->GetArray()->item_type_.value = item_type_.value->Clone();
  return cloned;
}

std::unique_ptr<base::Value> ArrayPropType::ToJson(bool full_schema,
                                                   bool in_command_def) const {
  std::unique_ptr<base::Value> value =
      PropType::ToJson(full_schema, in_command_def);
  CHECK(value);
  if (!item_type_.is_inherited || full_schema) {
    base::DictionaryValue* dict = nullptr;
    CHECK(value->GetAsDictionary(&dict)) << "Expecting a JSON object";
    auto type = item_type_.value->ToJson(full_schema, false);
    CHECK(type);
    dict->SetWithoutPathExpansion(commands::attributes::kItems, type.release());
  }
  return value;
}

bool ArrayPropType::ObjectSchemaFromJson(const base::DictionaryValue* value,
                                         const PropType* base_schema,
                                         std::set<std::string>* processed_keys,
                                         ErrorPtr* error) {
  if (!Base::ObjectSchemaFromJson(value, base_schema, processed_keys, error))
    return false;

  using commands::attributes::kItems;

  const PropType* base_type = nullptr;
  if (base_schema)
    base_type = base_schema->GetArray()->GetItemTypePtr();

  const base::Value* type_value = nullptr;
  if (value->GetWithoutPathExpansion(kItems, &type_value)) {
    processed_keys->insert(kItems);
    auto item_type = ObjectSchema::PropFromJson(*type_value, base_type, error);
    if (!item_type)
      return false;
    if (item_type->GetType() == ValueType::Array) {
      Error::AddTo(error, FROM_HERE, errors::commands::kDomain,
                   errors::commands::kInvalidObjectSchema,
                   "Arrays of arrays are not supported");
      return false;
    }
    SetItemType(std::move(item_type));
  } else if (!item_type_.value) {
    if (base_type) {
      item_type_.value = base_type->Clone();
      item_type_.is_inherited = true;
    } else {
      Error::AddToPrintf(error, FROM_HERE, errors::commands::kDomain,
                         errors::commands::kInvalidObjectSchema,
                         "Array type definition must include the "
                         "array item type ('%s' field not found)",
                         kItems);
      return false;
    }
  }
  return true;
}

void ArrayPropType::SetItemType(std::unique_ptr<const PropType> item_type) {
  item_type_.value = std::move(item_type);
  item_type_.is_inherited = false;
}

}  // namespace weave
