#!/usr/bin/env python
# coding: utf-8

# In[ ]:


# importing all the required modules

from importlib import reload
import nltk
from bs4 import BeautifulSoup
from nltk.tokenize import sent_tokenize, word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer
import os,sys
import errno
import string
from nltk.corpus import reuters 
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords
from nltk import FreqDist
from nltk.text import TextCollection
import collections
import numpy as np
from nltk.tokenize import sent_tokenize, word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from prettytable import PrettyTable
import time
from datetime import timedelta
from sklearn.metrics import recall_score,precision_score,average_precision_score,f1_score,accuracy_score,roc_auc_score,mean_absolute_error
from sklearn.preprocessing import label_binarize
from imblearn.metrics import geometric_mean_score
from sklearn import metrics
from sklearn.metrics.cluster import homogeneity_score,completeness_score
import statistics
import math
import sklearn.metrics 
from sklearn.model_selection import KFold
import csv
from sklearn.model_selection import train_test_split
from collections import Counter
import math
from scipy.spatial import distance
import statistics
from scipy.stats import pearsonr,entropy,mode
from scipy.io import arff
from sklearn.metrics import pairwise_distances
import pandas as pd
from sklearn.datasets import fetch_20newsgroups
from sklearn.ensemble import RandomForestClassifier
nltk.download('reuters')
nltk.download('stopwords')
nltk.download('punkt')
nltk.download('wordnet')
from sklearn.neighbors import NearestNeighbors
from sklearn.neighbors import NearestCentroid
import csv
from sklearn import svm
import warnings
import random
from scipy.stats import pearsonr,entropy,mode,hmean
from sklearn.linear_model import LogisticRegression
from sklearn import preprocessing
from sklearn.model_selection import StratifiedKFold
from sklearn.base import BaseEstimator, ClassifierMixin
import operator
random.seed(0)
warnings.filterwarnings('ignore')
def loadTimeSeriesDatasets(directory, dataset):
    f=directory+"\\"+dataset+"\\"+dataset+'_TEST.arff'
    data = arff.loadarff(f)
    df = pd.DataFrame(data[0])
    test_labels=df['target']
    test_data= np.array(df.loc[:, df.columns != 'target'])
    f=directory+"\\"+dataset+"\\"+dataset+'_TRAIN.arff'
    data = arff.loadarff(f)
    df = pd.DataFrame(data[0])
    train_labels=df['target']
    train_data= np.array(df.loc[:, df.columns != 'target'])
    return train_data, train_labels, test_data, test_labels

def Euclidean(a, b):#distance
    return distance.euclidean(a,b)

def PrintDetails(metric="smtp",measure= "Accuracy",Arr=None,kList=list(range(1,26)),train_time=0,test_time=0,std=[]):
    x = PrettyTable()
    #kList=[1,3,5,9,15,30,45]#,70,90,120]
    if std==[]:
        x.field_names = ["k",measure,"Train Time","Test time","Total Time"]
    else:
        x.field_names = ["k",measure,"std","Train Time","Test time","Total Time"]
        
    print("metric",metric)
    print("measure",measure)
    tables.write(("metric\t"+str(metric)+"\n").encode())
    tables.write(("measure\t"+str(measure)+"\n").encode())
    average=0
    total_time=train_time+test_time
    for i in range(0,len(Arr)):
        print(i,len(Arr))
        tr_time=str(timedelta(seconds=(train_time[i])))
        ts_time=str(timedelta(seconds=(test_time[i])))
        
        tot_time=str(timedelta(seconds=(total_time[i])))
        if std==[]:
            x.add_row([str(kList[i]),round(Arr[i],4),tr_time,ts_time,tot_time]) 
        else:
            x.add_row([str(kList[i]),round(Arr[i],4),round(std[i],4),tr_time,ts_time,tot_time]) 
            
        average+=Arr[i]
    if std==[]:
        x.add_row(["Average",round((average/len(Arr)),4),str(timedelta(seconds=np.mean(train_time))),
                   str(timedelta(seconds=np.mean(test_time))),str(timedelta(seconds=np.mean(total_time)))]) 
        x.add_row(["Std Dev.",round(np.std(Arr),4),np.std(train_time),
                   np.std(test_time),np.std(total_time)])   
    else:
        x.add_row(["Average",round((average/len(Arr)),4),round(np.mean(std),4),str(timedelta(seconds=np.mean(train_time))),
                   str(timedelta(seconds=np.mean(test_time))),str(timedelta(seconds=np.mean(total_time)))]) 
        x.add_row(["Std Dev.",round(np.std(Arr),4),round(np.std(std),4),
                   round(np.std(train_time),10),
                   round(np.std(test_time),10),
                   round(np.std(total_time),10)])
        
    x.padding_width =1
    tables.write(str(x).encode())
    print(x)


