# Copyright 2022 The Pigweed Authors
#
# Licensed 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
#
#     https://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.

import("//build_overrides/pigweed.gni")

import("$dir_pigweed/third_party/emboss/build_defs.gni")
import("$dir_pw_async2/backend.gni")
import("$dir_pw_bloat/bloat.gni")
import("$dir_pw_build/module_config.gni")
import("$dir_pw_build/target_types.gni")
import("$dir_pw_chrono/backend.gni")
import("$dir_pw_unit_test/test.gni")

declare_args() {
  # The build target that overrides the default configuration options for this
  # module. This should point to a source set that provides defines through a
  # public config (which may -include a file or add defines directly).
  pw_bluetooth_CONFIG = pw_build_DEFAULT_MODULE_CONFIG
}

pw_source_set("config") {
  public = [ "public/pw_bluetooth/config.h" ]
  public_configs = [ ":public_include_path" ]
  public_deps = [ pw_bluetooth_CONFIG ]
}

config("public_include_path") {
  include_dirs = [ "public" ]
  visibility = [ ":*" ]
}

pw_source_set("pw_bluetooth") {
  public_configs = [ ":public_include_path" ]
  public = [
    "public/pw_bluetooth/address.h",
    "public/pw_bluetooth/assigned_uuids.h",
    "public/pw_bluetooth/constants.h",
    "public/pw_bluetooth/controller.h",
    "public/pw_bluetooth/gatt/client.h",
    "public/pw_bluetooth/gatt/constants.h",
    "public/pw_bluetooth/gatt/error.h",
    "public/pw_bluetooth/gatt/server.h",
    "public/pw_bluetooth/gatt/types.h",
    "public/pw_bluetooth/host.h",
    "public/pw_bluetooth/internal/raii_ptr.h",
    "public/pw_bluetooth/low_energy/advertising_data.h",
    "public/pw_bluetooth/low_energy/bond_data.h",
    "public/pw_bluetooth/low_energy/central.h",
    "public/pw_bluetooth/low_energy/channel.h",
    "public/pw_bluetooth/low_energy/connection.h",
    "public/pw_bluetooth/low_energy/peripheral.h",
    "public/pw_bluetooth/low_energy/security_mode.h",
    "public/pw_bluetooth/pairing_delegate.h",
    "public/pw_bluetooth/peer.h",
    "public/pw_bluetooth/result.h",
    "public/pw_bluetooth/types.h",
    "public/pw_bluetooth/uuid.h",
    "public/pw_bluetooth/vendor.h",
  ]
  public_deps = [
    ":config",
    "$dir_pw_chrono:system_clock",
    "$dir_pw_string:hex",
    "$dir_pw_string:string",
    dir_pw_containers,
    dir_pw_function,
    dir_pw_multibuf,
    dir_pw_result,
    dir_pw_span,
    dir_pw_status,
    dir_pw_uuid,
  ]
}

pw_source_set("pw_bluetooth2") {
  public_configs = [ ":public_include_path" ]
  public = [
    "public/pw_bluetooth/address.h",
    "public/pw_bluetooth/assigned_uuids.h",
    "public/pw_bluetooth/constants.h",
    "public/pw_bluetooth/controller2.h",
    "public/pw_bluetooth/gatt/client2.h",
    "public/pw_bluetooth/gatt/constants.h",
    "public/pw_bluetooth/gatt/error.h",
    "public/pw_bluetooth/gatt/server2.h",
    "public/pw_bluetooth/gatt/types.h",
    "public/pw_bluetooth/internal/raii_ptr.h",
    "public/pw_bluetooth/low_energy/advertising_data.h",
    "public/pw_bluetooth/low_energy/bond_data2.h",
    "public/pw_bluetooth/low_energy/central2.h",
    "public/pw_bluetooth/low_energy/channel.h",
    "public/pw_bluetooth/low_energy/connection2.h",
    "public/pw_bluetooth/low_energy/peripheral2.h",
    "public/pw_bluetooth/low_energy/phy.h",
    "public/pw_bluetooth/low_energy/security_mode.h",
    "public/pw_bluetooth/pairing_delegate2.h",
    "public/pw_bluetooth/peer.h",
    "public/pw_bluetooth/types.h",
    "public/pw_bluetooth/uuid.h",
    "public/pw_bluetooth/vendor.h",
  ]
  public_deps = [
    ":config",
    "$dir_pw_async2:dispatcher",
    "$dir_pw_async2:once_sender",
    "$dir_pw_chrono:system_clock",
    "$dir_pw_result:expected",
    "$dir_pw_string:hex",
    "$dir_pw_string:string",
    dir_pw_channel,
    dir_pw_containers,
    dir_pw_function,
    dir_pw_multibuf,
    dir_pw_result,
    dir_pw_span,
    dir_pw_status,
    dir_pw_uuid,
  ]
}

