// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Useful modules for OpenTitanTool application development.
pub mod command;
pub mod config;

use crate::io::emu::Emulator;
use crate::io::gpio::{GpioMonitoring, GpioPin, PinMode, PullMode};
use crate::io::i2c::Bus;
use crate::io::spi::Target;
use crate::io::uart::Uart;
use crate::transport::{
    Capability, Progress, ProxyOps, Transport, TransportError, TransportInterfaceType,
};
use anyhow::Result;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};
use serde_annotate::Annotate;
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::rc::Rc;
use std::vec::Vec;

const DEFAULT_TEMPLATE: &str = "[{elapsed_precise}] [{wide_bar}] {bytes}/{total_bytes} ({eta})";

/// Helper function to create a progress bar in the same form for each of
/// the commands which will use it.
pub fn progress_bar(total: u64) -> ProgressBar {
    let progress = ProgressBar::new(total);
    progress.set_style(ProgressStyle::default_bar().template(DEFAULT_TEMPLATE));
    progress
}

/// Helper struct for displaying progress bars for operations which may have multiple stages
/// (e.g. erasing then writing), or whose byte size may not be known until the operation is
/// underway.
pub struct StagedProgressBar {
    pub current_progress_bar: Rc<RefCell<Option<indicatif::ProgressBar>>>,
}

impl Default for StagedProgressBar {
    fn default() -> Self {
        Self::new()
    }
}

impl StagedProgressBar {
    const STAGE_TEMPLATE: &str =
        "{msg}: [{elapsed_precise}] [{wide_bar}] {bytes}/{total_bytes} ({eta})";

    pub fn new() -> Self {
        Self {
            current_progress_bar: Rc::new(RefCell::new(None)),
        }
    }

    /// Construct boxed progress function, suitable for passing to certain methods that perform
    /// I/O or otherwise may take a long time to complete.
    pub fn pfunc(&self) -> Box<dyn Fn(Progress)> {
        let func_rc = self.current_progress_bar.clone();
        Box::new(move |pos| match pos {
            // A new stage has started (possibly the first), record the number of bytes and its
            // name.
            Progress::Stage { name, total } => {
                let progress = progress_bar(total as u64);
                if !name.is_empty() {
                    progress.set_style(ProgressStyle::default_bar().template(Self::STAGE_TEMPLATE));
                }
                func_rc.borrow_mut().replace(progress.with_message(name));
            }
            // Progress has been made on the current state (possibly completed).
            Progress::Progress { pos } => {
                let bar = func_rc.as_ref().borrow();
                let bar = bar.as_ref().unwrap();
                if pos as u64 == bar.length() {
                    bar.finish();
                    return;
                }
                bar.set_position(pos as u64);
            }
        })
    }
}

#[derive(Default, Debug)]
pub struct PinConfiguration {
    /// The input/output mode of the GPIO pin.
    pub mode: Option<PinMode>,
    /// The default/initial level of the pin (true means high), has effect only in `PushPull` or
    /// `OpenDrain` modes.
    pub level: Option<bool>,
    /// Whether the pin has pullup/down resistor enabled.
    pub pull_mode: Option<PullMode>,
    /// The default/initial analog level of the pin in Volts, has effect only in `AnalogOutput`
    /// mode.
    pub volts: Option<f32>,
}

fn merge_field<T>(f1: &mut Option<T>, f2: Option<T>) -> Result<(), ()>
where
    T: PartialEq<T> + Copy,
{
    match (&*f1, f2) {
        (Some(v1), Some(v2)) if *v1 != v2 => return Err(()),
        (None, _) => *f1 = f2,
        _ => (),
    }
    Ok(())
}

impl PinConfiguration {
    /// Sometimes one configuration file specifies OpenDrain while leaving out the level, and
    /// another file specifies high level, while leaving out the mode.  This method will merge
    /// declarations from multiple files, as long as they are not conflicting (e.g. both PushPull
    /// and OpenDrain, or both high and low level.)
    fn merge(&mut self, other: &PinConfiguration) -> Result<(), ()> {
        merge_field(&mut self.mode, other.mode)?;
        merge_field(&mut self.level, other.level)?;
        merge_field(&mut self.pull_mode, other.pull_mode)?;
        merge_field(&mut self.volts, other.volts)?;
        Ok(())
    }
}

