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

#ifndef SRC_DEVICES_MISC_DRIVERS_COMPAT_COMPOSITE_NODE_SPEC_UTIL_H_
#define SRC_DEVICES_MISC_DRIVERS_COMPAT_COMPOSITE_NODE_SPEC_UTIL_H_

#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <lib/ddk/device.h>

zx::result<fuchsia_driver_framework::wire::BindRule> ConvertBindRuleToFidl(
    fidl::AnyArena& allocator, bind_rule_t bind_rule) {
  fuchsia_driver_framework::wire::NodePropertyKey property_key;

  switch (bind_rule.key.key_type) {
    case DEVICE_BIND_PROPERTY_KEY_INT: {
      property_key =
          fuchsia_driver_framework::wire::NodePropertyKey::WithIntValue(bind_rule.key.data.int_key);
      break;
    }
    case DEVICE_BIND_PROPERTY_KEY_STRING: {
      property_key = fuchsia_driver_framework::wire::NodePropertyKey::WithStringValue(
          allocator, allocator, bind_rule.key.data.str_key);
      break;
    }
    default: {
      return zx::error(ZX_ERR_INVALID_ARGS);
    }
  }

  auto bind_rule_values = fidl::VectorView<fuchsia_driver_framework::wire::NodePropertyValue>(
      allocator, bind_rule.values_count);
  for (size_t i = 0; i < bind_rule.values_count; i++) {
    auto bind_rule_val = bind_rule.values[i];
    switch (bind_rule_val.data_type) {
      case ZX_DEVICE_PROPERTY_VALUE_INT: {
        bind_rule_values[i] = fuchsia_driver_framework::wire::NodePropertyValue::WithIntValue(
            bind_rule_val.data.int_value);
        break;
      }
      case ZX_DEVICE_PROPERTY_VALUE_STRING: {
        auto str_val =
            fidl::ObjectView<fidl::StringView>(allocator, allocator, bind_rule_val.data.str_value);
        bind_rule_values[i] =
            fuchsia_driver_framework::wire::NodePropertyValue::WithStringValue(str_val);
        break;
      }
      case ZX_DEVICE_PROPERTY_VALUE_BOOL: {
        bind_rule_values[i] = fuchsia_driver_framework::wire::NodePropertyValue::WithBoolValue(
            bind_rule_val.data.bool_value);
        break;
      }
      case ZX_DEVICE_PROPERTY_VALUE_ENUM: {
        auto enum_val =
            fidl::ObjectView<fidl::StringView>(allocator, allocator, bind_rule_val.data.enum_value);
        bind_rule_values[i] =
            fuchsia_driver_framework::wire::NodePropertyValue::WithEnumValue(enum_val);
        break;
      }
      default: {
        return zx::error(ZX_ERR_INVALID_ARGS);
      }
    }
  }

  fuchsia_driver_framework::wire::Condition condition;
  switch (bind_rule.condition) {
    case DEVICE_BIND_RULE_CONDITION_ACCEPT: {
      condition = fuchsia_driver_framework::wire::Condition::kAccept;
      break;
    }
    case DEVICE_BIND_RULE_CONDITION_REJECT: {
      condition = fuchsia_driver_framework::wire::Condition::kReject;
      break;
    }
    default: {
      return zx::error(ZX_ERR_INVALID_ARGS);
    }
  }

  return zx::ok(fuchsia_driver_framework::wire::BindRule{
      .key = property_key,
      .condition = condition,
      .values = bind_rule_values,
  });
}

zx::result<fuchsia_driver_framework::wire::NodeProperty> ConvertBindPropToFidl(
    fidl::AnyArena& allocator, const device_bind_prop_t& bind_prop) {
  auto node_property = fuchsia_driver_framework::wire::NodeProperty{};

  switch (bind_prop.key.key_type) {
    case DEVICE_BIND_PROPERTY_KEY_INT: {
      node_property.key =
          fuchsia_driver_framework::wire::NodePropertyKey::WithIntValue(bind_prop.key.data.int_key);
      break;
    }
    case DEVICE_BIND_PROPERTY_KEY_STRING: {
      node_property.key = fuchsia_driver_framework::wire::NodePropertyKey::WithStringValue(
          allocator, allocator, bind_prop.key.data.str_key);
      break;
    }
    default: {
      return zx::error(ZX_ERR_INVALID_ARGS);
    }
  }

  switch (bind_prop.value.data_type) {
    case ZX_DEVICE_PROPERTY_VALUE_INT: {
      node_property.value = fuchsia_driver_framework::wire::NodePropertyValue::WithIntValue(
          bind_prop.value.data.int_value);
      break;
    }
    case ZX_DEVICE_PROPERTY_VALUE_STRING: {
      node_property.value = fuchsia_driver_framework::wire::NodePropertyValue::WithStringValue(
          allocator, allocator, bind_prop.value.data.str_value);
      break;
    }
    case ZX_DEVICE_PROPERTY_VALUE_BOOL: {
      node_property.value = fuchsia_driver_framework::wire::NodePropertyValue::WithBoolValue(
          bind_prop.value.data.bool_value);
      break;
    }
    case ZX_DEVICE_PROPERTY_VALUE_ENUM: {
      node_property.value = fuchsia_driver_framework::wire::NodePropertyValue::WithEnumValue(
          fidl::ObjectView<fidl::StringView>(allocator, allocator,
                                             bind_prop.value.data.enum_value));
      break;
    }
    default: {
      return zx::error(ZX_ERR_INVALID_ARGS);
    }
  }

  return zx::ok(node_property);
}

zx::result<fuchsia_driver_framework::wire::ParentSpec> ConvertNodeRepresentation(
    fidl::AnyArena& allocator, parent_spec_t node) {
  fidl::VectorView<fuchsia_driver_framework::wire::BindRule> bind_rules(allocator,
                                                                        node.bind_rule_count);
  for (size_t i = 0; i < node.bind_rule_count; i++) {
    auto bind_rule_result = ConvertBindRuleToFidl(allocator, node.bind_rules[i]);
    if (!bind_rule_result.is_ok()) {
      return bind_rule_result.take_error();
    }

    bind_rules[i] = std::move(bind_rule_result.value());
  }

  fidl::VectorView<fuchsia_driver_framework::wire::NodeProperty> props(allocator,
                                                                       node.property_count);
  for (size_t i = 0; i < node.property_count; i++) {
    auto prop_result = ConvertBindPropToFidl(allocator, node.properties[i]);
    if (!prop_result.is_ok()) {
      return prop_result.take_error();
    }

    props[i] = std::move(prop_result.value());
  }

  return zx::ok(fuchsia_driver_framework::wire::ParentSpec{
      .bind_rules = bind_rules,
      .properties = props,
  });
}

#endif  // SRC_DEVICES_MISC_DRIVERS_COMPAT_COMPOSITE_NODE_SPEC_UTIL_H_
