"""

"""
from os.path import join
import argparse
import numpy as np
import pandas as pd
import sys
import os
import random 
from configs.train_config import IMG_SIZE

width_in_cfg_file = float(IMG_SIZE)
height_in_cfg_file = float(IMG_SIZE)

def IOU(x,centroids):
    similarities = []
    for centroid in centroids:
        c_w,c_h = centroid
        w,h = x
        if c_w>=w and c_h>=h:
            similarity = w*h/(c_w*c_h)
        elif c_w>=w and c_h<=h:
            similarity = w*c_h/(w*h + (c_w-w)*c_h)
        elif c_w<=w and c_h>=h:
            similarity = c_w*h/(w*h + c_w*(c_h-h))
        else: #means both w,h are bigger than c_w and c_h respectively
            similarity = (c_w*c_h)/(w*h)
        similarities.append(similarity) # will become (k,) shape
    return np.array(similarities) 

def avg_IOU(X,centroids):
    n, _ = X.shape
    sum = 0.
    for i in range(X.shape[0]):
        #note IOU() will return array which contains IoU for each centroid and X[i] // slightly ineffective, but I am too lazy
        sum+= max(IOU(X[i],centroids)) 
    return sum/n

def write_anchors_to_file(centroids,X,anchor_file):
    f = open(anchor_file,'w')
    
    anchors = centroids.copy() * 128
    print(anchors.shape)

    widths = anchors[:,0]
    sorted_indices = np.argsort(widths)

    print('Anchors = ', anchors[sorted_indices])
        
    for i in sorted_indices[:-1]:
        f.write('%0.2f,%0.2f, '%(int(anchors[i,0]),int(anchors[i,1])))

    #there should not be comma after last anchor, that's why
    f.write('%0.2f,%0.2f\n'%(int(anchors[sorted_indices[-1:],0]),int(anchors[sorted_indices[-1:],1])))
    
    f.write('%f\n'%(avg_IOU(X,centroids)))

def kmeans(X,centroids,anchor_file):
    
    N = X.shape[0]
    k,dim = centroids.shape
    prev_assignments = np.ones(N)*(-1)    
    iter = 0
    old_D = np.zeros((N,k))

    while True:
        D = [] 
        iter+=1           
        for i in range(N):
            d = 1 - IOU(X[i],centroids)
            D.append(d)
        D = np.array(D) # D.shape = (N,k)
        
        print("iter {}: dists = {}".format(iter,np.sum(np.abs(old_D-D))))
            
        #assign samples to centroids 
        assignments = np.argmin(D,axis=1)
        
        if (assignments == prev_assignments).all() :
            print("Centroids = ",centroids)
            write_anchors_to_file(centroids,X,anchor_file)
            return

        #calculate new centroids
        centroid_sums=np.zeros((k,dim),np.float)
        for i in range(N):
            centroid_sums[assignments[i]]+=X[i]        
        for j in range(k):            
            centroids[j] = centroid_sums[j]/(np.sum(assignments==j))
        
        prev_assignments = assignments.copy()     
        old_D = D.copy()  

def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument('-filelist', default = '../data/training', 
                        help='path to filelist\n' )
    parser.add_argument('-output_dir', default = 'generated_anchors', type = str, 
                        help='Output anchor directory\n' )  
    parser.add_argument('-num_clusters', default = 0, type = int, 
                        help='number of clusters\n' )
   
    args = parser.parse_args()
    
    if not os.path.exists(args.output_dir):
        os.mkdir(args.output_dir)
    
    annotation_dims = []

    folders = os.listdir(args.filelist)
    for folder in folders:
        if 'galaxies.csv' in os.listdir(args.filelist + '/' + folder):
            path_to_data = args.filelist + '/' + folder + '/galaxies.csv'
            dataset = pd.read_csv(path_to_data)
            imgs = dataset['img_path'].unique()
            for img in imgs:
                relevant_data = dataset[dataset['img_path'] == img]
                for _, row in relevant_data.iterrows():
                    xmin, ymin = row.xmin, row.ymin
                    xmax, ymax = row.xmax, row.ymax
                    height = ymax - ymin
                    width = xmax - xmin
                    annotation_dims.append(tuple(map(float,(width,height))))
    annotation_dims = np.array(annotation_dims)
  
    if args.num_clusters == 0:
        for num_clusters in range(1,11): #we make 1 through 10 clusters 
            anchor_file = join(args.output_dir,'anchors_trial{}.txt'.format(num_clusters))

            indices = [random.randrange(annotation_dims.shape[0]) for _ in range(num_clusters)]
            centroids = annotation_dims[indices]
            kmeans(annotation_dims,centroids,anchor_file)
            print('centroids.shape', centroids.shape)
    else:
        anchor_file = join(args.output_dir,'anchors_trial{}.txt'.format(args.num_clusters))
        indices = [ random.randrange(annotation_dims.shape[0]) for _ in range(args.num_clusters)]
        centroids = annotation_dims[indices]
        kmeans(annotation_dims,centroids,anchor_file)
        print('centroids.shape', centroids.shape)

if __name__=="__main__":
    main(sys.argv)
"""

"""
from os.path import join
import argparse
import numpy as np
import pandas as pd
import sys
import os
import random 
from configs.train_config import IMG_SIZE