#[derive(Default, Debug)]
pub struct SpiConfiguration {
    pub bits_per_sec: Option<u32>,
}

impl SpiConfiguration {
    fn merge(&mut self, other: &SpiConfiguration) -> Result<(), ()> {
        merge_field(&mut self.bits_per_sec, other.bits_per_sec)?;
        Ok(())
    }
}

pub struct TransportWrapperBuilder {
    transport: RefCell<Box<dyn Transport>>,
    pin_alias_map: HashMap<String, String>,
    uart_map: HashMap<String, String>,
    spi_map: HashMap<String, String>,
    i2c_map: HashMap<String, String>,
    pin_conf_list: Vec<(String, PinConfiguration)>,
    spi_conf_list: Vec<(String, SpiConfiguration)>,
    strapping_conf_map: HashMap<String, Vec<(String, PinConfiguration)>>,
}

// This is the structure to be passed to each Command implementation,
// replacing the "bare" Transport argument.  The fields other than
// transport will have been computed from a number ConfigurationFiles.
pub struct TransportWrapper {
    transport: RefCell<Box<dyn Transport>>,
    pin_map: HashMap<String, String>,
    uart_map: HashMap<String, String>,
    spi_map: HashMap<String, String>,
    i2c_map: HashMap<String, String>,
    pin_conf_map: HashMap<String, PinConfiguration>,
    spi_conf_map: HashMap<String, SpiConfiguration>,
    strapping_conf_map: HashMap<String, HashMap<String, PinConfiguration>>,
}

impl TransportWrapperBuilder {
    pub fn new(transport: Box<dyn crate::transport::Transport>) -> Self {
        Self {
            transport: RefCell::new(transport),
            pin_alias_map: HashMap::new(),
            uart_map: HashMap::new(),
            spi_map: HashMap::new(),
            i2c_map: HashMap::new(),
            pin_conf_list: Vec::new(),
            spi_conf_list: Vec::new(),
            strapping_conf_map: HashMap::new(),
        }
    }

    fn record_pin_conf(
        pin_conf_list: &mut Vec<(String, PinConfiguration)>,
        pin_conf: &config::PinConfiguration,
    ) {
        if (None, None, None, None)
            == (
                pin_conf.mode,
                pin_conf.pull_mode,
                pin_conf.level,
                pin_conf.volts,
            )
        {
            return;
        }
        let mut conf_entry: PinConfiguration = PinConfiguration::default();
        if let Some(pin_mode) = pin_conf.mode {
            conf_entry.mode = Some(pin_mode);
        }
        if let Some(pull_mode) = pin_conf.pull_mode {
            conf_entry.pull_mode = Some(pull_mode);
        }
        if let Some(level) = pin_conf.level {
            conf_entry.level = Some(level);
        }
        if let Some(volts) = pin_conf.volts {
            conf_entry.volts = Some(volts);
        }
        pin_conf_list.push((pin_conf.name.to_string(), conf_entry))
    }

    fn record_spi_conf(
        spi_conf_list: &mut Vec<(String, SpiConfiguration)>,
        spi_conf: &config::SpiConfiguration,
    ) {
        if spi_conf.bits_per_sec.is_none() {
            return;
        }
        let mut conf_entry: SpiConfiguration = SpiConfiguration::default();
        if let Some(bits_per_sec) = spi_conf.bits_per_sec {
            conf_entry.bits_per_sec = Some(bits_per_sec);
        }
        spi_conf_list.push((spi_conf.name.to_string(), conf_entry))
    }

