//! Implements many effects one can use to modify signals.
//!
//! Effects are structures that wrap around [`Signals`](crate::prelude::Signal)
//! and modify the samples they produce, be they envelope or audio data.
//!
//! The module file implements the most basic structures for transforming a
//! signal, including [`MapSgn`], [`MutSgn`], and [`ModSgn`].

pub mod adsr;
pub mod distortion;
pub mod freq;
pub mod mix;
pub mod pan;
pub mod trailing;
pub mod vol;

use std::marker::PhantomData;

use crate::prelude::*;

/// Converts a function into one applied pointwise to the entries of a
/// [`Sample`].
#[derive(Clone, Debug, Default)]
pub struct Pw<S: Sample, F: Map<Input = f64, Output = f64>> {
    /// The function to apply.
    pub func: F,

    /// Dummy value.
    phantom: PhantomData<S>,
}

impl<S: Sample, F: Map<Input = f64, Output = f64>> Pw<S, F> {
    /// Initializes a new [`Pw`] function.
    pub const fn new(func: F) -> Self {
        Self {
            func,
            phantom: PhantomData,
        }
    }
}

impl<S: Sample, F: Map<Input = f64, Output = f64>> Map for Pw<S, F> {
    type Input = S;
    type Output = S;

    fn eval(&self, x: S) -> S {
        x.map(|y| self.func.eval(y))
    }
}

/// Maps a signal to another via a specified map.
///
/// This map should send in most cases send the zero sample to itself. That
/// ensures that there is no DC offset if the signal stops.
///
/// Note that the map here takes in a sample and outputs a sample. If you
/// instead want to map the floating point values of the sample pointwise, wrap
/// the function in [`Pw`].
#[derive(Clone, Copy, Debug, Default)]
pub struct MapSgn<S: Signal, F: Map<Input = S::Sample>>
where
    F::Output: Sample,
{
    /// The signal being mapped.
    sgn: S,

    /// The map being applied.
    map: F,
}

impl<S: Signal, F: Map<Input = S::Sample>> MapSgn<S, F>
where
    F::Output: Sample,
{
    /// Initializes a generic [`MapSgn`].
    pub const fn new(sgn: S, map: F) -> Self {
        Self { sgn, map }
    }

    /// Initializes a [`MapSgn`] using the default constructor for the function.
    pub fn new_default(sgn: S) -> Self
    where
        F: Default,
    {
        Self::new(sgn, F::default())
    }

    /// Returns a reference to the original signal.
    pub const fn sgn(&self) -> &S {
        &self.sgn
    }

    /// Returns a mutable reference to the original signal.
    pub fn sgn_mut(&mut self) -> &mut S {
        &mut self.sgn
    }

    /// Returns a reference to the map modifying the signal.
    pub const fn map(&self) -> &F {
        &self.map
    }

    /// Returns a mutable reference to the map modifying the signal.
    pub fn map_mut(&mut self) -> &mut F {
        &mut self.map
    }
}

impl<S: Signal, F: Map<Input = S::Sample>> Signal for MapSgn<S, F>
where
    F::Output: Sample,
{
    type Sample = F::Output;

    fn get(&self) -> F::Output {
        self.map().eval(self.sgn.get())
    }

    fn advance(&mut self) {
        self.sgn_mut().advance();
    }

    fn retrigger(&mut self) {
        self.sgn_mut().retrigger();
    }
}

impl<S: Frequency, F: Map<Input = S::Sample>> Frequency for MapSgn<S, F>
where
    F::Output: Sample,
{
    fn freq(&self) -> crate::Freq {
        self.sgn().freq()
    }

    fn freq_mut(&mut self) -> &mut crate::Freq {
        self.sgn_mut().freq_mut()
    }
}

impl<S: Base, F: Map<Input = S::Sample>> Base for MapSgn<S, F>
where
    F::Output: Sample,
{
    type Base = S::Base;

    fn base(&self) -> &S::Base {
        self.sgn().base()
    }

    fn base_mut(&mut self) -> &mut S::Base {
        self.sgn_mut().base_mut()
    }
}

