# -*- coding: utf-8 -*-
"""
A simple statistical analysis of the simulation
caculates average time as well as success precentage
"""

from __future__ import division
import math
import matplotlib.pyplot as plt
import numpy as np
import json
import scipy.stats as stats
import seaborn as sns
sns.set(style="darkgrid")


__authors__ = 'Noam Benelli'



def search_efficiency(dict_list):
    #calculate the ratio of time in which odor was detected/all of the flight time
    search_efficincy_list = []
    for j in range(len(dict_list)): #itirate through navigators
        
        diff_dict = dict_list[j]
        num_it = len(diff_dict)
        Last_dt_odor = False
        T_odor = 0
        T_no_odor = 0

        diff_list = diff_dict["diff_list{0}".format(0)]
        if diff_list[-1][-1]:
            for i in range(len(diff_list)): #itirate within list 
                odor = diff_list[i][3] #odor found or odor lost
                if odor == None and Last_dt_odor :
                    T_odor += 1
                elif odor =='odor found':
                    T_odor += 1
                    Last_dt_odor = True
                elif odor == 'odor lost':
                    Last_dt_odor = False

            search_eff = T_odor/len(diff_dict["diff_list{0}".format(0)])
            #print search_eff
            search_efficincy_list.append(search_eff)
    if search_efficincy_list != []:
        average = math.fsum(search_efficincy_list) / len(search_efficincy_list)
    else:
        average = 0
    return average

def times_print(dict_list):
    #calculate the average time of flight for successful flights
    times_list = []
    for diff_dict in dict_list:
        diff_list = diff_dict["diff_list{0}".format(0)]
        if diff_list[-1][-1]:
            finishing_time = diff_list[-1][2]
            times_list.append(finishing_time)
    print (times_list)

def average_time(dict_list):
    #calculate the average time of flight for successful flights
    times_list = []
    for diff_dict in dict_list:
        diff_list = diff_dict["diff_list{0}".format(0)]
        if diff_list[-1][-1]:
            finishing_time = diff_list[-1][2]
            times_list.append(finishing_time)

    #print times_list
    if len(times_list) != 0:
        average = math.fsum(times_list) / float(len(times_list))
    else:
        average = 0
    return average