    pub fn add_configuration_file(&mut self, file: config::ConfigurationFile) -> Result<()> {
        // Merge content of configuration file into pin_map and other members.
        for pin_conf in file.pins {
            if let Some(alias_of) = &pin_conf.alias_of {
                self.pin_alias_map
                    .insert(pin_conf.name.to_uppercase(), alias_of.clone());
            }
            // Record default input / open drain / push pull configuration to the pin.
            Self::record_pin_conf(&mut self.pin_conf_list, &pin_conf);
        }
        for strapping_conf in file.strappings {
            let strapping_pin_map = self
                .strapping_conf_map
                .entry(strapping_conf.name.to_uppercase())
                .or_default();
            for pin_conf in strapping_conf.pins {
                Self::record_pin_conf(strapping_pin_map, &pin_conf);
            }
        }
        for spi_conf in file.spi {
            if let Some(alias_of) = &spi_conf.alias_of {
                self.spi_map
                    .insert(spi_conf.name.to_uppercase(), alias_of.clone());
            }
            Self::record_spi_conf(&mut self.spi_conf_list, &spi_conf);
        }
        for uart_conf in file.uarts {
            if let Some(alias_of) = &uart_conf.alias_of {
                self.uart_map
                    .insert(uart_conf.name.to_uppercase(), alias_of.clone());
            }
            // TODO(#8769): Record baud / parity configration for later
            // use when opening uart.
        }
        Ok(())
    }

    fn consolidate_pin_conf_map(
        pin_alias_map: &HashMap<String, String>,
        pin_conf_list: &Vec<(String, PinConfiguration)>,
    ) -> Result<HashMap<String, PinConfiguration>> {
        let mut result_pin_conf_map: HashMap<String, PinConfiguration> = HashMap::new();
        for (name, conf) in pin_conf_list {
            result_pin_conf_map
                .entry(map_name(pin_alias_map, name))
                .or_default()
                .merge(conf)
                .map_err(|_| {
                    TransportError::InconsistentConf(TransportInterfaceType::Gpio, name.to_string())
                })?;
        }
        Ok(result_pin_conf_map)
    }

    fn consolidate_spi_conf_map(
        spi_alias_map: &HashMap<String, String>,
        spi_conf_list: &Vec<(String, SpiConfiguration)>,
    ) -> Result<HashMap<String, SpiConfiguration>> {
        let mut result_spi_conf_map: HashMap<String, SpiConfiguration> = HashMap::new();
        for (name, conf) in spi_conf_list {
            result_spi_conf_map
                .entry(map_name(spi_alias_map, name))
                .or_default()
                .merge(conf)
                .map_err(|_| {
                    TransportError::InconsistentConf(TransportInterfaceType::Spi, name.to_string())
                })?;
        }
        Ok(result_spi_conf_map)
    }

    pub fn build(self) -> Result<TransportWrapper> {
        let pin_conf_map =
            Self::consolidate_pin_conf_map(&self.pin_alias_map, &self.pin_conf_list)?;
        let mut strapping_conf_map: HashMap<String, HashMap<String, PinConfiguration>> =
            HashMap::new();
        for (strapping_name, pin_conf_map) in self.strapping_conf_map {
            strapping_conf_map.insert(
                strapping_name,
                Self::consolidate_pin_conf_map(&self.pin_alias_map, &pin_conf_map)?,
            );
        }
        let spi_conf_map = Self::consolidate_spi_conf_map(&self.spi_map, &self.spi_conf_list)?;
        Ok(TransportWrapper {
            transport: self.transport,
            pin_map: self.pin_alias_map,
            uart_map: self.uart_map,
            spi_map: self.spi_map,
            i2c_map: self.i2c_map,
            pin_conf_map,
            spi_conf_map,
            strapping_conf_map,
        })
    }
}

impl TransportWrapper {
    /// Returns a `Capabilities` object to check the capabilities of this
    /// transport object.
    pub fn capabilities(&self) -> Result<crate::transport::Capabilities> {
        self.transport.borrow().capabilities()
    }

    /// Returns a SPI [`Target`] implementation.
    pub fn spi(&self, name: &str) -> Result<Rc<dyn Target>> {
        self.transport
            .borrow()
            .spi(map_name(&self.spi_map, name).as_str())
    }