pw_source_set("emboss_util") {
  public_configs = [ ":public_include_path" ]
  public = [ "public/pw_bluetooth/emboss_util.h" ]
  public_deps = [
    dir_pw_result,
    dir_pw_span,
    dir_pw_status,
    dir_pw_uuid,
  ]
}
pw_source_set("hci_util") {
  public_configs = [ ":public_include_path" ]
  public = [ "public/pw_bluetooth/hci_util.h" ]
  sources = [ "hci_util.cc" ]
  public_deps = [
    ":emboss_hci_common",
    ":emboss_hci_data",
    ":emboss_hci_h4",
    dir_pw_result,
    dir_pw_span,
    dir_pw_status,
  ]
}

pw_source_set("snoop") {
  public_configs = [ ":public_include_path" ]
  public = [ "public/pw_bluetooth/snoop.h" ]
  sources = [ "snoop.cc" ]
  public_deps = [
    ":emboss_snoop",
    "$dir_pw_chrono:system_clock",
    "$dir_pw_containers:inline_var_len_entry_queue",
    "$dir_pw_sync:mutex",
    "$dir_pw_sync:virtual_basic_lockable",
    dir_pw_assert,
    dir_pw_bluetooth_proxy,
    dir_pw_hex_dump,
    dir_pw_log,
    dir_pw_result,
  ]
}

if (dir_pw_third_party_emboss != "") {
  config("emboss_include_path") {
    include_dirs = [
      "$target_gen_dir/public",

      # Emboss headers (.emb.h) need to look for imported Emboss file headers in
      # Pigweed's root gen directory. This is *not* root_gen_dir in
      # external repositories depending on Pigweed.
      "$target_gen_dir/..",
    ]
    visibility = [ ":*" ]
  }

  emboss_cc_library("emboss_att") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/att.emb"
    imports = [
      "public/pw_bluetooth/hci_data.emb",
      "public/pw_bluetooth/l2cap_frames.emb",
    ]
    import_dirs = [ "public" ]
    deps = [
      ":emboss_hci_data",
      ":emboss_l2cap_frames",
    ]
  }

  emboss_cc_library("emboss_hci_android") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_android.emb"
    imports = [ "public/pw_bluetooth/hci_common.emb" ]
    import_dirs = [ "public" ]
    deps = [ ":emboss_hci_common" ]
  }

  emboss_cc_library("emboss_hci_common") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_common.emb"
  }

  emboss_cc_library("emboss_hci_commands") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_commands.emb"
    imports = [ "public/pw_bluetooth/hci_common.emb" ]
    import_dirs = [ "public" ]
    deps = [ ":emboss_hci_common" ]
  }

  emboss_cc_library("emboss_hci_data") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_data.emb"
  }

  emboss_cc_library("emboss_hci_events") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_events.emb"
    imports = [ "public/pw_bluetooth/hci_common.emb" ]
    import_dirs = [ "public" ]
    deps = [ ":emboss_hci_common" ]
  }

  emboss_cc_library("emboss_hci_h4") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_h4.emb"
    imports = [ "public/pw_bluetooth/hci_h4.emb" ]
    import_dirs = [ "public" ]
  }

  emboss_cc_library("emboss_hci_test") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/hci_test.emb"
    imports = [ "public/pw_bluetooth/hci_common.emb" ]
    import_dirs = [ "public" ]
    deps = [ ":emboss_hci_common" ]
  }

  emboss_cc_library("emboss_l2cap_frames") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/l2cap_frames.emb"
  }

  emboss_cc_library("emboss_rfcomm_frames") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/rfcomm_frames.emb"
  }

  emboss_cc_library("emboss_snoop") {
    public_configs = [ ":emboss_include_path" ]
    source = "public/pw_bluetooth/snoop.emb"
  }

  group("emboss_hci_group") {
    public_configs = [ ":emboss_include_path" ]
    public_deps = [
      ":emboss_hci_android",
      ":emboss_hci_commands",
      ":emboss_hci_common",
      ":emboss_hci_data",
      ":emboss_hci_events",
      ":emboss_hci_h4",
    ]
  }
} else {
  group("emboss_att") {
  }
  group("emboss_hci_android") {
  }
  group("emboss_hci_common") {
  }
  group("emboss_hci_commands") {
  }
  group("emboss_hci_data") {
  }
  group("emboss_hci_events") {
  }
  group("emboss_hci_h4") {
  }
  group("emboss_hci_test") {
  }
  group("emboss_hci_group") {
  }
  group("emboss_l2cap_frames") {
  }
  group("emboss_rfcomm_frames") {
  }
}

