/*
 * Copyright 2020 The Android Open Source Project
 *
 * 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
 *
 *      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 <cstdint>
#include <string>

#include "device/include/esco_parameters.h"
#include "stack/include/btm_api_types.h"

constexpr uint16_t kMaxScoLinks = static_cast<uint16_t>(BTM_MAX_SCO_LINKS);

#ifndef ESCO_DATA_PATH
#ifdef OS_ANDROID
#define ESCO_DATA_PATH ESCO_DATA_PATH_PCM
#else
#define ESCO_DATA_PATH ESCO_DATA_PATH_HCI
#endif
#endif

// SCO-over-HCI audio related definitions
namespace bluetooth::audio::sco {

// Initialize SCO-over-HCI socket (UIPC); the client is audio server.
void init();

// Open the socket when there is SCO connection open
void open();

// Clean up the socket when the SCO connection is done
void cleanup();

// Read from the socket (audio server) for SCO Tx
size_t read(uint8_t* p_buf, uint32_t len);

// Write to the socket from SCO Rx
size_t write(const uint8_t* buf, uint32_t len);
}  // namespace bluetooth::audio::sco

/* Define the structures needed by sco
 */

typedef enum : uint16_t {
  SCO_ST_UNUSED = 0,
  SCO_ST_LISTENING = 1,
  SCO_ST_W4_CONN_RSP = 2,
  SCO_ST_CONNECTING = 3,
  SCO_ST_CONNECTED = 4,
  SCO_ST_DISCONNECTING = 5,
  SCO_ST_PEND_UNPARK = 6,
  SCO_ST_PEND_ROLECHANGE = 7,
  SCO_ST_PEND_MODECHANGE = 8,
} tSCO_STATE;

inline std::string sco_state_text(const tSCO_STATE& state) {
  switch (state) {
    case SCO_ST_UNUSED:
      return std::string("unused");
    case SCO_ST_LISTENING:
      return std::string("listening");
    case SCO_ST_W4_CONN_RSP:
      return std::string("connect_response");
    case SCO_ST_CONNECTING:
      return std::string("connecting");
    case SCO_ST_CONNECTED:
      return std::string("connected");
    case SCO_ST_DISCONNECTING:
      return std::string("disconnecting");
    case SCO_ST_PEND_UNPARK:
      return std::string("pending_unpark");
    case SCO_ST_PEND_ROLECHANGE:
      return std::string("pending_role_change");
    case SCO_ST_PEND_MODECHANGE:
      return std::string("pending_mode_change");
  }
}

/* Define the structure that contains (e)SCO data */
typedef struct {
  tBTM_ESCO_CBACK* p_esco_cback; /* Callback for eSCO events     */
  enh_esco_params_t setup;
  tBTM_ESCO_DATA data; /* Connection complete information */
  uint8_t hci_status;
} tBTM_ESCO_INFO;

/* Define the structure used for SCO Management
 */
typedef struct {
  tBTM_ESCO_INFO esco;    /* Current settings             */
  tBTM_SCO_CB* p_conn_cb; /* Callback for when connected  */
  tBTM_SCO_CB* p_disc_cb; /* Callback for when disconnect */
  tSCO_STATE state;       /* The state of the SCO link    */

  uint16_t hci_handle;    /* HCI Handle                   */
 public:
  bool is_active() const { return state != SCO_ST_UNUSED; }
  uint16_t Handle() const { return hci_handle; }

  bool is_orig;           /* true if the originator       */
  bool rem_bd_known;      /* true if remote BD addr known */

} tSCO_CONN;

/* SCO Management control block */
typedef struct {
  tSCO_CONN sco_db[BTM_MAX_SCO_LINKS];
  enh_esco_params_t def_esco_parms;
  bool esco_supported;        /* true if 1.2 cntlr AND supports eSCO links */

  tSCO_CONN* get_sco_connection_from_index(uint16_t index) {
    return (index < kMaxScoLinks) ? (&sco_db[index]) : nullptr;
  }

  tSCO_CONN* get_sco_connection_from_handle(uint16_t handle) {
    tSCO_CONN* p_sco = sco_db;
    for (uint16_t xx = 0; xx < kMaxScoLinks; xx++, p_sco++) {
      if (p_sco->hci_handle == handle) {
        return p_sco;
      }
    }
    return nullptr;
  }

  void Init() {
    def_esco_parms = esco_parameters_for_codec(ESCO_CODEC_CVSD_S3);
    bluetooth::audio::sco::init();
  }

  uint16_t get_index(const tSCO_CONN* p_sco) const {
    CHECK(p_sco != nullptr);
    const tSCO_CONN* p = sco_db;
    for (uint16_t xx = 0; xx < kMaxScoLinks; xx++, p++) {
      if (p_sco == p) {
        return xx;
      }
    }
    return 0xffff;
  }

} tSCO_CB;

extern void btm_sco_chk_pend_rolechange(uint16_t hci_handle);
extern void btm_sco_disc_chk_pend_for_modechange(uint16_t hci_handle);

// Visible for test only
BT_HDR* btm_sco_make_packet(std::vector<uint8_t> data, uint16_t sco_handle);

// Send a SCO packet
void btm_send_sco_packet(std::vector<uint8_t> data);
