/*
 * Copyright 2018 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 
#include 
#include 
#include 
#include 
#include "avrcp_internal.h"
#include "hardware/avrcp/avrcp.h"
#include "packet/avrcp/avrcp_browse_packet.h"
#include "packet/avrcp/avrcp_packet.h"
#include "packet/avrcp/capabilities_packet.h"
#include "packet/avrcp/change_path.h"
#include "packet/avrcp/get_current_player_application_setting_value.h"
#include "packet/avrcp/get_element_attributes_packet.h"
#include "packet/avrcp/get_folder_items.h"
#include "packet/avrcp/get_item_attributes.h"
#include "packet/avrcp/get_total_number_of_items.h"
#include "packet/avrcp/list_player_application_setting_attributes.h"
#include "packet/avrcp/list_player_application_setting_values.h"
#include "packet/avrcp/play_item.h"
#include "packet/avrcp/register_notification_packet.h"
#include "packet/avrcp/set_addressed_player.h"
#include "packet/avrcp/set_browsed_player.h"
#include "packet/avrcp/set_player_application_setting_value.h"
#include "packet/avrcp/vendor_packet.h"
#include "profile/avrcp/media_id_map.h"
#include "raw_address.h"
namespace bluetooth {
namespace avrcp {
/**
 * A class representing a connection with a remote AVRCP device. It holds all
 * the state and message handling for the device that it represents.
 */