    /// Returns a I2C [`Bus`] implementation.
    pub fn i2c(&self, name: &str) -> Result<Rc<dyn Bus>> {
        self.transport
            .borrow()
            .i2c(map_name(&self.i2c_map, name).as_str())
    }

    /// Returns a [`Uart`] implementation.
    pub fn uart(&self, name: &str) -> Result<Rc<dyn Uart>> {
        self.transport
            .borrow()
            .uart(map_name(&self.uart_map, name).as_str())
    }

    /// Returns a [`GpioPin`] implementation.
    pub fn gpio_pin(&self, name: &str) -> Result<Rc<dyn GpioPin>> {
        let resolved_pin_name = map_name(&self.pin_map, name);
        if resolved_pin_name == "NULL" {
            return Ok(Rc::new(NullPin::new(name)));
        }
        self.transport.borrow().gpio_pin(resolved_pin_name.as_str())
    }

    /// Convenience method, returns a number of [`GpioPin`] implementations.
    pub fn gpio_pins(&self, names: &[String]) -> Result<Vec<Rc<dyn GpioPin>>> {
        let mut result = Vec::new();
        for name in names {
            result.push(self.gpio_pin(name)?);
        }
        Ok(result)
    }

    /// Returns a [`GpioMonitoring`] implementation.
    pub fn gpio_monitoring(&self) -> Result<Rc<dyn GpioMonitoring>> {
        self.transport.borrow().gpio_monitoring()
    }

    /// Returns a [`Emulator`] implementation.
    pub fn emulator(&self) -> Result<Rc<dyn Emulator>> {
        self.transport.borrow().emulator()
    }

    /// Methods available only on Proxy implementation.
    pub fn proxy_ops(&self) -> Result<Rc<dyn ProxyOps>> {
        self.transport.borrow().proxy_ops()
    }

    /// Invoke non-standard functionality of some Transport implementations.
    pub fn dispatch(&self, action: &dyn Any) -> Result<Option<Box<dyn Annotate>>> {
        self.transport.borrow().dispatch(action)
    }

    /// Apply given configuration to a single pins.
    fn apply_pin_configuration(&self, name: &str, conf: &PinConfiguration) -> Result<()> {
        let pin = self.gpio_pin(name)?;
        pin.set(conf.mode, conf.level, conf.pull_mode, conf.volts)
    }

    /// Apply given configuration to a all the given pins.
    fn apply_pin_configurations(&self, conf_map: &HashMap<String, PinConfiguration>) -> Result<()> {
        for (name, conf) in conf_map {
            self.apply_pin_configuration(name, conf)?
        }
        Ok(())
    }

    fn apply_spi_configurations(&self, conf_map: &HashMap<String, SpiConfiguration>) -> Result<()> {
        for (name, conf) in conf_map {
            let spi = self.spi(name)?;
            if let Some(bits_per_sec) = conf.bits_per_sec {
                spi.set_max_speed(bits_per_sec)?;
            }
        }
        Ok(())
    }

    /// Configure all pins as input/output, pullup, etc. as declared in configuration files.
    /// Also configure SPI port mode/speed, and other similar settings.
    pub fn apply_default_configuration(&self) -> Result<()> {
        self.transport.borrow().apply_default_configuration()?;
        self.apply_pin_configurations(&self.pin_conf_map)?;
        self.apply_spi_configurations(&self.spi_conf_map)?;
        Ok(())
    }

    /// Configure a specific set of pins as strong/weak pullup/pulldown as declared in
    /// configuration files under a given strapping name.
    pub fn apply_pin_strapping(&self, strapping_name: &str) -> Result<()> {
        let mut success = false;
        if self.capabilities()?.request(Capability::PROXY).ok().is_ok() {
            // The transport happens to be connection to a remote opentitan session.  Pass
            // request to the remote server.
            if let Err(e) = self.proxy_ops()?.apply_pin_strapping(strapping_name) {
                match e.downcast_ref::<TransportError>() {
                    Some(TransportError::InvalidStrappingName(_)) => (),
                    _ => return Err(e),
                }
            } else {
                // Remote server recognized name of the strapping, based on its configuration.
                // Make a note of that, and do not report error even if local configuration does
                // not mention this trapping.
                success = true;
            }
        }
        if let Some(strapping_conf_map) = self.strapping_conf_map.get(strapping_name) {
            // Local configuration contains this strapping, make a note of that and do not report
            // error even if remote server did not recognize this strapping.
            success = true;
            self.apply_pin_configurations(strapping_conf_map)?;
        }
        if success {
            Ok(())
        } else {
            Err(TransportError::InvalidStrappingName(strapping_name.to_string()).into())
        }
    }

