from MP_records import records
import random as rd
import time
import csv
import codecs

def polynomial_hash(word):
    p=11111
    m=(10**9)+9
    hashh=0
    for i in range(len(word)):
        hashh+=ord(word[i])*(p**i)
    hashh=hashh%m
    return hashh

def hash_to_index(hashh,length):
    while hashh>length:
        hashh=hashh%(length)
    return hashh

def ll_insert(table,name,phone,index):
    if table[index]==None:
        entry={"name":name,"phone":phone,"next":None}
        table[index]=entry
        return table
    else:
        entry={"name":name,"phone":phone,"next":None}
        if table[index]["phone"]==phone:
            table[index]["name"]=name
            return table
        if table[index]["next"]==None:
            table[index]["next"]=entry
            return table
        else:
            nexxt=table[index]["next"]
            if nexxt["phone"]==phone:
                nexxt["name"]=name
                return table
            while nexxt["next"]!=None:
                nexxt=nexxt["next"]
                if nexxt["phone"]==phone:
                    nexxt["name"]=name
                    return table
            nexxt["next"]=entry
            return table

def ht_insert(table,name,phone):
    index=hash_to_index(polynomial_hash(name), len(table))
    ll_insert(table,name,phone,index)
    return table

def ht_find(table, name):
    index=hash_to_index(polynomial_hash(name), len(table))
    if table[index]!=None:
        if table[index]["name"]==name:
            return table[index]["phone"]
        elif table[index]["next"]!=None:
            if table[index]["next"]["name"]==name:
                return table[index]["next"]["phone"]
            else:
                nexxt=table[index]["next"]
                while nexxt["next"]!=None:
                    nexxt=nexxt["next"]
                    if nexxt["name"]==name:
                        return nexxt["phone"]
    return None

def ht_delete(table,name):
    index=hash_to_index(polynomial_hash(name), len(table))
    if len(table)>0:
        if table[index]["name"]==name:
            if table[index]["next"]!=None:
                table[index]=table[index]["next"]
                return table
            else:
                table[index]=None
                return table
        elif table[index]["next"]!=None:
            if table[index]["next"]["name"]==name:
                if table[index]["next"]["next"]!=None:
                    table[index]["next"]=table[index]["next"]["next"]
                    return table
                else:
                    table[index]["next"]=None
                    return table
            elif table[index]["next"]["next"]!=None:
                nexxt1=table[index]["next"]
                nexxt2=nexxt1["next"]
                if nexxt2["name"]==name:
                    if nexxt2["next"]!=None:
                        nexxt1["next"]=nexxt2["next"]
                        return table
                    else:
                        nexxt1["next"]=None
                        return table
                while nexxt2["next"]!=None:
                    nexxt1=nexxt2
                    nexxt2=nexxt1["next"]
                    if nexxt2["name"]==name:
                        if nexxt2["next"]!=None:
                            nexxt1["next"]=nexxt2["next"]
                            return table
                        else:
                            nexxt1["next"]=None
                            return table

def bad_sort(names,phones):
    names1=[]
    phones1=[]
    while len(names)>0:
        min_=names[0].encode()
        ph=phones[0]
        for i in range(len(names)):
            nm=names[i].encode()
            if nm<min_:
                min_=nm
                ph=phones[i]
        #print(min_.decode()," - ",ph)
        names1.append(min_.decode())
        phones1.append(ph)
        names.remove(min_.decode())
        phones.remove(ph)
    #print(names1,"\n",phones1)
    return names1, phones1

def Shell(names,phones):
    N = len(names)
    n = N // 2
    while n>0:
        for i in range (0,N-n):
            j=i
            while j+n<N:
                if (names[j].encode())>(names[j+n].encode()):
                    t=names[j]
                    t1=phones[j]
                    names[j]=names[j+n]
                    phones[j]=phones[j+n]
                    names[j+n]=t
                    phones[j+n]=t1
                    j=i
                else:
                    j+=n
        n=n//2
    return names,phones

