# L-6 MCS 275 Mon 23 Jan 2017 : kmeans.py
"""
Reads the file generated by makedata.py, shuffles the list,
and applies the k-means algorithm.
"""

from random import sample, shuffle
import turtle
from makedata import distance, centroids, radii, show_data, show_centroids

def read_list(file):
    """
    Attempts to read a list from file
    and will return this list.
    Returns the empty list if exceptions occur.
    """
    try:
        line = file.readline()
        data = eval(line)
        if isinstance(data, list):
            return data
        else:
            print(line)
            print("no list on file...")
            return []
    except IOError:
        print("exception occurred during reading...")
        return []

def read_data():
    """
    Prompts the user for a name of a file,
    tries to open the file and to read a list.
    If all goes well, the list is returned.
    """
    data = []
    while True:
        name = input("give a file name : ")
        try:
            datafile = open(name, 'r')
            data = read_list(datafile)
            datafile.close()
            return data
        except IOError:
            print('cound not open file ' + name)
            print('please try again')
    return data

def flatten(data):
    """
    Flattens the list of lists into one list.
    """
    result = []
    for each in data:
        for item in each:
            result.append(item)
    return result

def classify_point(ctr, pnt):
    """
    Returns the index of the point q in ctr,
    closest to ctr.
    """
    dis = [distance(pnt, q) for q in ctr]
    minval = min(dis)
    return dis.index(minval)

def classify_data(L, k, C):
    """
    Returns a lists of k lists, using the centroids
    in C to classify all points in L.
    """
    R = [[] for i in range(0, k)]
    for p in L:
        i = classify_point(C, p)
        R[i].append(p)
    return R

def kmeans(L, k):
    """
    Applies the K-means algorithm 3 times to divide
    the data in L into k clusters.
    """
    C0 = sample(L, k) # k unique random elements from L
    K0 = classify_data(L, k, C0)
    C1 = centroids(K0)
    R1 = radii(K0, C1)
    turtle.color('red', 'red')
    show_centroids(C1, R1)
    input("hit enter to continue ...")
    K1 = classify_data(L, k, C1)
    C2 = centroids(K1)
    R2 = radii(K1, C2)
    turtle.color('green', 'green')
    show_centroids(C2, R2)
    input("hit enter to continue ...")
    K2 = classify_data(L, k, C2)
    C3 = centroids(K2)
    R3 = radii(K2, C3)
    turtle.color('blue', 'blue')
    show_centroids(C3, R3)

def main():
    """
    Prompts the user for a file to read a list of lists
    of points of integer coordinates (generated by makedata).
    """
    D = read_data()
    show_data(D)
    L = flatten(D)
    print("the flattened list : ", L)
    shuffle(L)
    k = int(input("Give number of clusters : "))
    kmeans(L, k)
    input("exit ? (y/n) ")

main()
