// Copyright 2018 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.

#include "topaz/runtime/flutter_runner/semantics_bridge.h"

#include <lib/syslog/global.h>

#include "topaz/runtime/dart/utils/inlines.h"

#include "topaz/runtime/flutter_runner/logging.h"

namespace flutter {

// Helper function to convert SkRect, Flutter semantics node bounding box
// format to fuchsia::ui::gfx::BoundingBox, the Fidl equivalent.
fuchsia::ui::gfx::BoundingBox WrapBoundingBox(SkRect& rect) {
  fuchsia::ui::gfx::BoundingBox box;
  box.min.x = rect.fLeft;
  box.min.y = rect.fTop;
  box.min.z = 0;
  box.max.x = rect.fRight;
  box.max.y = rect.fBottom;
  box.max.z = 0;
  return box;
}

// Helper function to convert SkMatrix44, Flutter semantics node transform
// format to fuchsia::ui::gfx::mat4, the Fidl equivalent.
fuchsia::ui::gfx::mat4 WrapSkMatrix(SkMatrix44& args) {
  fuchsia::ui::gfx::mat4 value;
  DEBUG_CHECK(value.matrix.count() == 16, LOG_TAG, "");
  float* m = value.matrix.mutable_data();
  args.asColMajorf(m);
  return value;
}

// Helper function to convert Flutter SemanticsNode to fuchsia Fidl
// accessibility node format.
fuchsia::accessibility::Node SerializeNode(blink::SemanticsNode node,
                                           float scale) {
  fuchsia::accessibility::Node s_node = fuchsia::accessibility::Node();
  s_node.node_id = node.id;
  s_node.children_hit_test_order =
      fidl::VectorPtr<int32_t>(node.childrenInHitTestOrder);
  s_node.children_traversal_order =
      fidl::VectorPtr<int32_t>(node.childrenInTraversalOrder);

  s_node.data = fuchsia::accessibility::Data();
  s_node.data.role = fuchsia::accessibility::Role::NONE;
  s_node.data.label = node.label;

  s_node.data.location = WrapBoundingBox(node.rect);
  SkMatrix44 inverse(SkMatrix44::kUninitialized_Constructor);
  node.transform.invert(&inverse);

  if (s_node.node_id == 0) {
    SkMatrix44 scaling(SkMatrix44::kIdentity_Constructor);
    scaling.setScale(scale, scale, 1);
    inverse = inverse * scaling;
  }
  s_node.data.transform = WrapSkMatrix(inverse);
  return s_node;
}

SemanticsBridge::SemanticsBridge(shell::PlatformView* platform_view,
                                 blink::LogicalMetrics* metrics)
    : binding_(this), platform_view_(platform_view), metrics_(metrics) {
  root_.set_error_handler([this](zx_status_t status) {
    FX_LOG(INFO, LOG_TAG, "A11y bridge disconnected from a11y manager");
    binding_.Unbind();
    root_.Unbind();
    platform_view_->SetSemanticsEnabled(false);
  });

  // Set up |a11y_toggle_| to listen for turning on/off a11y support.
  // If this disconnects, we shut down all other connections and disable
  // a11y support.
  a11y_toggle_.events().OnAccessibilityToggle =
      fit::bind_member(this, &SemanticsBridge::OnAccessibilityToggle);
  a11y_toggle_.set_error_handler([this](zx_status_t status) {
    FX_LOG(INFO, LOG_TAG, "Disconnected from a11y toggle broadcaster.");
    binding_.Unbind();
    root_.Unbind();
    environment_set_ = false;
    platform_view_->SetSemanticsEnabled(false);
  });
}

void SemanticsBridge::SetupEnvironment(
    uint32_t view_id,
    fuchsia::sys::ServiceProvider* environment_service_provider) {
  view_id_ = view_id;
  environment_service_provider_ = environment_service_provider;
  environment_service_provider->ConnectToService(
      fuchsia::accessibility::ToggleBroadcaster::Name_,
      a11y_toggle_.NewRequest().TakeChannel());
  environment_set_ = true;
  // Starts up accessibility support if accessibility was toggled before
  // the environment was set.
  if (enabled_) {
    OnAccessibilityToggle(enabled_);
  }
}

void SemanticsBridge::UpdateSemantics(
    const blink::SemanticsNodeUpdates& update) {
  fidl::VectorPtr<int32_t> delete_nodes;
  fidl::VectorPtr<fuchsia::accessibility::Node> update_nodes;
  for (auto it = update.begin(); it != update.end(); ++it) {
    blink::SemanticsNode node = it->second;
    // We delete nodes that are hidden from the screen.
    if (node.HasFlag(blink::SemanticsFlags::kIsHidden)) {
      delete_nodes.push_back(node.id);
    } else {
      update_nodes.push_back(SerializeNode(node, (float)metrics_->scale));
    }
  }
  // TODO(MI4-1539): re-enable after changes to semantics root API
  /*
  if (!delete_nodes.get().empty()) {
    root_->DeleteSemanticNodes(view_id_, std::move(delete_nodes));
  }
  if (!update_nodes.get().empty()) {
    root_->UpdateSemanticNodes(view_id_, std::move(update_nodes));
  }
  root_->Commit(view_id_);
   */
}

void SemanticsBridge::PerformAccessibilityAction(
    int32_t node_id, fuchsia::accessibility::Action action) {
  std::vector<uint8_t> args = {};
  switch (action) {
    case fuchsia::accessibility::Action::GAIN_ACCESSIBILITY_FOCUS:
      platform_view_->DispatchSemanticsAction(
          node_id, blink::SemanticsAction::kDidGainAccessibilityFocus, args);
      break;
    case fuchsia::accessibility::Action::LOSE_ACCESSIBILITY_FOCUS:
      platform_view_->DispatchSemanticsAction(
          node_id, blink::SemanticsAction::kDidLoseAccessibilityFocus, args);
      break;
    case fuchsia::accessibility::Action::TAP:
      platform_view_->DispatchSemanticsAction(
          node_id, blink::SemanticsAction::kTap, args);
      break;
    default:
      FX_LOG(ERROR, LOG_TAG, "Accessibility action not supported");
  }
}

void SemanticsBridge::OnAccessibilityToggle(bool enabled) {
  if (enabled == enabled_ && root_.is_bound()) {
    return;
  }
  enabled_ = enabled;
  if (enabled && environment_set_) {
    // Reconnect if the a11y manager connection is not bound.
    if (!root_.is_bound()) {
      environment_service_provider_->ConnectToService(
          fuchsia::accessibility::SemanticsRoot::Name_,
          root_.NewRequest().TakeChannel());
    }
    // TODO(MI4-1539): re-enable after changes to semantics root API
    /*
     if (root_.is_bound()) {
          root_->RegisterSemanticsProvider(view_id_, binding_.NewBinding());
          platform_view_->SetSemanticsEnabled(true);
          return;
        }
        */
  }
  root_.Unbind();
  // Disable if fall through to here.
  platform_view_->SetSemanticsEnabled(false);
}

}  // namespace flutter
