# -*- coding: utf-8 -*-
"""
Created on Fri Jul 21 11:53:44 2017

@author: Philipp
"""

import pywt
import numpy as np
from numpy import array
import pandas as panda
from scipy.signal import argrelextrema

def threshold(values, gain, freq):
    """
    freq = round(60 * freq / 50)
    
    threshold = panda.DataFrame(values)
    thresholdMin = threshold.rolling(window=freq,center=False).min()
    thresholdMax = threshold.rolling(window=freq,center=False).max()
    
    threshold = thresholdMin + gain * (thresholdMax - thresholdMin)[0]
    where_are_NaNs = np.isnan(threshold)
    threshold[where_are_NaNs] = np.median(values) * 50 # arbitrary number 
    
    low_values_indices = values**2 < threshold**2  # Where values are low
    values[low_values_indices] = 0  # All low values set to 0
"""
    return values

def running_sum(s, n):
    return [sum(s[lo:lo + n]) for lo in range(len(s) - n + 1)]


def checkEs(values, method="count"):
    
    def f1(x):
        return 6-16/(2-x)
    
    def f2(x):
        return 1-(2+3*x)/(6+x)
    
    def f3(x):
        return 4-8/(2-x)
    
    def f4(x):
        return -2+8/(4+x)
    
    df1 = ((f1(values)[:-1]-values[1:])**2)
    df2 = ((f2(values)[:-1]-values[1:])**2)
    df3 = ((f3(values)[:-1]-values[1:])**2)
    df4 = ((f4(values)[:-1]-values[1:])**2)
    dfb = (values[:-1] + values[1:])**2
   
    # Simple Extrasystole (interpolated)
    simpleEs = np.all([values[0:-2] < .2, 
                   (df1[0:-1] + df2[1:]) < .15], 0)

    
    nSimpleEs = np.all([np.abs(values[:-3])<.2, 
                values[1:-2] < .2, 
                (df1[1:-1] + df2[2:]) < .15], 0)
    
    
    nDoubleEs = np.all([np.abs(values[0:-5])<.2, 
                values[1:-4] < .2,
                (df1[1:-3] + dfb[2:-2] + dfb[3:-1] + df2[4:]) < .15], 0)
    
    
    nTripleEs = np.all([np.abs(values[0:-7])<.2, 
                values[1:-6] < .2,
                (df1[1:-5] + dfb[2:-4] + dfb[3:-3] + dfb[4:-2] + dfb[5:-1] + df2[6:]) < .15], 0)
    

    # Compensatory Pause
    
    compedEs = np.all([np.abs(values[:-3])<.2, 
                values[1:-2] < -.2, 
                values[2:-1] >.2, 
                (df3[1:-1] + df4[2:]) < .15], 0)
    
    
    cDoubleEs = np.all([np.abs(values[0:-5])<.2, 
                values[1:-4] < .2,
                (df3[1:-3] + dfb[2:-2] + dfb[3:-1] + df4[4:]) < .15], 0)
    
    
    cTripleEs = np.all([np.abs(values[0:-7])<.2, 
                values[1:-6] < .2,
                (df3[1:-5] + dfb[2:-4] + dfb[3:-3] + dfb[4:-2] + dfb[5:-1] + df4[6:]) < .15], 0)
    
    
    if method == "count":
        simpleEs = len(simpleEs[simpleEs == True])
        nSimpleEs = len(nSimpleEs[nSimpleEs == True])
        nDoubleEs = len(nDoubleEs[nDoubleEs == True])
        nTripleEs = len(nTripleEs[nTripleEs == True])
        compedEs = len(compedEs[compedEs == True])
        cDoubleEs = len(cDoubleEs[cDoubleEs == True])
        cTripleEs = len(cTripleEs[cTripleEs == True])  
        
        count = nSimpleEs + 2*nDoubleEs + 3*nTripleEs + compedEs + 2*cDoubleEs + 3*cTripleEs
    
        return [simpleEs, simpleEs-nSimpleEs, nDoubleEs, nTripleEs, compedEs, cDoubleEs, cTripleEs, count]
    else:
        es = np.where(nSimpleEs == True)[0]
        for e in es:    
            values = np.delete(values, range(e+1, e+3))
            
        es = np.where(nDoubleEs == True)[0]
        for e in es:    
            values = np.delete(values, range(e+1, e+6))
            
        return values
    