def classify(k=3,metric="euclidean",termOccurance=None, docOccurance=None):
    accuracy=[]
    precision=[]
    Recall=[]
    fMeasure=[]
    mprecision=[]
    mRecall=[]
    mfMeasure=[]
    roc=[]
    y_pred=[]
    mae=[]
    averageMeanPrecison=[]
    kList=list(range(1,26))
    func=globals()[metric]
    train_time=[]
    test_time=[]
    class_dist=[]
    label_dist=[]
    classes=list(set(train_labels))
    p=1
    clss=list(classes)
    for c in range(0,len(classes)):
        #print(c)
        #print(train_labels[0])
        ind=[i for i in range(0,len(train_labels)) if classes[c]==train_labels[i]]
        class_dist.append(train_data[ind,:])
        #print()
        label_dist.append([train_labels[i] for i in ind])
    
    for k in kList:
        time1=time.time()
        pred=[]
        print("k",k)
        distances_class=[]
        neighs_class=[]
        for c in range(0,len(classes)):
            if len(class_dist[c])<k:
                    classifier = KNeighborsClassifier(n_neighbors=len(class_dist[c]),metric=func).fit(class_dist[c],label_dist[c])
            else:
                classifier = KNeighborsClassifier(n_neighbors=k,metric=func).fit(class_dist[c],label_dist[c])
            d,n=classifier.kneighbors(test_data,return_distance=True)
            distances_class.append(d)
            neighs_class.append(n)
        classifier1 = KNeighborsClassifier(n_neighbors=k,metric=func).fit(train_data,train_labels)
        distances,neighs=classifier1.kneighbors(test_data,return_distance=True)
        time2=time.time()
        for t in range(0,len(test_data)):
            cl_rdist=[]
            cl_mean=[]
            for c in range(0,len(classes)):
                neigh_labels=[train_labels[i] for i in neighs[t] if train_labels[i]==classes[c]]
                neigh_vals=[train_data[i] for i in neighs[t] if train_labels[i]==classes[c]]
                dist=[distances[t][j] for j,i in enumerate(neighs[t]) if train_labels[i]==classes[c]]
                total_d=0
                f1,f2=False,False
                if len(neigh_vals)>0:
                    r_mean=np.nanmean(neigh_vals,axis=0)
                    m2=func(test_data[t,:],r_mean)#+np.nanmin(dist)
                    total_d+=m2  
                    #cl_rdist.append(total_d) 
                    f1=True
                if len(neighs_class[c])>0:
                    neigh_vals=[class_dist[c][i] for i in neighs_class[c][t]]
                    r1_mean=np.nanmean(neigh_vals,axis=0)
                    m2=func(test_data[t,:],r1_mean)+np.nanmin(distances_class[c][t])
                    total_d+=m2
                    f2=True
                if f1==True :
                    cl_rdist.append(total_d)   
                else:
                    cl_rdist.append(np.inf)  
                
            cl_rdist=np.array(cl_rdist)
            class_weight = np.array(cl_rdist**-1)
            membership = class_weight/ np.nansum(class_weight)
            maxInd=np.argmax(membership)
            pred.append(clss[maxInd])  
        y_pred.append(pred)    
        time3=time.time()
        train_time.append(time2-time1)
        test_time.append(time3-time2)

    
    classes=list(set(labels))
    class_dict={}
    for i in range(0,len(classes)):
        class_dict[classes[i]]=i
    print(class_dict)
    num_testLabels=[]
    for i in range(0,len(test_labels)):
        num_testLabels.append(class_dict[test_labels[i]])
       
    for i in range(0,len(y_pred)):
        test_labels1=list(test_labels)

        #Accuracy
       
        accuracy.append(accuracy_score(test_labels, y_pred[i]))
        
        #Precison
        precision.append(precision_score(test_labels, y_pred[i],average='macro'))
         
        #Recall
        Recall.append(recall_score(test_labels, y_pred[i],average='macro'))
           
        #f measure
        fMeasure.append(f1_score(test_labels, y_pred[i],average='macro'))
        
        #Precison
        mprecision.append(precision_score(test_labels, y_pred[i],average='micro'))
         
        #Recall
        mRecall.append(recall_score(test_labels, y_pred[i],average='micro'))
           
        #f measure
        mfMeasure.append(f1_score(test_labels, y_pred[i],average='micro'))
      
        test = label_binarize(test_labels1, classes=categories).reshape((-1))
        pred = label_binarize( y_pred[i], classes=categories).reshape((-1))
        
        #roc
        try:
            roc.append(roc_auc_score(test,pred))
        except:
            roc.append(-1)
        #Average Mean Precision
        #y_val_true, val_pred = y_val_true.reshape((-1)), val_pred.reshape((-1))
        averageMeanPrecison.append(average_precision_score(test, pred))
        #MAE
        num_pred=[]
        for j in range(0,len(y_pred[i])):
            num_pred.append(class_dict[y_pred[i][j]])
        mae.append(mean_absolute_error(num_testLabels, num_pred))
        
        #PrintDetails(metric=metric,time=str(timedelta(seconds=(time2-time1))),measure="Average Mean Precison",Arr=averageMeanPrecison)

    #Accuracy
    PrintDetails(metric=metric,measure="Accuracy",Arr=accuracy,train_time=train_time,test_time=test_time)
    
    #Precison
    PrintDetails(metric=metric,measure="Precision",Arr=precision,train_time=train_time,test_time=test_time)
    #Precison
    PrintDetails(metric=metric,measure="micro Precision",Arr=mprecision,train_time=train_time,test_time=test_time)
    #Recall
    PrintDetails(metric=metric,measure="Recall",Arr=Recall,train_time=train_time,test_time=test_time)
     #Recall
    PrintDetails(metric=metric,measure="micro Recall",Arr=mRecall,train_time=train_time,test_time=test_time)
    #f measure
    PrintDetails(metric=metric,measure="F Measure",Arr=fMeasure,train_time=train_time,test_time=test_time)
    
    #f measure
    PrintDetails(metric=metric,measure="micro F Measure",Arr=mfMeasure,train_time=train_time,test_time=test_time)
    
    #roc
    PrintDetails(metric=metric,measure="ROC",Arr=roc,train_time=train_time,test_time=test_time)
    #Average Mean Precision
    PrintDetails(metric=metric,measure="Average Mean Precison",Arr=averageMeanPrecison,train_time=train_time,test_time=test_time)
    #MAE
    PrintDetails(metric=metric,measure="MAE",Arr=mae,train_time=train_time,test_time=test_time)
  
    
    
