#!/usr/bin/env python3
import numpy as np
import csv
import itertools
import math

#https://stackoverflow.com/questions/5360220/how-to-split-a-list-into-pairs-in-all-possible-ways
def all_pairs(lst):
    if len(lst) < 2:
        yield lst
        return
    a = lst[0]
    for i in range(1,len(lst)):
        pair = (a,lst[i])
        for rest in all_pairs(lst[1:i]+lst[i+1:]):
            yield [pair] + rest

column_label=0
column_capacity=3
column_resistance=4


config_parallel=2
config_cells=12

#config_parallel*config_cells*config_packs needed
batteriesneeded=config_parallel*config_cells


batteries=[]
batterylabels=[]

with open('12S_LiIon_Akkupack_selected.csv', 'r') as csvfile:
    csvreader = csv.reader(csvfile, delimiter=';')
    firstrow=True
    for row in csvreader:
        label=row[column_label]
        capacity=row[column_capacity]
        resistance=row[column_resistance]
        if not firstrow:
            capacity=float(capacity)
            resistance=float(resistance)

            batteries.append([label,capacity,resistance])
            batterylabels.append(label)
        firstrow=False

print(str(len(batteries))+" Batteries found")
if len(batteries)==batteriesneeded:
    print("You have just enough batteries")
elif len(batteries)>batteriesneeded:
    print("You have "+str(len(batteries)-batteriesneeded)+" batteries spare")
elif len(batteries)<batteriesneeded:
    print("You need "+str(batteriesneeded-len(batteries))+" more batteries!")
    exit()

#batteries=[["a",1],["b",2],["c",3],["d",4],["e",5],["f",6]]

bestcombination=[]
bestdist=100000000


combinations=all_pairs(batteries)

num_combinations=0
#print("Counting combinations")
#for i in combinations: #just count the combinations
#    num_combinations+=1

print(str(num_combinations)+" combinations possible")

#evaluate combinations
count=0
for i in combinations: #every combinations
    count+=1
    if count%1000000==0:
        print(str(count)+"/"+str(num_combinations))

    seriescapacities=[]
    for s in i: #all series
        parallelcapacity=0
        for p in s: #all parallels
            parallelcapacity+=p[1]
        seriescapacities.append(parallelcapacity)

    meancapacity=np.mean(seriescapacities)
    dist=0
    for c in seriescapacities:
        dist+=math.pow(abs(c-meancapacity),2)

    if dist<bestdist:
        print(str(count)+"/"+str(num_combinations)+" New Best with distance "+str(dist))
        bestdist=dist
        bestcombination=i
        print("## Combination ##")
        for i in bestcombination:
            print(i)
        print("## ----------- ##")

print("")
print("best combination with "+str(bestdist)+" distance:")
#print(bestcombination)
for i in bestcombination:
    print(i)