def average_time_relative(dict_list):
    """
    let us define the optimal time as the time it would have taken the navigator
    to reach it's final position if it were to move in straight line
    the relatve navigation time is define as measured time/optimal time
    this function calculates the relative navigation time for each successful navigator
    and returns an average
    """
    ##(x,y,T,odor,gamma,state,success)
    def first_movement(diff_list):
        for i in range(len(diff_list)):
            if diff_list[i][5] != 'wait':
                #print 'state = '+ diff_list[i][5]
                return i

    def calc_speed(diff_list):
        i = first_movement(diff_list)
        x1 = diff_list[i][0]
        y1 = diff_list[i][1]
        x2 = diff_list[i+1][0]
        y2 = diff_list[i+1][1]
        dist = distance(x1,y1,x2,y2)
        dt = diff_list[i+1][2] - diff_list[i][2]
        speed = dist/dt
        return speed

    def optimal_time(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        opt_dist = distance(x1,y1,x2,y2)

        speed = calc_speed(diff_list)
        optimal_time = opt_dist/speed

        return optimal_time
        
    def distance(x1,y1,x2,y2):
       x = x2-x1
       y = y2-y1
       return (x**2+y**2)**0.5

    def optimal_distance(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        return distance(x1,y1,x2,y2)
    
    
    def traveled_distance(diff_list):
        dist_sum = 0.0
        for i in range(1,len(diff_list)):
            if diff_list[i][-2]:
                x1 = diff_list[i-1][0]
                y1 = diff_list[i-1][1]
                x2 = diff_list[i][0]
                y2 = diff_list[i][1]
                dist_sum += distance(x1,y1,x2,y2)
        return dist_sum

    def time_elasped(diff_list):
        i = first_movement(diff_list)
        time_ela = diff_list[i][2]-diff_list[-1][2]
        return time_ela
                
    times_list = []
    for diff_dict in dict_list:
        for key in diff_dict:
            diff_list = diff_dict[key]
            if diff_list[-1][-1]:
                """
                optimal = optimal_distance(diff_list)
                traveled = traveled_distance(diff_list)
                #print (optimal,traveled)
                relative_time = traveled/optimal
                """
                elasped = time_elasped(diff_list)
                optimal = optimal_time(diff_list)
                relative_time = elasped/optimal
                times_list.append(math.fabs(relative_time))

    #print times_list
    if len(times_list) != 0:
        average = math.fsum(times_list) / float(len(times_list))
    else:
        average = 0
    return average
def time_standrd_error(dict_list):
    ##(x,y,T,odor,gamma,state,success)
    def first_movement(diff_list):
        for i in range(len(diff_list)):
            if diff_list[i][5] != 'wait':
                #print 'state = '+ diff_list[i][5]
                return i

    def calc_speed(diff_list):
        i = first_movement(diff_list)
        x1 = diff_list[i][0]
        y1 = diff_list[i][1]
        x2 = diff_list[i+1][0]
        y2 = diff_list[i+1][1]
        dist = distance(x1,y1,x2,y2)
        dt = diff_list[i+1][2] - diff_list[i][2]
        speed = dist/dt
        return speed

    def optimal_time(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        opt_dist = distance(x1,y1,x2,y2)

        speed = calc_speed(diff_list)
        optimal_time = opt_dist/speed

        return optimal_time
        
    def distance(x1,y1,x2,y2):
       x = x2-x1
       y = y2-y1
       return (x**2+y**2)**0.5

    def optimal_distance(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        return distance(x1,y1,x2,y2)
    
    
    def traveled_distance(diff_list):
        dist_sum = 0.0
        for i in range(1,len(diff_list)):
            if diff_list[i][-2]:
                x1 = diff_list[i-1][0]
                y1 = diff_list[i-1][1]
                x2 = diff_list[i][0]
                y2 = diff_list[i][1]
                dist_sum += distance(x1,y1,x2,y2)
        return dist_sum

    def time_elasped(diff_list):
        i = first_movement(diff_list)
        time_ela = diff_list[i][2]-diff_list[-1][2]
        return time_ela
                
    times_list = []
    for diff_dict in dict_list:
        for key in diff_dict:
            diff_list = diff_dict[key]
            if diff_list[-1][-1]:
                elasped = time_elasped(diff_list)
                optimal = optimal_time(diff_list)
                relative_time = elasped/optimal
                times_list.append(math.fabs(relative_time))

    #print times_list
    if len(times_list) != 0:
        standard_error = stats.sem(times_list,0,1,'raise')
    else:
        standard_error = 0
    return standard_error

def succuss_precentage(dict_list):
    winners = 0.
    for diff_dict in dict_list:
        diff_list = diff_dict["diff_list{0}".format(0)]
        #print diff_list[-1]
        if diff_list[-1][-1]:
            winners += 1
    
    dn =count_duds(dict_list)
    succuss_precentage = winners / (len(dict_list)-dn) *100      
    return succuss_precentage


#main function
def calc_stats(diff_dict):

    succ_prec = succuss_precentage(diff_dict)

    avg_time = average_time_relative(diff_dict)
    
    standard_error = time_standrd_error(diff_dict)

    return [succ_prec ,avg_time,standard_error]



def optimal_distance_range(dict_list):
    def first_movement(diff_list):
        for i in range(len(diff_list)):
            if diff_list[i][5] != 'wait':
                #print 'state = '+ diff_list[i][5]
                return i
    def calc_speed(diff_list):
        i = first_movement(diff_list)
        x1 = diff_list[i][0]
        y1 = diff_list[i][1]
        x2 = diff_list[i+1][0]
        y2 = diff_list[i+1][1]
        dist = distance(x1,y1,x2,y2)
        dt = diff_list[i+1][2] - diff_list[i][2]
        speed = dist/dt
        return speed
    
    def optimal_time(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        opt_dist = distance(x1,y1,x2,y2)

        speed = calc_speed(diff_list)
        optimal_time = opt_dist/speed
        return optimal_time
        
    def distance(x1,y1,x2,y2):
       x = x2-x1
       y = y2-y1
       return (x**2+y**2)**0.5

    def optimal_distance(diff_list):
        x1 = diff_list[0][0]
        y1 = diff_list[0][1]
        x2 = diff_list[-1][0]
        y2 = diff_list[-1][1]
        return distance(x1,y1,x2,y2)
    
    optimal_times_list = []
    for diff_dict in dict_list:
        for key in diff_dict:
            diff_list = diff_dict[key]
            if diff_list[-1][-1]:
                optimal = optimal_time(diff_list)
                optimal_times_list.append(optimal)

    print (max(optimal_times_list))
    print (min(optimal_times_list))

def multi_splice(list_dict,n):
    length =len(list_dict)
    if length%n != 0:
        raise Exception('Number of navigators could not be devided into %0.1i' %n)
    spliced_lists = []
    lenn = int(length/n)
    for i in range(n):
        if i ==0 :
            new_list = list_dict[:lenn]
        elif i == n-1:
            new_list = list_dict[i*lenn:]
        else:
            new_list = list_dict[lenn*i:lenn*(i+1)]
        spliced_lists.append(new_list)
    return spliced_lists

def get_data(file_name,num):
    with open(file_name) as data_file1:  
        dict_list1 = json.load(data_file1)

    spliced_lists = multi_splice(dict_list1,num)
    data_list = [calc_stats(dict_list) for dict_list in spliced_lists]

    return data_list
    
def count_duds(dict_list):
    #the number of navigators that had not moved for the entire simulation
    #for each navigator in the dictionary it check the last entry in it's trajectory list
    #if it's state is 'waiting' at the last time step, we know it hasn't navigated at all.
    dud_number = 0
    for nav_dict in dict_list:
        for key in nav_dict:
            #(x,y,T,odor,gamma,state,success)
            if nav_dict[key][-1][-2] == 'wait':
                #print('dud found')
                dud_number +=1
            else:
                pass
                #print(nav_dict[key][-1][-2])
    return dud_number
                
    
def times_print(dict_list):
    #calculate the average time of flight for successful flights
    times_list = []
    for diff_dict in dict_list:
        diff_list = diff_dict["diff_list{0}".format(0)]
        if diff_list[-1][-1]:
            finishing_time = diff_list[-1][2]
            times_list.append(finishing_time)
    print (times_list)
    
if __name__ == "__main__":

    
    """
    for i in range(1):
        loop = str(i)
        with open('data3.json') as data_file1:  
            dict_list1 = json.load(data_file1)
        #optimal_distance_range(dict_list1)
        print len(dict_list1)
        times_print(dict_list1)
    """
        