use num_traits::{Float, FromPrimitive, One, Zero};

use crate::preprocessing::smooth::lib::{ema, median_filter, rma, sma};

/// Ema
pub trait Ema<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn ema_smooth(&self, window_size: usize) -> Result<Vec<T>, String>;
}

impl<T> Ema<T> for [T] where 
    T: Float + FromPrimitive + Zero + Clone + One
{
    fn ema_smooth(&self, window_size: usize) -> Result<Vec<T>, String> {
        ema(self, window_size)
    }
}

impl<T> Ema<T> for Vec<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn ema_smooth(&self, window_size: usize) -> Result<Vec<T>, String> {
        self.as_slice().ema_smooth(window_size)
    }
}

/// Rma
pub trait Rma<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn rma_smooth(&self, window_size: usize) -> Result<Vec<T>, String>;
}

impl<T> Rma<T> for [T] where 
    T: Float + FromPrimitive + Zero + Clone + One
{
    fn rma_smooth(&self, window_size: usize) -> Result<Vec<T>, String> {
        rma(self, window_size)
    }
}

impl<T> Rma<T> for Vec<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn rma_smooth(&self, window_size: usize) -> Result<Vec<T>, String> {
        self.as_slice().rma_smooth(window_size)
    }
}

/// Sma
pub trait Sma<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn sma_smooth(&mut self, window_size: usize) -> Result<(), String>;
}

impl<T> Sma<T> for [T] where 
    T: Float + FromPrimitive + Zero + Clone + One
{
    fn sma_smooth(&mut self, window_size: usize) -> Result<(), String> {
        sma(self, window_size)
    }
}

impl<T> Sma<T> for Vec<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn sma_smooth(&mut self, window_size: usize) -> Result<(), String> {
        self.as_mut_slice().sma_smooth(window_size)
    }
}

/// Median
pub trait MedianSmooth<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn median_smooth(&self, window_size: usize, precision: f64) -> Result<Vec<T>, String>;
}

impl<T> MedianSmooth<T> for [T] where 
    T: Float + FromPrimitive + Zero + Clone + One
{
    fn median_smooth(&self, window_size: usize, precision: f64) -> Result<Vec<T>, String> {
        median_filter(self,window_size, precision)
    }
}

impl<T> MedianSmooth<T> for Vec<T> where 
    T: Float + FromPrimitive + Zero + Clone + One,
{
    fn median_smooth(&self, window_size: usize, precision: f64) -> Result<Vec<T>, String> {
        self.as_slice().median_smooth(window_size, precision)
    }
}

