import numpy as np
import tools.vinkelfart as vf
from tools.global_constants import R,g,del_t
from tools.ping_pong_constants import m,c

def find_radius(x_list,y_list, return_error = False): #finner radius til en ustentrert bane definert ved x_list,y_list
    x_list,y_list = origo_to_bot(x_list,y_list)

    r_list = []
    for i in range(len(x_list)):
        if abs(x_list[i]) > 0.2:
            y = (x_list[i] ** 2 - y_list[i] ** 2) / (2 * y_list[i])
            r_list.append(y_list[i] + y)
    deviation = np.std(np.array(r_list))
    mean = np.mean(np.array(r_list))
    print('mean_r : ',mean)

    if return_error == True:
        return mean, deviation
    else:
        return mean

def find_track_bot(x_list,y_list): #tar inn x og y posisjoner, returnerer (x,y) posisjonen til bunn av banen
    bot_y = min(y_list)
    bot_x = x_list[y_list.index(bot_y)]
    return bot_x,bot_y

def origo_to_bot(x_list,y_list):  #tar inn x og y posisjoner, returnerer listene justert slik at origo er i bunn av banen
    bot_x,bot_y = find_track_bot(x_list,y_list)
    adjusted_x_list = [x - bot_x for x in x_list]
    adjusted_y_list = [y - bot_y for y in y_list]
    return adjusted_x_list,adjusted_y_list

def origo_to_center(x_list,y_list):     #flytter origo til sentrum av sirkelen
    centered_x_list,y_list = origo_to_bot(x_list,y_list) #når origo er i bunn av sirkelen trenger ikke x_list justeres
    R = find_radius(x_list,y_list)

    centered_y_list = [y - R for y in y_list]
    return centered_x_list,centered_y_list

def adjust_t0(t_list): #justerer alle t-verdier slik at t_0 = 0
    t_0 = t_list[0]
    t_list = [t-t_0 for t in t_list]
    return t_list

def avg_list(tracks): #tracks er en liste med mange dataset, returnerer en liste hvor hvert element er snittet av alle datasettene
    lens = [len(i) for i in tracks] #lengden av hvert dataset

    n = len(tracks) #antall datasett
    min_len = min(lens) #lengden til det korteste datasettet

    avg = [0 for i in range(min_len)] #allokerer minne, for å spare kjøretid
    for i in range(min_len):
        avg[i] = sum([data[i]/n for data in tracks]) # regner ut gjennomsnittsverdier

    return avg

def dev_from_sircle(x_list,y_list): #finner ut hvor mye en bane avviker fra en perfekt sirkel ved gjennomsnittlig absolutt avvik

    R = find_radius(x_list,y_list)

    sircle_y = [-np.sqrt(R**2 - x**2) for x in x_list] #datapunker for en perfekt sirkel

    n = len(y_list)
    mean_abs_error = sum([(abs(y_list[i]-sircle_y[i]))/n for i in range(n)])

    return mean_abs_error

def check_ekstrema(list_part): #sjekker om en liste med tre verdier inneholder et ekstrema
    if abs(list_part[0])<abs(list_part[1]) and abs(list_part[1])>abs(list_part[2]):
        return True
    return False

def find_ekstrema(data_list): #returnerer en liste med tupler (ekstrema verdi, indeks)
    ekstrema_list=[]
    for i in range(1,len(data_list)-2):
        if check_ekstrema(data_list[i-1:i+2]):
            ekstrema_list.append((data_list[i],i))
    return ekstrema_list

def klipp_liste(data_list,max_y, svingninger = 0): #klipper data_list, fra første gang den har en verdi over max_y til det har gått svingniner antall svingninger
    ekstrema_list = find_ekstrema(data_list)
    print(ekstrema_list)
    for i in range(len(ekstrema_list)):
        val = ekstrema_list[i][0]
        if val <= max_y:
            start_index = ekstrema_list[i][1]
            if svingninger == 0:
                break
            else:
                try:
                    end_index = ekstrema_list[i+svingninger][1]
                    return start_index,end_index

                except IndexError:
                    print('Det finnes ikke så mange svingninger!')

    return start_index

def svingningsfinner(theta_list, time_list, dtheta=0): #returnerer tre matriser hvor hver rad er datapunktene i en svingning
    if type(dtheta) == int:
        dtheta = [0 for x in theta_list]
    sving_list = []
    tid_list = []
    indeks_list = []
    dtheta_list = []
    for i in range(1, len(theta_list)-1):
        if (theta_list[i-1] < theta_list[i]) and theta_list[i+1] < theta_list[i]:
            indeks_list.append(i)
    for i in range(0, len(indeks_list)-1):
        theta_sub = theta_list[indeks_list[i]: indeks_list[i+1]]
        time_sub = time_list[indeks_list[i]: indeks_list[i+1]]
        dtheta_sub = dtheta[indeks_list[i]:indeks_list[i+1]]
        dtheta_list.append(dtheta_sub)
        sving_list.append(theta_sub)
        tid_list.append(time_sub)

    if sum(dtheta) == 0:
        return sving_list, tid_list
    return sving_list,tid_list,dtheta_list

def theta_usikker(x,y): #regner ut theta og usikkerhet i theta fra x og y verdier
    x = np.array(x)
    y = np.array(y)
    theta = np.arctan(x/y)/np.pi

    del_theta = 0.001/(x**2 + y**2)

    return theta, del_theta

def usikker_luftmotstand(t_list,x,y): #regner ut luftmotstand med usikkerhet fra t, x og y lister
    theta_list, del_theta = theta_usikker(x, y)

    aks_list = vf.vinkelakselerasjon(t_list,theta_list)

    alfa, delta_w, delta_t = [np.array(x) for x in vf.vinkelakselerasjon(t_list, theta_list, usikker=True, glatt=30)]

    w, delta_theta, delta_t = vf.vinkelfart(t_list, theta_list, usikker=True, glatt=15)
    w, delta_theta, delta_t = [np.array(x) for x in [w, delta_theta, delta_t]]

    del_w = abs(w) * np.sqrt((2 * del_theta / delta_theta) ** 2 + (2 * del_t / delta_t) ** 2)
    del_alfa = abs(alfa) * np.sqrt((2 * del_w / delta_w) ** 2 + (2 * del_t / delta_t) ** 2)

    luft_list = []
    del_luft = []

    for i in range(len(theta_list)):
        l = m*g*np.sin(theta_list[i]) + R*aks_list[i]*m + c * m * R * aks_list[i]

        del_l = np.sqrt(((g*np.sin(theta_list[i]) + R*aks_list[i] + c * R * aks_list[i])*0.00005)**2 +
                        ((m * np.sin(theta_list[i]))*0.005)**2 +
                        ((aks_list[i]*m + c * m * aks_list[i])*0.073)**2 +
                        ((g*np.cos(theta_list[i])) * del_theta[i])**2 +
                        ((R*m + c*R)*del_alfa[i])**2)

        del_luft.append(del_l)
        luft_list.append(l)

    return luft_list, del_l, w