from sklearn.cluster import DBSCAN
import math

def custom_metric(q, p, space_eps, time_eps):
    dist = 0
    for i in range(2):
        dist += (q[i] - p[i])**2
    spatial_dist = math.sqrt(dist)

    time_dist = math.sqrt((q[2]-p[2])**2)

    if time_dist/time_eps <= 1 and spatial_dist/space_eps <= 1 and p[3] != q[3]:
        return 1
    else:
        return 2


def cluster(vector_4d, distance, time, minimum_cluster):

    params = {"space_eps": distance, "time_eps": time}
    db = DBSCAN(eps=1, min_samples=minimum_cluster-1, metric=custom_metric, metric_params=params).fit_predict(vector_4d)

    unique_labels = set(db)
    total_clusters = len(unique_labels) if -1 not in unique_labels else len(unique_labels) -1

    print("Total clusters:", total_clusters)

    total_noise = list(db).count(-1)

    print("Total un-clustered:", total_noise)
    clusters = []
    clind = 0
    for k in unique_labels:
        if k != -1:

            labels_k = db == k
            cluster_k = vector_4d[labels_k]

            print("Cluster", k, " size:", len(cluster_k))
            cluster = []
            pind = 0
            for pt in cluster_k:
                print("(x:{}, y:{}, day:{}, caseNo:{})".format(pt[0], pt[1], pt[2], pt[3]))
                cluster.append({
                    'x': pt[0],
                    'y': pt[1],
                    'day': pt[2],
                    'caseNo': pt[3],
                    'ind': pind
                });
                pind+=1
            clusters.append({'ind': clind, 'cluster': cluster})
            clind += 1

    return {
        'total_clusters': total_clusters,
        'total_noise': total_noise,
        'clustres': clusters
    }

from sklearn.cluster import DBSCAN
import math

def custom_metric(q, p, space_eps, time_eps):
    dist = 0
    for i in range(2):
        dist += (q[i] - p[i])**2
    spatial_dist = math.sqrt(dist)

    time_dist = math.sqrt((q[2]-p[2])**2)

    if time_dist/time_eps <= 1 and spatial_dist/space_eps <= 1 and p[3] != q[3]:
        return 1
    else:
        return 2


def cluster(vector_4d, distance, time, minimum_cluster):

    params = {"space_eps": distance, "time_eps": time}
    db = DBSCAN(eps=1, min_samples=minimum_cluster-1, metric=custom_metric, metric_params=params).fit_predict(vector_4d)

    unique_labels = set(db)
    total_clusters = len(unique_labels) if -1 not in unique_labels else len(unique_labels) -1

    print("Total clusters:", total_clusters)

    total_noise = list(db).count(-1)

    print("Total un-clustered:", total_noise)
    clusters = []
    clind = 0
    for k in unique_labels:
        if k != -1:

            labels_k = db == k
            cluster_k = vector_4d[labels_k]

            print("Cluster", k, " size:", len(cluster_k))
            cluster = []
            pind = 0
            for pt in cluster_k:
                print("(x:{}, y:{}, day:{}, caseNo:{})".format(pt[0], pt[1], pt[2], pt[3]))
                cluster.append({
                    'x': pt[0],
                    'y': pt[1],
                    'day': pt[2],
                    'caseNo': pt[3],
                    'ind': pind
                });
                pind+=1
            clusters.append({'ind': clind, 'cluster': cluster})
            clind += 1

    return {
        'total_clusters': total_clusters,
        'total_noise': total_noise,
        'clustres': clusters
    }