def ht_listall(table):
    names=[]
    phones=[]
    pointer=0
    while pointer<len(table):
        if table[pointer]!=None:
            names.append(table[pointer]["name"])
            phones.append(table[pointer]["phone"])
            if table[pointer]["next"]!=None:
                names.append(table[pointer]["next"]["name"])
                phones.append(table[pointer]["next"]["phone"])
                nexxt=table[pointer]["next"]
                while nexxt["next"]!=None:
                    nexxt=nexxt["next"]
                    names.append(nexxt["name"])
                    phones.append(nexxt["phone"])
        pointer+=1
    names1, phones1 = bad_sort(names, phones)
    #names1, phones1 = Shell(names, phones)
    for i in range(len(names1)):
        print(names1[i]," - ",phones1[i],end='')
        if i%4==0:
            print("\n")
        else:
            print(", ",end='')
    print("\n")
    
def test():
    table=[]
    for i in range(8):
        table.append(None)
    ht_insert(table, "Zyky", 1)
    ht_insert(table, "Abba", 2)
    ht_insert(table, "Babba", 3)
    ht_insert(table, "Aaaaa", 4)
    ht_insert(table, "Aakk", 5)
    ht_insert(table, "Bfaw", 6)
    ht_insert(table, "Uno", 7)
    ht_insert(table, "Uk", 8)
    ht_insert(table, "Uaa", 9)
    ht_insert(table, "h", 10)
    print(table)
    print(ht_find(table,"Aakk"))
    #ht_delete(table, "Aakk")
    #ht_delete(table, "Aaaaa")
    #print(table)
    #ht_delete(table, "Uaa")
    #ht_delete(table, "Zyky")
    print(table)
    ht_listall(table)
    