#%% gets maximum values from values
def getMax(values):
    # why this windowsize?
    x_max = argrelextrema(values, np.greater,0,100)[0]
    y_max = [values[i] for i in x_max]
    x_max = np.array(x_max, dtype=float)
    x_max = [i-10 for i in x_max]
    y_max = [.9 for i in y_max]

    return [list(a) for a in zip(x_max, y_max)]

def getBPM(values):
    # 150 instead of 300?
    # set value high enough to have at least one beat in it
    x_max = argrelextrema(values, np.greater,0,round(150*0.5))[0]
    
    
    
    l = len(x_max)
    timing = []
    for index, x in enumerate(x_max):
        if index+1 < l:
            timing.append(x_max[index+1]-x_max[index])
            
    if(len(timing)>0):        
        return sum(timing) / float(len(timing))
    else:
        return 50
    #return (1/(sum(timing) / float(len(timing))/300)*60)
    
def thresholdMaxima(values, gain, freq):
    
    freq = round(60 * freq / 50)
    threshold = panda.DataFrame(values)
    thresholdMin = threshold.rolling(window=freq,center=False).min()
    thresholdMax = threshold.rolling(window=freq,center=False).max()

    threshold = thresholdMin + gain * (thresholdMax - thresholdMin)
    
    where_are_NaNs = np.isnan(threshold)
    # ignore starting points    
    threshold[where_are_NaNs] = 5

    # threshold every point that doesnt exceed the min threshold
    for i,x in enumerate(values):
        if values[i]**2 < threshold[0][i]**2:
            values[i] = 0
    # Plot if needed
    """
    import matplotlib.pyplot as plt
    plt.plot(threshold[:])
    plt.plot(values[:])
    plt.show()
    """

    return values
    
def cleanUp(values):
    db1 = pywt.Wavelet('db4')
    cA8, cD8, cD7, cD6, cD5, cD4,cD3, cD2, cD1 = pywt.wavedec(values, db1, level=8)
    
    #bandpass filter, the array is hacky but it fails without :/
    
    # threshold is currently not used
    t = 50
    freq = 100
    
    cA8 = array([0*x for x in cA8])
    cA8 = threshold(cA8, t, freq);
    
    cD8 = array([0*x for x in cD8])
    cD8 = threshold(cD8, t, freq);
    
    cD7 = array([.5*x for x in cD7])
    cD7 = threshold(cD7, t, freq);
    
    cD6 = array([1*x for x in cD6])
    cD6 = threshold(cD6, t, freq);
    
    cD5 = array([1*x for x in cD5])
    cD5 = threshold(cD5, t, freq);
    
    cD4 = array([.5*x for x in cD4])
    cD4 = threshold(cD4, t, freq);
    
    cD3 = array([0*x for x in cD3])
    cD3 = threshold(cD3, t, freq)
    
    cD2 = array([0*x for x in cD2])
    cD2 = threshold(cD2, t, freq);
    
    cD1 = array([0*x for x in cD1])
    cD1 = threshold(cD1, t, freq);

    
    #putting it together again
    values_clean = pywt.waverec([cA8, cD8, cD7, cD6, cD5, cD4, cD3, cD2, cD1], db1)
    return values_clean
    
def findR(values):
    win = np.array(values)
    rr = int(getBPM(win))
    
    win = thresholdMaxima(win,.2, rr)
    
    win_window_size = 10
    win = panda.DataFrame(win)
    win = win.rolling(win_window_size * 2, win_type='triang').sum().values
    
    where_are_NaNs = np.isnan(win)
    win[where_are_NaNs] = 0
    
    timingthreshold = round(0.228*300+0.154*rr*0.85) 
    x_max = argrelextrema(win, np.greater,0,timingthreshold)[0]
    x_max = [x-win_window_size for x in x_max]
    
    return x_max