// TODO (apanicke): Once we move over to having the individual message
// responders for Browse and Classic AVRCP Messages move the device around via a
// weak pointer.
class Device {
 public:
  /**
   * Device is friends with Avrcp::ConnectionHandler so that ConnectionHandler
   * can deliver messages to individual devices.
   */
  friend class ConnectionHandler;
  Device(
      const RawAddress& bdaddr, bool avrcp13_compatibility,
      base::Callback message)>
          send_msg_cb,
      uint16_t ctrl_mtu, uint16_t browse_mtu);
  Device(const Device&) = delete;
  Device& operator=(const Device&) = delete;
  virtual ~Device() = default;
  /**
   * Gets a weak pointer to this device that is invalidated when the device is
   * disconnected.
   */
  base::WeakPtr Get();
  const RawAddress& GetAddress() const { return address_; };
  /**
   * Disconnects the AVRCP connection that this device represents.
   */
  bool Disconnect();
  /**
   * Set the status of the BIP obex client
   */
  void SetBipClientStatus(bool connected);
  /**
   * Returns true if the current device has a BIP OBEX client.
   */
  bool HasBipClient() const;
  /**
   * Returns true if the current device is silenced.
   */
  bool IsInSilenceMode() const;
  /**
   * Returns true if the current device is active.
   */
  bool IsActive() const;
  /**
   * Register the interfaces that the device uses to get information. If the
   * Volume Interface is null, then absolute volume is disabled.
   * TODO (apanicke): Add these to the constructor/factory so that each device
   * is created valid and can't be accidentally interacted with when no
   * interfaces are registered.
   */
  void RegisterInterfaces(MediaInterface* interface,
                          A2dpInterface* a2dp_interface,
                          VolumeInterface* volume_interface,
                          PlayerSettingsInterface* player_settings_interface);
  /**
   * Set the maximum size of a AVRCP Browsing Packet. This is done after the
   * connection of the Browsing channel.
   */
  void SetBrowseMtu(uint16_t browse_mtu);
  /**
   * Notify the device that metadata, play_status, and/or queue have updated
   * via a boolean. Each boolean represents whether its respective content has
   * updated.
   */
  virtual void SendMediaUpdate(bool metadata, bool play_status, bool queue);
  /**
   * Notify the device that the available_player, addressed_player, or UIDs
   * have updated via a boolean. Each boolean represents whether its respective
   * content has updated.
   */
  virtual void SendFolderUpdate(bool available_player, bool addressed_player,
                                bool uids);
  // TODO (apanicke): Split the message handlers into two files. One
  // for handling Browse Messages and the other for handling all other
  // messages. This prevents the .cc file from getting bloated like it is
  // now. The Device class will then become a state holder for each message
  // and all the functions in these handler classes can be static since the
  // device will be passed in. The extensions of the Device class can contain
  // any interop handling for specific messages on specific devices.
  void MessageReceived(uint8_t label, std::shared_ptr pkt);
  void BrowseMessageReceived(uint8_t label, std::shared_ptr pkt);
  void VendorPacketHandler(uint8_t label, std::shared_ptr pkt);
  /********************
   * MESSAGE RESPONSES
   ********************/
  // CURRENT TRACK CHANGED
  virtual void HandleTrackUpdate();
  virtual void TrackChangedNotificationResponse(
      uint8_t label, bool interim, std::string curr_song_id,
      std::vector song_list);
  // GET CAPABILITY
  virtual void HandleGetCapabilities(
      uint8_t label, const std::shared_ptr& pkt);
  // REGISTER NOTIFICATION
  virtual void HandleNotification(
      uint8_t label, const std::shared_ptr& pkt);
  // PLAY STATUS CHANGED
  virtual void HandlePlayStatusUpdate();
  // NOW PLAYING LIST CHANGED
  virtual void HandleNowPlayingUpdate();
  virtual void HandleNowPlayingNotificationResponse(
      uint8_t label, bool interim, std::string curr_song_id,
      std::vector song_list);
  // PLAY POSITION CHANGED
  virtual void HandlePlayPosUpdate();
  virtual void PlaybackPosNotificationResponse(uint8_t label, bool interim,
                                               PlayStatus status);
  // GET PLAY STATUS
  virtual void GetPlayStatusResponse(uint8_t label, PlayStatus status);
  virtual void PlaybackStatusNotificationResponse(uint8_t label, bool interim,
                                                  PlayStatus status);
  // PLAYER APPLICATION SETTINGS CHANGED
  virtual void HandlePlayerSettingChanged(
      std::vector attributes, std::vector values);
  virtual void PlayerSettingChangedNotificationResponse(
      uint8_t label, bool interim, std::vector attributes,
      std::vector values);
  // GET ELEMENT ATTRIBUTE
  // TODO (apanicke): Add a Handler function for this so if a specific device
  // needs to implement an interop fix, you only need to overload the one
  // function.
  virtual void GetElementAttributesResponse(
      uint8_t label, std::shared_ptr pkt,
      SongInfo info);
  // AVAILABLE PLAYER CHANGED
  virtual void HandleAvailablePlayerUpdate();
  // ADDRESSED PLAYER CHANGED
  virtual void HandleAddressedPlayerUpdate();
  virtual void RejectNotification();
  virtual void AddressedPlayerNotificationResponse(
      uint8_t label, bool interim, uint16_t curr_player,
      std::vector /* unused */);
  // GET FOLDER ITEMS
  virtual void HandleGetFolderItems(
      uint8_t label, std::shared_ptr request);
  virtual void GetMediaPlayerListResponse(
      uint8_t label, std::shared_ptr pkt,
      uint16_t curr_player, std::vector players);
  virtual void GetVFSListResponse(uint8_t label,
                                  std::shared_ptr pkt,
                                  std::vector items);
  virtual void GetNowPlayingListResponse(
      uint8_t label, std::shared_ptr pkt,
      std::string curr_song_id, std::vector song_list);
  // GET TOTAL NUMBER OF ITEMS
  virtual void HandleGetTotalNumberOfItems(
      uint8_t label, std::shared_ptr pkt);
  virtual void GetTotalNumberOfItemsMediaPlayersResponse(
      uint8_t label, uint16_t curr_player, std::vector list);
  virtual void GetTotalNumberOfItemsVFSResponse(uint8_t label,
                                                std::vector items);
  virtual void GetTotalNumberOfItemsNowPlayingResponse(
      uint8_t label, std::string curr_song_id, std::vector song_list);
  // GET ITEM ATTRIBUTES
  virtual void HandleGetItemAttributes(
      uint8_t label, std::shared_ptr request);
  virtual void GetItemAttributesNowPlayingResponse(
      uint8_t label, std::shared_ptr pkt,
      std::string curr_media_id, std::vector song_list);
  virtual void GetItemAttributesVFSResponse(
      uint8_t label, std::shared_ptr pkt,
      std::vector item_list);
  // SET BROWSED PLAYER
  virtual void HandleSetBrowsedPlayer(
      uint8_t label, std::shared_ptr request);
  virtual void SetBrowsedPlayerResponse(
      uint8_t label, std::shared_ptr pkt, bool success,
      std::string root_id, uint32_t num_items);
  // CHANGE PATH
  virtual void HandleChangePath(uint8_t label,
                                std::shared_ptr request);
  virtual void ChangePathResponse(uint8_t label,
                                  std::shared_ptr request,
                                  std::vector list);
  // PLAY ITEM
  virtual void HandlePlayItem(uint8_t label,
                              std::shared_ptr request);
  // SET ADDRESSED PLAYER
  virtual void HandleSetAddressedPlayer(
      uint8_t label, std::shared_ptr request,
      uint16_t curr_player, std::vector players);
  // LIST PLAYER APPLICATION SETTING ATTRIBUTES
  virtual void ListPlayerApplicationSettingAttributesResponse(
      uint8_t label, std::vector attributes);
  // LIST PLAYER APPLICATION SETTING VALUES
  virtual void ListPlayerApplicationSettingValuesResponse(
      uint8_t label, PlayerAttribute setting, std::vector values);
  // GET CURRENT PLAYER APPLICATION SETTING VALUE
  virtual void GetPlayerApplicationSettingValueResponse(
      uint8_t label, std::vector attributes,
      std::vector values);
  // SET PLAYER APPLICATION SETTING VALUE
  virtual void SetPlayerApplicationSettingValueResponse(uint8_t label,
                                                        CommandPdu pdu,
                                                        bool success);
  /********************
   * MESSAGE REQUESTS
   ********************/
  // VOLUME CHANGED NOTIFICATION
  virtual void RegisterVolumeChanged();
  virtual void HandleVolumeChanged(
      uint8_t label, const std::shared_ptr& pkt);
  // SET VOLUME
  virtual void SetVolume(int8_t volume);
  /**
   * This function is called by Avrcp::ConnectionHandler to signify that
   * the remote device was disconnected.
   *
   * TODO (apanicke): Prevent allowing responses to messages while the device is
   * disconnected by using a weak pointer handle to the device when we separate
   * out the message handling. Also separate the logic in the future when
   * disconnecting only browsing (Though this shouldn't matter as if we are
   * disconnecting browsing then we should be fully disconnecting the device).
   */
  void DeviceDisconnected();
  friend std::ostream& operator<<(std::ostream& out, const Device& c);
 private:
  // This should always contain one item which represents the root id on the
  // current player.
  std::string CurrentFolder() const {
    if (current_path_.empty()) return "";
    return current_path_.top();
  }
  void send_message(uint8_t label, bool browse,
                    std::unique_ptr<::bluetooth::PacketBuilder> message) {
    active_labels_.erase(label);
    send_message_cb_.Run(label, browse, std::move(message));
  }
  base::WeakPtrFactory weak_ptr_factory_;
  // TODO (apanicke): Initialize all the variables in the constructor.
  RawAddress address_;
  // Enables AVRCP 1.3 Compatibility mode. This disables any AVRCP 1.4+ features
  // such as browsing and playlists but has the highest chance of working.
  bool avrcp13_compatibility_ = false;
  base::Callback message)>
      send_message_cb_;
  uint16_t ctrl_mtu_;
  uint16_t browse_mtu_;
  bool has_bip_client_;
  int curr_browsed_player_id_ = -1;
  std::stack current_path_;
  // Notification Trackers
  using Notification = std::pair;
  Notification track_changed_ = Notification(false, 0);
  Notification play_status_changed_ = Notification(false, 0);
  Notification play_pos_changed_ = Notification(false, 0);
  Notification player_setting_changed_ = Notification(false, 0);
  Notification now_playing_changed_ = Notification(false, 0);
  Notification addr_player_changed_ = Notification(false, 0);
  Notification avail_players_changed_ = Notification(false, 0);
  Notification uids_changed_ = Notification(false, 0);
  MediaIdMap vfs_ids_;
  MediaIdMap now_playing_ids_;
  uint32_t play_pos_interval_ = 0;
  SongInfo last_song_info_;
  PlayStatus last_play_status_;
  base::CancelableClosure play_pos_update_cb_;
  MediaInterface* media_interface_ = nullptr;
  A2dpInterface* a2dp_interface_ = nullptr;
  VolumeInterface* volume_interface_ = nullptr;
  PlayerSettingsInterface* player_settings_interface_ = nullptr;
  // Labels used for messages currently in flight.
  std::set active_labels_;
  int8_t volume_ = -1;
};
}  // namespace avrcp
}  // namespace bluetooth