def run_shuffled(records_shuffled):
    insertion_times=[]
    finding_times=[]
    deletion_times1=[]
    print("Shuffled list: ")
    for k in range(5):
        lisst=[]
        for i in range(5000):
            lisst.append(None)
        rd.shuffle(records_shuffled)
        
        #А. Вставка всех записей
        start=time.perf_counter()
        for i in range(len(records_shuffled)):
            ht_insert(lisst, records_shuffled[i][0], records_shuffled[i][1])
        end=time.perf_counter()
        insertion_times.append(end-start)
        
        #Б. Поиск 100 случайных записей
        names=[]
        index=rd.randint(0,9899)
        for i in range(100):
            names.append(records_shuffled[index][0])
            index+=1
        for i in range(10):
            names.append("A")
        rd.shuffle(names)
        
        start=time.perf_counter()
        for i in range(len(names)):
            ht_find(lisst,names[i])   
        end=time.perf_counter()
        finding_times.append(end-start)
        
        #В. Удаление 50 случайных записей
        for i in range(10):
            names.remove("A")
        rd.shuffle(names)
        deletion_times=[]
        
        for i in range(50):
            start=time.perf_counter()
            ht_delete(lisst,names[i])
            end=time.perf_counter()
            ttt=end-start
            deletion_times.append(ttt)
        deletion_times1.append(deletion_times)
        
        print("Run number ",k+1)
        print("Insertion time: ",insertion_times[k])
        print("Finding time: ",finding_times[k])
        print("Deletion times: ","\n",deletion_times)
        print("\n")
    
    temp=0
    for i in range(5):
        temp+=insertion_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"случайный", u"вставка", insertion_times[0]],
    ["HashTable", u"случайный", u"вставка", insertion_times[1]],
    ["HashTable", u"случайный", u"вставка", insertion_times[2]],
    ["HashTable", u"случайный", u"вставка", insertion_times[3]],
    ["HashTable", u"случайный", u"вставка", insertion_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"случайный", u"вставка", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
    
    temp=0
    for i in range(5):
        temp+=finding_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"случайный", u"поиск", finding_times[0]],
    ["HashTable", u"случайный", u"поиск", finding_times[1]],
    ["HashTable", u"случайный", u"поиск", finding_times[2]],
    ["HashTable", u"случайный", u"поиск", finding_times[3]],
    ["HashTable", u"случайный", u"поиск", finding_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"случайный", u"поиск", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
        
    temp=0
    del_times=[]
    for i in range(5):
        for j in range(50):
            temp+=deletion_times1[i][j]
        temp=temp/50
        del_times.append(temp)
        temp=0
    
    temp=0
    for i in range(5):
        temp+=del_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"случайный", u"удаление", del_times[0]],
    ["HashTable", u"случайный", u"удаление", del_times[1]],
    ["HashTable", u"случайный", u"удаление", del_times[2]],
    ["HashTable", u"случайный", u"удаление", del_times[3]],
    ["HashTable", u"случайный", u"удаление", del_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"случайный", u"удаление", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
        writer.writerows("\n")

def run_sorted(records_shuffled):
    insertion_times=[]
    finding_times=[]
    deletion_times1=[]
    print("Sorted list: ")
    for k in range(5):
        lisst=[]
        for i in range(5000):
            lisst.append(None)
        
        #А. Вставка всех записей
        start=time.perf_counter()
        for i in range(len(records_shuffled)):
            ht_insert(lisst, records_shuffled[i][0], records_shuffled[i][1])
        end=time.perf_counter()
        insertion_times.append(end-start)
        
        #Б. Поиск 100 случайных записей
        names=[]
        index=rd.randint(0,9899)
        for i in range(100):
            names.append(records_shuffled[index][0])
            index+=1
        for i in range(10):
            names.append("A")
        rd.shuffle(names)
        
        start=time.perf_counter()
        for i in range(len(names)):
            ht_find(lisst,names[i])   
        end=time.perf_counter()
        finding_times.append(end-start)
        
        #В. Удаление 50 случайных записей
        for i in range(10):
            names.remove("A")
        rd.shuffle(names)
        deletion_times=[]
        
        for i in range(50):
            start=time.perf_counter()
            ht_delete(lisst,names[i])
            end=time.perf_counter()
            ttt=end-start
            deletion_times.append(ttt)
        deletion_times1.append(deletion_times)
        
        print("Run number ",k+1)
        print("Insertion time: ",insertion_times[k])
        print("Finding time: ",finding_times[k])
        print("Deletion times: ","\n",deletion_times)
        print("\n")
    
    temp=0
    for i in range(5):
        temp+=insertion_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"отсортированный", u"вставка", insertion_times[0]],
    ["HashTable", u"отсортированный", u"вставка", insertion_times[1]],
    ["HashTable", u"отсортированный", u"вставка", insertion_times[2]],
    ["HashTable", u"отсортированный", u"вставка", insertion_times[3]],
    ["HashTable", u"сотсортированный", u"вставка", insertion_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"отсортированный", u"вставка", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
    
    temp=0
    for i in range(5):
        temp+=finding_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"отсортированный", u"поиск", finding_times[0]],
    ["HashTable", u"отсортированный", u"поиск", finding_times[1]],
    ["HashTable", u"отсортированный", u"поиск", finding_times[2]],
    ["HashTable", u"отсортированный", u"поиск", finding_times[3]],
    ["HashTable", u"отсортированный", u"поиск", finding_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"отсортированный", u"поиск", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
        
    temp=0
    del_times=[]
    for i in range(5):
        for j in range(50):
            temp+=deletion_times1[i][j]
        temp=temp/50
        del_times.append(temp)
        temp=0
    
    temp=0
    for i in range(5):
        temp+=del_times[i]
    temp=temp/5
    
    results = [
    [u"Структура", u"Режим", u"Операция", u"Время (сек)"],
    ["HashTable", u"отсортированный", u"удаление", del_times[0]],
    ["HashTable", u"отсортированный", u"удаление", del_times[1]],
    ["HashTable", u"отсортированный", u"удаление", del_times[2]],
    ["HashTable", u"отсортированный", u"удаление", del_times[3]],
    ["HashTable", u"отсортированный", u"удаление", del_times[4]],
    [u"Структура", u"Режим", u"Операция", u"Среднее время (сек)"],
    ["HashTable", u"отсортированный", u"удаление", temp,]
    ]
    
    with codecs.open("docs/data/[1]results.csv", "a+", "utf-16") as f:
        writer = csv.writer(f)
        writer.writerows(results)
        writer.writerows("\n")
        writer.writerows("\n")

records_shuffled, records_sorted = records()
run_shuffled(records_shuffled)
run_sorted(records_sorted)