import glob
directory = "Time Series Datasets"
datasets = [f for f in os.listdir(directory) if os.path.isdir(os.path.join(directory, f))]
print(datasets)

 
for dataset in datasets:
    print(dataset)
    train_data,train_labels, test_data,test_labels=loadTimeSeriesDatasets("Time Series Datasets\\", dataset)
    labels=list(train_labels).copy()
    labels.extend(test_labels)
    labels=np.array(labels)
    labels=list(labels)
    le = preprocessing.LabelEncoder().fit(labels)
    labels=le.transform(labels)
    train_labels=le.transform(train_labels)
    test_labels=le.transform(test_labels)
    categories=list(set(labels))
    measures=["Euclidean"]
    classes=list(set(labels))
    global w
    w=0
    global Weights
    for met in measures:
        n_split=1
        labels=np.array(labels)
        path = "LMGL-FkNN\\Time Series Datasets"
        if not os.path.exists(path):
            os.makedirs(path)
        fname=path+'\\table_'+dataset+'_'+met+'-LMGL-FkNN.txt'
        tables = open(fname, 'wb')
        tables.write("\n*************".encode())
        tables.write((" Split\t"+str(n_split)).encode())
        tables.write(" ***********\n".encode())
        n_split=n_split+1
        k=1
        print("###############")
        Weights=np.ones(train_data.shape[0])
        classify(k=k,metric=met)
        tables.write("\n************* Average Results ***********\n".encode())
        tables.close()
        print("###############")





# In[ ]:


test=[1,2,3,4]
print(test[0:-1])


# In[ ]:


import numpy as np
from sklearn.metrics import roc_auc_score
y_true = np.array([0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
y_scores = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
roc_auc_score(y_true, y_scores)


# In[ ]:





# In[ ]:




