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

use {
    failure::{bail, Error},
    fidl_fuchsia_bluetooth_snoop::{SnoopControlHandle, SnoopPacket},
    fuchsia_syslog::{fx_log_warn, fx_vlog},
    std::{collections::HashMap, iter},
};

use crate::{ClientId, DeviceId};

/// `SubscriptionManager` tracks the client subscriptions for hci devices. It allows clients to be
/// registered and degregistered as subscribers, clean up all clients registered to
/// a specific device, and notify clients when packets are received on a device.
///
/// It optimizes for the `notify` usecase. Notification happens every time a new packet is logged
/// from a snoop channel. This can be very frequent. It intentionally does *not* optimize for
/// tracking state changes of subscribers and devices. This is because client and device state is
/// not expected to change frequently.
pub(crate) struct SubscriptionManager {
    global: Vec<(ClientId, SnoopControlHandle)>,
    by_device: HashMap<DeviceId, Vec<(ClientId, SnoopControlHandle)>>
}

impl SubscriptionManager {
    pub fn new() -> SubscriptionManager {
        SubscriptionManager {
            global: vec![],
            by_device: HashMap::new()
        }
    }

    /// Register a client as a subscriber. If `device` is provided, the client is registered to
    /// receive packets from a single device. If `device` is not provided, the client is registered
    /// to receive packets from all devices.
    ///
    /// Returns an error if the client is already registered as a subscriber.
    pub fn register(&mut self, id: ClientId, handle: SnoopControlHandle, device: Option<DeviceId>)
        -> Result<(), Error>
    {
        if self.is_registered(&id) {
            bail!("Client already registered.");
        }
        match device {
            Some(device) => {
                self.by_device.entry(device)
                    .or_insert_with(Vec::new)
                    .push((id, handle));
            }
            None => {
                self.global.push((id, handle))
            }
        }
        Ok(())
    }

    /// Remove client subscriptions by id if the client is currently registered.
    /// Set the client to shutdown.
    pub fn deregister(&mut self, id: &ClientId) {
        let global_subs = iter::once(&mut self.global);
        for subscribers in self.by_device.values_mut().chain(global_subs) {
            let index = subscribers.iter().position(|(id_, _)| id_ == id);
            if let Some(i) = index {
                let (_, handle) = subscribers.swap_remove(i);
                handle.shutdown();
            }
        }
    }

    /// Close connections to all clients that are registered as subscribers to the given device.
    /// Clients with global subscriptions are not affected.
    pub fn remove_device(&mut self, device_id: &DeviceId) {
        if let Some(clients) = self.by_device.remove(device_id){
            for (_, handle) in clients {
                handle.shutdown();
            }
        }
    }

    /// Is the client registered as a subscriber.
    pub fn is_registered(&mut self, id: &ClientId) -> bool {
        self.by_device.values()
            .flat_map(|v| v.iter())
            .chain(self.global.iter())
            .any(|(id_, _)| id_ == id)
    }

    /// Send `packet` to all clients that are subscribed to receive it.
    /// If sending the packet to a client results in an error, the client is deregistered and the
    /// error is logged.
    pub fn notify(&mut self, device: &DeviceId, packet: &mut SnoopPacket) {
        let mut success_count = 0;
        let mut to_cleanup = vec![];

        // Look up clients that are subscribed only to this device.
        let subscribers = self.by_device.get(device);
        // Chain on clients that are subscribed globally.
        let subscribers = subscribers.iter()
            .flat_map(|subs| subs.iter())
            .chain(self.global.iter());

        // Send events to all clients that have registered interest in this device
        for (id, handle) in subscribers {
            if let Err(e) = handle.send_on_packet(device, packet) {
                fx_log_warn!("Subscriber {} failed with {}. Removing.", id, e);
                to_cleanup.push(*id);
            } else {
                success_count += 1;
            }
        }

        // Clean up any client handles that have returned an error when sent an event.
        for id in to_cleanup {
            self.deregister(&id);
        }
        fx_vlog!(2, "Notified {} clients.", success_count);
    }

    #[allow(dead_code)] // Used in test assertions.
    pub fn number_of_subscribers(&self) -> usize {
        self.by_device.values().fold(self.global.len(), |acc, vec| acc + vec.len())
    }
}