pw_test_group("tests") {
  enable_if = pw_chrono_SYSTEM_CLOCK_BACKEND != ""
  tests = [
    ":address_test",
    ":api_test",
    ":api2_test",
    ":result_test",
    ":uuid_test",
    ":emboss_test",
    ":emboss_util_test",
    ":snoop_test",
  ]
}

pw_test("address_test") {
  sources = [ "address_test.cc" ]
  deps = [ ":pw_bluetooth" ]
}

pw_test("api_test") {
  sources = [ "api_test.cc" ]
  deps = [ ":pw_bluetooth" ]
}

pw_test("emboss_util_test") {
  enable_if =
      dir_pw_third_party_emboss != "" && pw_chrono_SYSTEM_CLOCK_BACKEND != ""
  sources = [ "emboss_util_test.cc" ]
  include_dirs = [ "." ]
  deps = [
    ":emboss_hci_test",
    ":emboss_util",
  ]
}

pw_test("api2_test") {
  enable_if = pw_async2_DISPATCHER_BACKEND != ""
  sources = [ "api2_test.cc" ]
  deps = [ ":pw_bluetooth2" ]
}

pw_test("result_test") {
  sources = [ "result_test.cc" ]
  deps = [ ":pw_bluetooth" ]
}

pw_test("uuid_test") {
  sources = [ "uuid_test.cc" ]
  deps = [ ":pw_bluetooth" ]
}

pw_test("emboss_test") {
  enable_if = dir_pw_third_party_emboss != ""
  sources = [ "emboss_test.cc" ]
  deps = [
    # All emboss targets are listed (even if they don't have explicit tests) to
    # ensure they are compiled.
    ":emboss_att",
    ":emboss_hci_group",
    ":emboss_hci_test",
    ":emboss_l2cap_frames",
    ":emboss_rfcomm_frames",
    ":emboss_util",
    "$pw_external_fuchsia:stdcompat",
  ]
}

if (dir_pw_third_party_emboss != "") {
  pw_size_diff("emboss_size_report") {
    title = "pw_bluetooth Emboss Size Report"
    base = "$dir_pw_bloat:bloat_base"
    binaries = [
      {
        target = "size_report:make_view_and_write"
        label = "Make view and write field"
      },
    ]
  }

  pw_size_diff("emboss_size_report_diff") {
    title = "pw_bluetooth Emboss Size Report diff"
    base = "size_report:make_view_and_write"
    binaries = [
      {
        target = "size_report:make_2_views_and_write"
        label = "Size difference when adding a second view"
      },
    ]
  }
} else {
  pw_size_diff("emboss_size_report") {
    title = "pw_bluetooth Emboss Size Report"
    base = "$dir_pw_bloat:bloat_base"
    binaries = [
      {
        target = "$dir_pw_bloat:bloat_base"
        label = "Emboss not configured."
      },
    ]
  }

  pw_size_diff("emboss_size_report_diff") {
    title = "pw_bluetooth Emboss Size Report diff"
    base = "$dir_pw_bloat:bloat_base"
    binaries = [
      {
        target = "$dir_pw_bloat:bloat_base"
        label = "Emboss not configured."
      },
    ]
  }
}

pw_test("hci_util_test") {
  enable_if =
      dir_pw_third_party_emboss != "" && pw_chrono_SYSTEM_CLOCK_BACKEND != ""
  sources = [ "hci_util_test.cc" ]
  include_dirs = [ "." ]
  deps = [ ":hci_util" ]
}

pw_test("snoop_test") {
  enable_if =
      dir_pw_third_party_emboss != "" && pw_chrono_SYSTEM_CLOCK_BACKEND != ""
  sources = [ "snoop_test.cc" ]
  include_dirs = [ "." ]
  deps = [
    ":snoop",
    "$dir_pw_chrono:simulated_system_clock",
  ]
}