    /// Return the set of pins affected by the given strapping to their "default" (un-strapped)
    /// configuration, that is, to the level declared in the "pins" section of configuration
    /// files, outside of any "strappings" section.
    pub fn remove_pin_strapping(&self, strapping_name: &str) -> Result<()> {
        let mut success = false;
        if self.capabilities()?.request(Capability::PROXY).ok().is_ok() {
            // The transport happens to be connection to a remote opentitan session.  Pass
            // request to the remote server.
            if let Err(e) = self.proxy_ops()?.remove_pin_strapping(strapping_name) {
                match e.downcast_ref::<TransportError>() {
                    Some(TransportError::InvalidStrappingName(_)) => (),
                    _ => return Err(e),
                }
            } else {
                // Remote server recognized name of the strapping, based on its configuration.
                // Make a note of that, and do not report error even if local configuration does
                // not mention this trapping.
                success = true;
            }
        }
        if let Some(strapping_conf_map) = self.strapping_conf_map.get(strapping_name) {
            // Local configuration contains this strapping, make a note of that and do not report
            // error even if remote server did not recognize this strapping.
            success = true;
            for pin_name in strapping_conf_map.keys() {
                if let Some(default_pin_conf) = self.pin_conf_map.get(pin_name) {
                    self.apply_pin_configuration(pin_name, default_pin_conf)?;
                }
            }
        }
        if success {
            Ok(())
        } else {
            Err(TransportError::InvalidStrappingName(strapping_name.to_string()).into())
        }
    }

    pub fn reset_target(&self, reset_delay: Duration, clear_uart_rx: bool) -> Result<()> {
        log::info!("Asserting the reset signal");
        self.apply_pin_strapping("RESET")?;
        std::thread::sleep(reset_delay);
        if clear_uart_rx {
            log::info!("Clearing the UART RX buffer");
            self.uart("console")?.clear_rx_buffer()?;
        }
        log::info!("Deasserting the reset signal");
        self.remove_pin_strapping("RESET")?;
        std::thread::sleep(reset_delay);
        Ok(())
    }
}

/// Given an pin/uart/spi/i2c port name, if the name is a known alias, return the underlying
/// name/number, otherwise return the string as is.
fn map_name(map: &HashMap<String, String>, name: &str) -> String {
    let name = name.to_uppercase();
    match map.get(&name) {
        Some(v) => {
            if v.eq(&name) {
                name
            } else {
                map_name(map, v)
            }
        }
        None => name,
    }
}

/// Certain transports may want to declare that they do not support a particular pin and that it
/// should be ignored, even though its name is mentioned in e.g. generic strapping configurations.
/// (Absent any such declaration, it would result in an error to mention strappings of a pin that
/// is not in fact supported.)
struct NullPin {
    name: String,
    has_warned: Cell<bool>,
}

impl NullPin {
    fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
            has_warned: Cell::new(false),
        }
    }

    /// Emit a warning the first this pin is accessed.
    fn warn(&self) {
        if !self.has_warned.get() {
            log::warn!("Accessed NULL pin {}", self.name);
            self.has_warned.set(true);
        }
    }
}

impl GpioPin for NullPin {
    fn read(&self) -> Result<bool> {
        self.warn();
        Ok(false)
    }

    fn write(&self, _value: bool) -> Result<()> {
        self.warn();
        Ok(())
    }

    fn set_mode(&self, _mode: PinMode) -> Result<()> {
        self.warn();
        Ok(())
    }

    fn set_pull_mode(&self, _mode: PullMode) -> Result<()> {
        self.warn();
        Ok(())
    }
}
