import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
import seaborn as sns; sns.set()
import decimal
import csv
import os
os.environ["OMP_NUM_THREADS"] = "1" # export OMP_NUM_THREADS=1
os.environ["OPENBLAS_NUM_THREADS"] = "4" # export OPENBLAS_NUM_THREADS=4 
os.environ["MKL_NUM_THREADS"] = "6" # export MKL_NUM_THREADS=6
os.environ["VECLIB_MAXIMUM_THREADS"] = "4" # export VECLIB_MAXIMUM_THREADS=4
os.environ["NUMEXPR_NUM_THREADS"] = "6" # export NUMEXPR_NUM_THREADS=6


# Variable with the Longitude and Latitude
df=pd.read_csv('Cluster_Input.csv')
X=df.loc[:,['Avg','latitude','longitude','ID']]


""" #Create Clusters and Visualize - Unweighted
#Elbow Method
K_clusters = range(1,10)
kmeans = [KMeans(n_clusters=i) for i in K_clusters]
Y_axis = df[['latitude']]
X_axis = df[['longitude']]
score = [kmeans[i].fit(Y_axis).score(Y_axis) for i in range(len(kmeans))]
# Visualize elbow plot
plt.plot(K_clusters, score)
plt.xlabel('Number of Clusters')
plt.ylabel('Score')
plt.title('Elbow Curve')
plt.show()
#Input optimal number of clusters and print
from tkinter import simpledialog
Optimal_num_clusters = simpledialog.askstring("Optimal #", "Enter optimal # of Clusters:")
Optimal_num_clusters = int(Optimal_num_clusters)
print(Optimal_num_clusters)

# Compute k-means clustering
kmeans = KMeans(n_clusters = Optimal_num_clusters, init ='k-means++')
kmeans.fit(X[X.columns[1:3]]) 
#Predict Centers
X['cluster_label'] = kmeans.fit_predict(X[X.columns[1:3]])
centers = kmeans.cluster_centers_ # Coordinates of cluster centers.
labels = kmeans.predict(X[X.columns[1:3]]) # Labels of each point
#Visualise Results
X.plot.scatter(x = 'latitude', y = 'longitude', c=labels, s=50, cmap='viridis')
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)
plt.title('Clustering GPS Co-ordinates to Form Regions - Unweighted',fontsize=18, fontweight='bold')
plt.show()
print(Optimal_num_clusters) """


##Create Clusters and Visualize, Weighted    Using Value from Cluster Input as Weight
#drop nulls
df.dropna(axis=0,how='any',subset=['latitude','longitude','value'],inplace=True)
# Create Variable with the Longitude and Latitude
X_weighted = df.loc[:,['Avg','latitude','longitude','ID']]

#Elbow Method
K_clusters = range(1,10)
kmeans = [KMeans(n_clusters=i) for i in K_clusters]
lat_long = X_weighted[X_weighted.columns[1:2]]
value = X_weighted[X_weighted.columns[0]]
score = [kmeans[i].fit(lat_long, sample_weight = value).score(lat_long) for i in range(len(kmeans))]
# Visualize elbow plot
plt.plot(K_clusters, score)
plt.xlabel('Number of Clusters')
plt.ylabel('Score')
plt.title('Elbow Curve')
plt.show()
#Input optimal number of clusters and print
from tkinter import simpledialog
Optimal_num_clusters_weighted = simpledialog.askstring("Optimal #", "Enter optimal # of Clusters:")
Optimal_num_clusters_weighted = int(Optimal_num_clusters_weighted)
Optimal_num_cluster_weighted_range = range(1,Optimal_num_clusters_weighted)
print(Optimal_num_clusters_weighted)

# Compute weighted k-means clustering
kmeans = KMeans(n_clusters = Optimal_num_clusters_weighted, max_iter=1000, init ='k-means++')
lat_long = X_weighted[X_weighted.columns[1:3]]
value = X_weighted[X_weighted.columns[0]]
weighted_kmeans_clusters = kmeans.fit(lat_long, sample_weight = value) # Compute k-means clustering.
#Predict Centers
X_weighted['cluster_label'] = kmeans.predict(lat_long, sample_weight = value)
centers = kmeans.cluster_centers_ # Coordinates of cluster centers.
labels = X_weighted['cluster_label'] # Labels of each point
#Visualise Results
X_weighted.plot.scatter(x = 'latitude', y = 'longitude', c=labels, s=50, cmap='viridis')
plt.scatter(centers[:, 0], centers[:, 1], c='black', s=200, alpha=0.5)
plt.title('Optimal Clustering GPS Co-ordinates to Form Regions - Weighted',fontsize=18, fontweight='bold')
plt.show()
print(Optimal_num_clusters_weighted)

#Export to CSV
X_weighted=X_weighted[['ID','cluster_label']]
clustered_data = df.merge(X_weighted, left_on='ID', right_on='ID')
# convert latitude and longitude to decimal degrees
clustered_data['latitude'] = pd.to_numeric(clustered_data['latitude'])
clustered_data['longitude'] = pd.to_numeric(clustered_data['longitude'])                                                        
clustered_data.to_csv('clustered_data.csv')

##Find Bounding Boxes
# Get unique cluster labels
cluster_labels = clustered_data['cluster_label'].unique()
# Create a new DataFrame to store the results
results_rows= []
results_table = pd.DataFrame(columns=['cluster_label', 'min_latitude', 'max_latitude', 'min_longitude', 'max_longitude'])
# Loop over cluster labels
for label in cluster_labels:
    # Filter table based on the current cluster label
    cluster_data_label = clustered_data[clustered_data['cluster_label'] == label]
    # Find the minimum and maximum GPS coordinates for the current cluster label
    min_latitude = float(np.min(cluster_data_label['latitude']))
    max_latitude = np.max(cluster_data_label['latitude'])
    min_longitude = np.min(cluster_data_label['longitude'])
    max_longitude = np.max(cluster_data_label['longitude'])
    # Create a new row with the results and append it to the results table
    results_row = {
        'cluster_label': [label],
        'min_latitude': [min_latitude],
        'max_latitude': [max_latitude],
        'min_longitude': [min_longitude],
        'max_longitude': [max_longitude],
    }
    results_rows.append(results_row)
results_table = pd.DataFrame(results_rows)
# Print the results table
print(results_table)

#Export bounding boxes to kml
import simplekml
# create a KML file object
kml = simplekml.Kml()

# loop through each row in the results table
for index, row in results_table.iterrows():
    # get the minimum and maximum GPS coordinates for the current cluster label
    min_latitude = row['min_latitude']
    max_latitude = row['max_latitude']
    min_longitude = row['min_longitude']
    max_longitude = row['max_longitude']
    
    # create a boundary box from the minimum and maximum GPS coordinates
    boundary_box = kml.newgroundoverlay(name=f'Cluster {row["cluster_label"]}',
                                        latlonbox=simplekml.LatLonBox(
                                            north=max_latitude,
                                            south=min_latitude,
                                            east=max_longitude,
                                            west=min_longitude
                                        ))
    # set the image path and transparency of the boundary box
    boundary_box.color = simplekml.Color.rgb(255, 255, 255, 127)
    
# save the KML file
kml.save('boundary_boxes.kml')