impl<S: Stop, F: Map<Input = S::Sample>> Stop for MapSgn<S, F>
where
    F::Output: Sample,
{
    fn stop(&mut self) {
        self.sgn_mut().stop();
    }
}

impl<S: Done, F: Map<Input = S::Sample>> Done for MapSgn<S, F>
where
    F::Output: Sample,
{
    fn is_done(&self) -> bool {
        self.sgn().is_done()
    }
}

impl<S: Panic, F: Map<Input = S::Sample>> Panic for MapSgn<S, F>
where
    F::Output: Sample,
{
    fn panic(&mut self) {
        self.sgn_mut().panic();
    }
}

/// A [`MapSgn`] taking in a [`Pw`] function.
pub type PwMapSgn<S, F> = MapSgn<S, Pw<<S as Signal>::Sample, F>>;

impl<S: Signal, F: Map<Input = f64, Output = f64>> PwMapSgn<S, F> {
    /// Initializes a [`MapSgn`] from a pointwise function.
    pub const fn new_pw(sgn: S, map: F) -> Self {
        Self::new(sgn, Pw::new(map))
    }

    /// Returns a reference to the pointwise map modifying the signal.
    pub const fn map_pw(&self) -> &F {
        &self.map().func
    }

    /// Returns a mutable reference to the pointwise map modifying the signal.
    pub fn map_pw_mut(&mut self) -> &mut F {
        &mut self.map_mut().func
    }
}

/// Modifies a signal according to a given envelope.
///
/// This signal stops whenever the original signal does. If you instead want a
/// signal that stops when the envelope does, use [`ModSgn`].
#[derive(Clone, Debug)]
pub struct MutSgn<S: Signal, E: Signal<Sample = Env>, F: Mut<S, f64>> {
    /// The signal to modify.
    sgn: S,

    /// The envelope modifying the signal.
    env: E,

    /// The function to modify the signal.
    func: F,
}

impl<S: Signal, E: Signal<Sample = Env>, F: Mut<S, f64>> MutSgn<S, E, F> {
    /// Initializes a new [`MutSgn`].
    pub fn new(mut sgn: S, env: E, mut func: F) -> Self {
        func.modify(&mut sgn, env.get().0);
        Self { sgn, env, func }
    }

    /// Returns a reference to the original signal.
    pub const fn sgn(&self) -> &S {
        &self.sgn
    }

    /// Returns a mutable reference to the original signal.
    pub fn sgn_mut(&mut self) -> &mut S {
        &mut self.sgn
    }

    /// Returns a reference to the envelope controlling the signal.
    pub const fn env(&self) -> &E {
        &self.env
    }

    /// Returns a mutable reference to the envelope controlling the signal.
    pub fn env_mut(&mut self) -> &mut E {
        &mut self.env
    }

    /// Returns a reference to the function modifying the signal.
    pub const fn func(&self) -> &F {
        &self.func
    }

    /// Returns a mutable reference to the function modifying the signal.
    pub fn func_mut(&mut self) -> &mut F {
        &mut self.func
    }
}

impl<S: Signal, E: Signal<Sample = Env>, F: Mut<S, f64>> Signal for MutSgn<S, E, F> {
    type Sample = S::Sample;

    fn get(&self) -> S::Sample {
        self.sgn().get()
    }

    fn advance(&mut self) {
        self.sgn.advance();
        self.func.modify(&mut self.sgn, self.env.next().0);
    }

    fn retrigger(&mut self) {
        self.sgn_mut().retrigger();
        self.env_mut().retrigger();
    }
}

impl<S: Frequency, E: Signal<Sample = Env>, F: Mut<S, f64>> Frequency for MutSgn<S, E, F> {
    fn freq(&self) -> Freq {
        self.sgn().freq()
    }

    fn freq_mut(&mut self) -> &mut Freq {
        self.sgn_mut().freq_mut()
    }
}

impl<S: Base, E: Signal<Sample = Env>, F: Mut<S, f64>> Base for MutSgn<S, E, F> {
    type Base = S::Base;