width_in_cfg_file = float(IMG_SIZE)
height_in_cfg_file = float(IMG_SIZE)

def IOU(x,centroids):
    similarities = []
    for centroid in centroids:
        c_w,c_h = centroid
        w,h = x
        if c_w>=w and c_h>=h:
            similarity = w*h/(c_w*c_h)
        elif c_w>=w and c_h<=h:
            similarity = w*c_h/(w*h + (c_w-w)*c_h)
        elif c_w<=w and c_h>=h:
            similarity = c_w*h/(w*h + c_w*(c_h-h))
        else: #means both w,h are bigger than c_w and c_h respectively
            similarity = (c_w*c_h)/(w*h)
        similarities.append(similarity) # will become (k,) shape
    return np.array(similarities) 

def avg_IOU(X,centroids):
    n, _ = X.shape
    sum = 0.
    for i in range(X.shape[0]):
        #note IOU() will return array which contains IoU for each centroid and X[i] // slightly ineffective, but I am too lazy
        sum+= max(IOU(X[i],centroids)) 
    return sum/n

def write_anchors_to_file(centroids,X,anchor_file):
    f = open(anchor_file,'w')
    
    anchors = centroids.copy() * 128
    print(anchors.shape)

    widths = anchors[:,0]
    sorted_indices = np.argsort(widths)

    print('Anchors = ', anchors[sorted_indices])
        
    for i in sorted_indices[:-1]:
        f.write('%0.2f,%0.2f, '%(int(anchors[i,0]),int(anchors[i,1])))

    #there should not be comma after last anchor, that's why
    f.write('%0.2f,%0.2f\n'%(int(anchors[sorted_indices[-1:],0]),int(anchors[sorted_indices[-1:],1])))
    
    f.write('%f\n'%(avg_IOU(X,centroids)))

def kmeans(X,centroids,anchor_file):
    
    N = X.shape[0]
    k,dim = centroids.shape
    prev_assignments = np.ones(N)*(-1)    
    iter = 0
    old_D = np.zeros((N,k))

    while True:
        D = [] 
        iter+=1           
        for i in range(N):
            d = 1 - IOU(X[i],centroids)
            D.append(d)
        D = np.array(D) # D.shape = (N,k)
        
        print("iter {}: dists = {}".format(iter,np.sum(np.abs(old_D-D))))
            
        #assign samples to centroids 
        assignments = np.argmin(D,axis=1)
        
        if (assignments == prev_assignments).all() :
            print("Centroids = ",centroids)
            write_anchors_to_file(centroids,X,anchor_file)
            return

        #calculate new centroids
        centroid_sums=np.zeros((k,dim),np.float)
        for i in range(N):
            centroid_sums[assignments[i]]+=X[i]        
        for j in range(k):            
            centroids[j] = centroid_sums[j]/(np.sum(assignments==j))
        
        prev_assignments = assignments.copy()     
        old_D = D.copy()  

def main(argv):
    parser = argparse.ArgumentParser()
    parser.add_argument('-filelist', default = '../data/training', 
                        help='path to filelist\n' )
    parser.add_argument('-output_dir', default = 'generated_anchors', type = str, 
                        help='Output anchor directory\n' )  
    parser.add_argument('-num_clusters', default = 0, type = int, 
                        help='number of clusters\n' )
   
    args = parser.parse_args()
    
    if not os.path.exists(args.output_dir):
        os.mkdir(args.output_dir)
    
    annotation_dims = []

    folders = os.listdir(args.filelist)
    for folder in folders:
        if 'galaxies.csv' in os.listdir(args.filelist + '/' + folder):
            path_to_data = args.filelist + '/' + folder + '/galaxies.csv'
            dataset = pd.read_csv(path_to_data)
            imgs = dataset['img_path'].unique()
            for img in imgs:
                relevant_data = dataset[dataset['img_path'] == img]
                for _, row in relevant_data.iterrows():
                    xmin, ymin = row.xmin, row.ymin
                    xmax, ymax = row.xmax, row.ymax
                    height = ymax - ymin
                    width = xmax - xmin
                    annotation_dims.append(tuple(map(float,(width,height))))
    annotation_dims = np.array(annotation_dims)
  
    if args.num_clusters == 0:
        for num_clusters in range(1,11): #we make 1 through 10 clusters 
            anchor_file = join(args.output_dir,'anchors_trial{}.txt'.format(num_clusters))

            indices = [random.randrange(annotation_dims.shape[0]) for _ in range(num_clusters)]
            centroids = annotation_dims[indices]
            kmeans(annotation_dims,centroids,anchor_file)
            print('centroids.shape', centroids.shape)
    else:
        anchor_file = join(args.output_dir,'anchors_trial{}.txt'.format(args.num_clusters))
        indices = [ random.randrange(annotation_dims.shape[0]) for _ in range(args.num_clusters)]
        centroids = annotation_dims[indices]
        kmeans(annotation_dims,centroids,anchor_file)
        print('centroids.shape', centroids.shape)

if __name__=="__main__":
    main(sys.argv)
#means both w,h are bigger than c_w and c_h respectively # will become (k,) shape #note IOU() will return array which contains IoU for each centroid and X[i] // slightly ineffective, but I am too lazy #there should not be comma after last anchor, that's why # D.shape = (N,k) #assign samples to centroids #calculate new centroids #we make 1 through 10 clusters