    fn base(&self) -> &S::Base {
        self.sgn().base()
    }

    fn base_mut(&mut self) -> &mut S::Base {
        self.sgn_mut().base_mut()
    }
}

impl<S: Done, E: Signal<Sample = Env>, F: Mut<S, f64>> Done for MutSgn<S, E, F> {
    fn is_done(&self) -> bool {
        self.sgn().is_done()
    }
}

impl<S: Stop, E: Signal<Sample = Env>, F: Mut<S, f64>> Stop for MutSgn<S, E, F> {
    fn stop(&mut self) {
        self.sgn_mut().stop();
    }
}

impl<S: Panic, E: Signal<Sample = Env>, F: Mut<S, f64>> Panic for MutSgn<S, E, F> {
    fn panic(&mut self) {
        self.sgn_mut().panic();
    }
}

/// Modifies a signal according to a given envelope.
///
/// This signal stops whenever the envelope does. If you instead want a signal
/// that stops when the signal does, use [`MutSgn`].
#[derive(Clone, Debug)]
pub struct ModSgn<S: Signal, E: Stop<Sample = Env>, F: Mut<S, f64>> {
    /// Inner data.
    inner: MutSgn<S, E, F>,
}

impl<S: Signal, E: Stop<Sample = Env>, F: Mut<S, f64>> ModSgn<S, E, F> {
    /// Initializes a new [`ModSgn`].
    pub fn new(sgn: S, env: E, func: F) -> Self {
        Self {
            inner: MutSgn::new(sgn, env, func),
        }
    }

    /// Returns a reference to the original signal.
    pub const fn sgn(&self) -> &S {
        self.inner.sgn()
    }

    /// Returns a mutable reference to the original signal.
    pub fn sgn_mut(&mut self) -> &mut S {
        self.inner.sgn_mut()
    }

    /// Returns a reference to the envelope controlling the signal.
    pub const fn env(&self) -> &E {
        self.inner.env()
    }

    /// Returns a mutable reference to the envelope controlling the signal.
    pub fn env_mut(&mut self) -> &mut E {
        self.inner.env_mut()
    }

    /// Returns a reference to the function modifying the signal.
    pub const fn func(&self) -> &F {
        self.inner.func()
    }

    /// Returns a mutable reference to the function modifying the signal.
    pub fn func_mut(&mut self) -> &mut F {
        self.inner.func_mut()
    }
}

impl<S: Signal, E: Stop<Sample = Env>, F: Mut<S, f64>> Signal for ModSgn<S, E, F> {
    type Sample = S::Sample;

    fn get(&self) -> S::Sample {
        self.inner.get()
    }

    fn advance(&mut self) {
        self.inner.advance();
    }

    fn retrigger(&mut self) {
        self.inner.retrigger();
    }
}

impl<S: Frequency, E: Stop<Sample = Env>, F: Mut<S, f64>> Frequency for ModSgn<S, E, F> {
    fn freq(&self) -> Freq {
        self.inner.freq()
    }

    fn freq_mut(&mut self) -> &mut Freq {
        self.inner.freq_mut()
    }
}

impl<S: Base, E: Stop<Sample = Env>, F: Mut<S, f64>> Base for ModSgn<S, E, F> {
    type Base = S::Base;

    fn base(&self) -> &S::Base {
        self.inner.base()
    }

    fn base_mut(&mut self) -> &mut S::Base {
        self.inner.base_mut()
    }
}

impl<S: Signal, E: Stop<Sample = Env> + Done, F: Mut<S, f64>> Done for ModSgn<S, E, F> {
    fn is_done(&self) -> bool {
        self.env().is_done()
    }
}

impl<S: Signal, E: Stop<Sample = Env>, F: Mut<S, f64>> Stop for ModSgn<S, E, F> {
    fn stop(&mut self) {
        self.env_mut().stop();
    }
}

impl<S: Signal, E: Stop<Sample = Env> + Panic, F: Mut<S, f64>> Panic for ModSgn<S, E, F> {
    fn panic(&mut self) {
        self.env_mut().panic();
    }
}
