from Seqbacksel import SBS
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cross_validation import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
from sklearn.cross_validation import StratifiedKFold
from sklearn.svm import SVC
from sklearn.grid_search import GridSearchCV
from sklearn import preprocessing
from sklearn import utils
from sklearn.neural_network import MLPClassifier
from sklearn.metrics.pairwise import cosine_similarity as cos_sim
import math
from math import sqrt
from sklearn.metrics import pairwise_distances
from sklearn.metrics import mean_squared_error
from sklearn.neighbors import NearestNeighbors
from scipy.spatial.distance import correlation, cosine
from sklearn.linear_model import SGDClassifier
from sklearn.tree import DecisionTreeClassifier

class Learner:
    def __init__(self,clf):
        self.clf=clf

    def scoring(self,X_train,y_train,pipe_lr):
        kfold = StratifiedKFold(y=y_train, n_folds=4 , random_state=1) #make 4 fold validation
        scores=[]
        for k, (train,test) in enumerate(kfold): #run on each fold and output the accuracy score
            pipe_lr.fit(X_train[train],y_train[train])
            score=pipe_lr.score(X_train[train],y_train[train])
            scores.append(score)
            print('Fold %s, acc %.3f' % (k+1,score))

        print("CROSS VALIDATION ACCURACY: %.3f +/- %.3f" % (np.mean(scores),np.std(scores))) #final accuracy of the classifier

    def data_processing(self):
        rating_df = pd.read_csv('data/ratings.csv') #read ratings.csv
        users = rating_df['userId'].unique() #take unique user_id values
        movies = rating_df['movieId'].unique() #take unique movie_id values
        user2idx = {k: i for i, k in enumerate(users)}
        movie2idx = {k: i for i, k in enumerate(movies)}
        #combine them into a single dataframe
        rating_df['userId'] = rating_df['userId'].apply(lambda x: user2idx[x])
        rating_df['movieId'] = rating_df['movieId'].apply(lambda x: movie2idx[x])
        df = pd.read_csv('data/tags.csv')
        tags = df['tag'].unique() #take unique tags
        tag2idx = {k: i for i,k in enumerate(tags)}
        #add it to the dataframe
        rating_df['tag'] = df['tag'].apply(lambda x: tag2idx[x])
        #replace NaN values
        rating_df['tag'].fillna(-1,inplace=True)
        rating_df.drop('timestamp',axis=1,inplace=True) #drop timestamp because we dont need it
        #print(rating_df)
        Y = rating_df.iloc[:,-2].values #split the dataframe into X,Y . Ratings are put in Y
        rating = rating_df.pop('rating')
        #uder_id= rating_df.pop('userId')
        X = rating_df.iloc[:,:].values #rest of the features are put into X
        X_train, X_test, y_train, y_test =  train_test_split(X,Y, test_size=0.3, random_state=0) #split the total dataset into 70% train and 30% test

        lab_enc = preprocessing.LabelEncoder() #to replace continous values
        y_train = lab_enc.fit_transform(y_train)
        y_test = lab_enc.fit_transform(y_test)
        return X_train, X_test, y_train, y_test

    def classifier(self,X_train, X_test, y_train, y_test):
        # Regression classifier
        # Outputs training accuract
        # Output the predictions it predicts
        # Low Accuracy due to lack of features
        if self.clf == "regression":
            clf = LogisticRegression()
            clf.fit(X_train, y_train)
            print("LogisticRegression")
            print("Training accuracy: ",clf.score(X_train,y_train)*100)
            #print("predictions: ",clf.predict(X_test))

        # KNN classifier
        # Outputs training accuract
        # Output the predictions it predicts
        # 50% Accuracy, highest among all
        elif self.clf == "knn":
            clf = KNeighborsClassifier(n_neighbors=10)
            clf.fit(X_train, y_train)
            print("knn")
            print("Training accuracy: ",clf.score(X_train,y_train)*100)
            #print("predictions: ",clf.predict(X_test))

        # SVC classifier
        # Outputs training accuract
        # Output the predictions it predicts
        # Low Accuracy due to lack of features
        elif self.clf == "svc":
            clf = SVC()
            clf.fit(X_train, y_train)
            print("SVC")
            print("Training accuracy: ",round(clf.score(X_train,y_train)*100,2))
            #print("predictions: ",clf.predict(X_test))

        # Random Forest classifier
        # Outputs training accuract
        # Output the predictions it predicts
        # Over fitting data due to lack of features
        # not useful
        elif self.clf == "random forest":
            clf = RandomForestClassifier(n_estimators=500, random_state=0, n_jobs=1)
            clf.fit(X_train, y_train)
            print("Random Forest")
            print("Training accuracy: ",round(clf.score(X_train,y_train)*100,2))
            #print("predictions: ",clf.predict(X_test))

        # Neural Nets
        # Outputs training accuract
        # Output the predictions it predicts
        # Low Accuracy due to lack of features

        elif self.clf == "neural nets":
            clf = MLPClassifier(solver='lbfgs', alpha = 1e-5 , hidden_layer_sizes=(10,5), random_state=1)
            clf.fit(X_train, y_train)
            print("neural nets")
            print("Training accuracy: ",round(clf.score(X_train,y_train)*100,2))
            #print("Predictions: ",clf.predict(X_test))

        elif self.clf == "gnb":
            gaussian = GaussianNB()
            gaussian.fit(X_train, y_train)
            #Y_pred = gaussian.predict(X_test)
            acc_gaussian = round(gaussian.score(X_train, y_train) * 100, 2)
            print("gaussian NB\n")
            print("Training accuracy: ",acc_gaussian)

        elif self.clf == "dtree":
            decision_tree = DecisionTreeClassifier()
            decision_tree.fit(X_train, y_train)
            #Y_pred = decision_tree.predict(test)
            accuracy = round(decision_tree.score(X_train, y_train) * 100, 2)
            print("Decision Tree\n")
            print("Training accuracy: ",accuracy)

        elif self.clf == "sgd":
            sgd = SGDClassifier()
            sgd.fit(X_train, y_train)
            accuracy = round(sgd.score(X_train, y_train) * 100, 2)
            print("Stochastic Gradient Descent")
            print("Training accuracy: ",accuracy)

    def pipeline_learning(self,X_train, X_test, y_train, y_test):
        #pipeline does the same work as normal classifiers, ive not standardised the data and have not used PCA because
        # there are very less features already.
        # PIPELINING does apply k-fold validation on the dataset and outputs the accuracy at each fold and overall training accuracy
        # most of the classifiers gave just a slight increase in the accuracy but nothing substantial

        if self.clf == "knn":
            #Pipeline code
            print('KNN\n')
            pipe_lr= Pipeline([('clf',KNeighborsClassifier(n_neighbors=4))])
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "neural nets":
            print("Neural Nets")
            pipe_lr= Pipeline([('clf',MLPClassifier(solver='lbfgs', alpha = 1e-5 , hidden_layer_sizes=(10,5), random_state=1))])
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "random forest":
            print('RANDOM FOREST\n')
            #random = RandomForestClassifier(n_estimators=500, random_state=0, n_jobs=1))
            pipe_lr= Pipeline([('clf',RandomForestClassifier(n_estimators=100, random_state=0, n_jobs=1))])
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "regression":
            print('LOGISTIC REGRESSION\n')
            pipe_lr= Pipeline([('clf',LogisticRegression(random_state=1))])
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "svc":
            print('SVC\n')
            pipe_svc = Pipeline([('clf',SVC(random_state=1))])
            self.scoring(X_train,y_train,pipe_svc)

        elif self.clf == "gnb":
            pipe_lr= Pipeline([('clf',GaussianNB())])
            print("gaussian NB\n")
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "dtree":
            pipe_lr= Pipeline([('clf',DecisionTreeClassifier())])
            print("Decision Tree\n")
            self.scoring(X_train,y_train,pipe_lr)

        elif self.clf == "sgd":
            pipe_lr= Pipeline([('clf',SGDClassifier())])
            print("Stochastic Gradient Descent")
            self.scoring(X_train,y_train,pipe_lr)

    def create_similarity_matrix(self):
        rr = pd.read_csv('data/ratings.csv')
        x = rr['userId'].max() #max userID
        y = rr['movieId'].max() #max movie_id
        rating1=np.zeros((x,y)) #create a x,y matrix full of zeros
        total_ratings=0
        for  row in rr.itertuples():
            rating1[row[1]-1,row[2]-1]=row[3] #put the available ratings
            total_ratings+=1  #add the total number of actual rating in the matrix

        how_sparse=float(total_ratings)
        size=x*y #total entreies
        sparse = how_sparse/size #calculate sparsity
        test_item = math.floor(0.1*sparse*y)
        train_set = rating1.copy()
        test_set = np.zeros((x,y))
        #dividing it into training and test set. fill zeros where there was rating to create a random set.
        for uid in range(x):
                item = np.random.choice(rating1[uid, :].nonzero()[0], size=test_item, replace=False)
                test_set[uid, item] = rating1[uid, item] #add to the test_set
                train_set[uid, item] = 0
        user_sim = cos_sim(train_set) #calculating the cosine similarity
        return rating1,user_sim

    def pair_wise_distances(self,rating_matrix):
        cos_similarity  = 1-pairwise_distances(rating_matrix, metric="cosine") #calculates similarity on the basis of cosine metric
        pearson_similarity  = 1-pairwise_distances(rating_matrix, metric = "correlation") #calculates similarity on the basis of correlation metric

    def find_similar_users(self,user_id, ratings, metric, k=4):
        similar=[]
        index=[]
        model_knn = NearestNeighbors(metric = metric, algorithm = 'brute')  #create model
        model_knn.fit(ratings) #fit ratings ( user_id x movie_id)
        distances, index = model_knn.kneighbors(ratings.iloc[user_id-1, :].values.reshape(1, -1), n_neighbors = k+1) #find the distances
        similar = 1-distances.flatten() #find similar users
        print("%2d most similar users for User %2d:\n"%(k,user_id))
        for i in range(0, len(index.flatten())):
            if index.flatten()[i]+1 == user_id:
                continue
            else:
                print("%2d: User %2d, with similarity of %3.5f"%(i, index.flatten()[i]+1, similar.flatten()[i]))
        return similar,index

    def find_similar_movies(self,movie_id, ratings, metric, k=4):
        similar=[]
        index=[]
        ratings=ratings.T # transpose the matrix so as to get movie_id x useer_id
        movie_df = pd.read_csv('data/movies.csv') #read the movies_csv file to get the movie_id and title names
        genre = movie_df.pop('genres') #remove genres as we dont need it
        model_knn = NearestNeighbors(metric = metric, algorithm = 'brute')  #create the model
        model_knn.fit(ratings) # fit the rating matrix
        distances, index = model_knn.kneighbors(ratings.iloc[movie_id-1, :].values.reshape(1, -1), n_neighbors = k+1)
        similar = 1-distances.flatten() #find similar movies
        if any(movie_df.movieId == movie_id):
            movie_nam = movie_df.loc[movie_df['movieId']==movie_id,'title'].iloc[0]
        else:
            #print("movie_id doesnt exist in the database\n")
            movie_nam = str(movie_id)
        print("%2d most similar movies for Movie %s:\n"%(k,movie_nam)) #print the movie name
        for i in range(0, len(index.flatten())):
            if index.flatten()[i]+1 == movie_id:
                continue
            else:
                if any(movie_df.movieId == index.flatten()[i]+1):
                    movie_name=movie_df.loc[movie_df['movieId']==(index.flatten()[i]+1),'title'].iloc[0]
                else:
                    movie_name = index.flatten()[i]+1
                print("%2d: %s, with similarity of %3.5f"%(i, movie_name , similar.flatten()[i])) #print the similar movie names
        return similar,index

    def predict_userbased_rating(self,user_id, movie_id, ratings, metric, k=4):
        prediction=0
        similar, index=self.find_similar_users(user_id, ratings,metric, k) #similar users based on cosine similarity
        mean_rating = ratings.loc[user_id-1,:].mean() #to adjust for zero based indexing
        sum_wt = np.sum(similar)-1 #calculate the weight
        product=1
        wtd_sum = 0
        for i in range(0, len(index.flatten())):
            if index.flatten()[i]+1 == user_id:
                continue
            else:
                ratings_diff = ratings.iloc[index.flatten()[i],movie_id-1]-np.mean(ratings.iloc[index.flatten()[i],:]) #calculate the difference in rating
                product = ratings_diff * (similar[i])  #account the difference in rating
                wtd_sum = wtd_sum + product #update wt

        prediction = int(round(mean_rating + (wtd_sum/sum_wt)))
        print('\nPredicted rating for user %2d -> movie %2d: %2d'%(user_id,movie_id,prediction))
        return prediction

    def predict_moviebased_rating(self,user_id, movie_id, ratings, metric, k=4):
        #very similar function to predict user based ratings, just the matrux provded to it is transposed
        prediction=0
        wtd_sum=0
        similar, index=self.find_similar_movies(movie_id, ratings,metric,k) #similar users based on cosine similarity
        sum_wt = np.sum(similar)-1
        product=1
        for i in range(0, len(index.flatten())):
            if index.flatten()[i]+1 == movie_id:
                continue
            else:
                product =  ratings.iloc[user_id-1,index.flatten()[i]] * (similar[i])
                wtd_sum = wtd_sum + product

        prediction = int(round((wtd_sum/sum_wt)))
        print('\nPredicted rating for user %2d -> movie %2d: %2d'%(user_id,movie_id,prediction))
        return prediction

    def RMSE(self, ratings , metric):

        n_users = ratings.shape[0]
        n_items = ratings.shape[1]
        prediction = np.zeros((n_users, n_items))
        prediction= pd.DataFrame(prediction)

        for i in range(n_users):
            for j in range(n_items):
                prediction[i][j] = self.predict_userbased_rating(i+1, j+1, ratings, metric)

        MSE = mean_squared_error(prediction, ratings)
        RMSE = round(sqrt(MSE),3)
        print("RMSE using item based approach with %s metric is: %5.5f"%(metric,RMSE))

        prediction = np.zeros((n_users, n_items))
        prediction= pd.DataFrame(prediction)

        for i in range(n_users):
            for j in range(n_items):
                prediction[i][j] = self.predict_moviebased_rating(i+1, j+1, ratings, metric)

        MSE = mean_squared_error(prediction, ratings)
        RMSE = round(sqrt(MSE),3)
        print("RMSE using item based approach with %s metric is: %5.5f"%(metric,RMSE))

if __name__ == '__main__':
    #different learners used are:remove the comment from clfs
    print("Different classifiers running without k-fold validation and with 4-fold validation")
    clfs = ['knn','neural nets', 'random forest', 'regression', 'gnb' , 'dtree' , 'sgd']
    #clfs = ['knn']

    for clf in clfs: #clfs store the name of all the classifiers tested, but currently it is set to knn
        learner = Learner(clf)
        X_train, X_test, y_train, y_test = learner.data_processing()
        learner.classifier(X_train, X_test, y_train, y_test )
        learner.pipeline_learning(X_train, X_test, y_train, y_test)

    print('~~~~~~~~~~~~xx~~~~~~~~~~~~~~~')
    rating_matrix,user_similarity = learner.create_similarity_matrix()
    rating_matrix = pd.DataFrame(rating_matrix)
    user_id = int(input("Enter the user id: "))
    movie_id = int(input("Enter the movie_id: "))
    metric = input("Enter the metric - cosine or correlation: ")
    print('\n')
    print("USER BASED SIMILARITY\n")
    prediction_userbased = learner.predict_userbased_rating(user_id,movie_id,rating_matrix, metric = metric)
    print("ITEM BASED SIMILARITY\n")
    prediction_moviebased = learner.predict_moviebased_rating(user_id,movie_id,rating_matrix, metric = metric)
    #eval = learner.RMSE(rating_matrix, metric)


import os
import random

trainval_percent = 1
train_percent = 0.999
cur_dir = os.path.dirname(os.path.abspath(__file__))
xmlfilepath = cur_dir + '/datasets/Annotations/'
txtsavepath = cur_dir + '/datasets/ImageSets/Main/'
if not os.path.exists(txtsavepath):
    os.makedirs(txtsavepath)
total_xml = os.listdir(xmlfilepath)

num=len(total_xml)
list=range(num)
tv=int(num*trainval_percent)
tr=int(tv*train_percent)
trainval= random.sample(list,tv)
train=random.sample(trainval,tr)

ftrainval = open(txtsavepath + 'trainval.txt', 'w')
ftest = open(txtsavepath + 'test.txt', 'w')
ftrain = open(txtsavepath + 'train.txt', 'w')
fval = open(txtsavepath + 'val.txt', 'w')

for i in list:
    name=total_xml[i][:-4]+'\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest .close()


import socket
from multiprocessing import Process
import re
import sys

HTML_ROOT_DIR = "./html"

class HTTPServer(object):
    def __init__(self, app):
        self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.app = app

    def bind(self, port):
        self.serverSocket.bind(("", port))

    def start(self):
        self.serverSocket.listen(1000)
        while 1:
            clientSocket, clientAddress = self.serverSocket.accept()
            process = Process(target=self.handleClient, args=(clientSocket, ))
            process.start()
            clientSocket.close()

    def startResponse(self, status, headers):
        responseHeaders = "HTTP/1.1" + status + "\r\n"
        for header in headers:
            responseHeaders += "%s: %s\r\n" % header
        self.responseHeaders = responseHeaders

    def handleClient(self, clientSocket):
        requestData = clientSocket.recv(1024)
        requestLines = requestData.splitlines()
        requestStartLine = requestLines[0]
        print(requestStartLine.decode("utf-8"))
        fileName = re.match(r"\w+ +(/[^ ]*) ", requestStartLine.decode("utf-8")).group(1)
        method = re.match(r"(\w+) +/[^ ]* ", requestStartLine.decode("utf-8")).group(1)

        env = {
            "PATH_INFO": fileName,
            "METHOD": method
        }
        responseBody = self.app(env, self.startResponse)
        response = self.responseHeaders + "\r\n" + responseBody

        clientSocket.send(bytes(response, "utf-8"))
        clientSocket.close()

def main():
    sys.path.insert(1, HTML_ROOT_DIR)
    if len(sys.argv) < 2:
        sys.exit("framework!!!")

    moduleName, appName = sys.argv[1].split(":")
    m = __import__(moduleName)
    app = getattr(m, appName)
    httpServer = HTTPServer(app)
    httpServer.bind(4567)
    httpServer.start()

if __name__ == '__main__':
    main()


# -*- coding: utf-8 -*-

"""

@author: bartulem

Assign real times (based on elapsed IPIs) to spikes.

If there is sync misalignment between tracking and imec clocks,
such that sampling frequencies cannot be trusted, it is possible
to convert every event into time/frame measured by the IPI generator.

That works in the following way:
(1) spikes that happen before or after tracking are eliminated
(2) each spike time is calculated as the sum between how much time
    elapsed until the LED just prior to the spike, and the sampling
    rate between two bounding LEDs multiplied by the number of samples
    until the spike

!NB: Spike times are now zeroed to tracking start!

"""

import numpy as np
from numba import njit

@njit(parallel=False)
def times_to_events(sync_data,
                    event_data,
                    imec_data_col,
                    time_data_col,
                    frame_data_col):

    """
    Inputs
    ----------
    sync_data : np.ndarray
        The sync data; necessary input.
    event_data : np.ndarray
        The spike train; necessary input.
    imec_data_col : int
        IMEC column in the sync DataFrame; necessary input.
    time_data_col : int
        IPI time column in the sync DataFrame; necessary input.
    frame_data_col : int
        Tracking column in the sync DataFrame; necessary input.
    ----------

    Outputs
    ----------
    new_event_times : np.ndarray
        An array with spike times converted to the synce pulse clock.
    new_event_frames : np.ndarray
        An array with spike frames adjusted to the synce pulse clock.
    ----------
    """

    # get first and last imec LEDs
    first_led_samples = sync_data[1, imec_data_col]
    last_led_samples = sync_data[-2, imec_data_col]

    # eliminate events before 1st and after last LED onset
    # this means there are no more spikes before or after tracking
    event_data = event_data[(event_data > first_led_samples) & (event_data < last_led_samples)]

    # create new array for event times
    new_event_times = np.zeros(len(event_data))
    new_event_frames = np.zeros(len(event_data), dtype=np.int64)

    for idx, spike in enumerate(event_data):

        for xx in range(1, sync_data.shape[0] - 2):

            # find bounding LED events in samples
            lower_bound_samples = sync_data[xx, imec_data_col]
            upper_bound_samples = sync_data[xx + 1, imec_data_col]

            if lower_bound_samples <= spike < upper_bound_samples:

                # find bounding LED events in sync time and frames
                lower_bound_time = sync_data[xx, time_data_col]
                upper_bound_time = sync_data[xx + 1, time_data_col]

                lower_bound_frames = sync_data[xx, frame_data_col]
                upper_bound_frames = sync_data[xx + 1, frame_data_col]

                # get total number of samples between two bounding LED events
                total_samples_between = upper_bound_samples - lower_bound_samples

                # samples between spike and lower bound led
                samples_to_spike = spike - lower_bound_samples + 1

                # get total time/frames between two bounding LED events
                total_time_between = upper_bound_time - lower_bound_time
                total_frames_between = upper_bound_frames - lower_bound_frames

                # calculate spike time/frame
                spike_time = lower_bound_time + (total_time_between / total_samples_between) * samples_to_spike
                spike_frame = (lower_bound_frames - sync_data[1, frame_data_col]) + \
                              int(round((total_frames_between / total_samples_between) * samples_to_spike))

                # save results converted to seconds/frames to array
                new_event_times[idx] = spike_time / 1e3
                new_event_frames[idx] = spike_frame

                break

    return new_event_times, new_event_frames


import torch
from dataset import test_loader
from generator_model import Generator
from tqdm import tqdm
import config
from torchvision.utils import save_image
import numpy as np
import cv2 as cv
from skimage.measure._label import label

def cv_imread(filePath):

    cv_img = cv.imdecode(np.fromfile(filePath, dtype=np.uint8), -1)
    cv_img = cv.cvtColor(cv_img, cv.COLOR_RGB2BGR)

    return cv_img

def threshold_image(image):

    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    ret, binary = cv.threshold(gray, 255, 255, cv.THRESH_BINARY|cv.THRESH_OTSU)

    return binary

def save_some_examples(gen, x, y, epoch, folder):

    x, y = x.to(config.DEVICE), y.to(config.DEVICE)
    gen.eval()
    with torch.no_grad():
        y_fake = gen(x)

        y_fake += torch.flip(y_fake, (2,))   # row
        y_fake += torch.flip(y_fake, (3,))   # column
        y_fake += y_fake.transpose(-1, -2)   # diagonal

        save_image(y_fake, folder + f"/y_gen_{epoch}.png")
        save_image(y, folder + f"/input_{epoch}.png")

        y_fake_name = folder + f"/y_gen_{epoch}.png"
        y_fake_image = cv_imread(y_fake_name)
        y_fake_image = cv.medianBlur(y_fake_image, ksize=3)
        y_binary = threshold_image(image=y_fake_image)

        labels, num = label(y_binary, return_num=True, background=255)

        max_area = 0
        for i in range(1, num + 1):
            value_area = (np.ones_like(labels) * i == labels).sum()

            if value_area > max_area:
                max_area = value_area
                value = i

        y_binary = 1 - np.array(np.ones_like(labels) * value == labels).astype('uint8')

        y_fake = torch.from_numpy(y_binary)[None, None, ...]
        y_fake = torch.clamp(y_fake.float(), min=0., max=1.)

        save_image(y_fake, folder + f"/y_gen_{epoch}_binary.png")

        return y, y_fake

gen = Generator(in_channels=1, features=32).to(config.DEVICE)

gen.load_state_dict(torch.load('checkpoints/gen_500.pth.tar')['state_dict'], strict=False)

loop = tqdm(test_loader, leave=True)

output_50_50 = []
label_50_50 = []
label_10_31 = []
for idx, (x, y) in enumerate(loop):

    if idx>14120:

        y, y_fake = save_some_examples(gen, x, y, idx+1, folder="inference")

        label_50_50.append(y.squeeze(1).cpu().numpy())
        output_50_50.append(y_fake.squeeze(1).cpu().numpy())
        label_10_31.append(x.reshape(-1, 10, 31).cpu().numpy())

label_10_31 = np.concatenate(label_10_31, axis=0)
label_50_50 = np.concatenate(label_50_50, axis=0)
output_50_50 = np.concatenate(output_50_50, axis=0)

import scipy.io as sio

sio.savemat('inference.mat', {'label_10_31': label_10_31,
                              'label_50_50': label_50_50,
                              'output_50_50': output_50_50})


import math
import multiprocessing as mp
import pickle

from interpro7dw import metacyc, uniprot
from interpro7dw.interpro import oracle
from interpro7dw.interpro.utils import copy_dict
from interpro7dw.utils import logger
from interpro7dw.utils.store import BasicStore, Directory, KVStore
from .utils import dump_to_tmp, unpack_pdb_matches

MIN_SIMILARITY = 0.75
MAIN_RANKS = [
    "superkingdom",
    "kingdom",
    "phylum",
    "class",
    "order",
    "family",
    "genus",
    "species"
]

def export_sim_entries(matches_file: str, output: str):
    logger.info("starting")

    num_proteins = {}  # number of proteins matched by entry
    num_overlaps = {}  # number of proteins where two entries overlap >= 50%
    entry2type = {}    # type (in lower case) of each InterPro entry

    with KVStore(matches_file) as matches:
        for i, (signatures, entries) in enumerate(matches.values()):
            entry2locations = {}

            for entry_acc, entry in entries.items():
                if entry_acc not in entry2type:
                    entry2type[entry_acc] = entry["type"].lower()

                # Flatten the entry's matches (only one frag / location)
                entry2locations[entry_acc] = []
                for loc in entry["locations"]:
                    entry2locations[entry_acc].append((
                        loc["fragments"][0]["start"],
                        loc["fragments"][0]["end"],
                    ))

            # Evaluate how InterPro entries overlap
            for entry_acc, locations in entry2locations.items():
                try:
                    num_proteins[entry_acc] += 1
                except KeyError:
                    num_proteins[entry_acc] = 1

                for other_acc, other_locations in entry2locations.items():
                    if other_acc >= entry_acc:
                        continue

                    try:
                        entry_overlaps = num_overlaps[entry_acc]
                    except KeyError:
                        entry_overlaps = num_overlaps[entry_acc] = {}

                    try:
                        overlaps = entry_overlaps[other_acc]
                    except KeyError:
                        overlaps = entry_overlaps[other_acc] = [0, 0]

                    flag = 0
                    for start1, end1 in locations:
                        length1 = end1 - start1 + 1

                        for start2, end2 in other_locations:
                            length2 = end2 - start2 + 1
                            overlap = min(end1, end2) - max(start1, start2) + 1

                            if not flag & 1 and overlap >= length1 * 0.5:
                                # 1st time fragments overlap >= 50% of entry 1
                                flag |= 1
                                overlaps[0] += 1

                            if not flag & 2 and overlap >= length2 * 0.5:
                                # 1st time fragments overlap >= 50% of entry 2
                                flag |= 2
                                overlaps[1] += 1

                        if flag == 3:
                            # Both cases already happened
                            break

            if (i + 1) % 1e7 == 0:
                logger.info(f"{i + 1:>15,}")

        logger.info(f"{i + 1:>15,}")

    supfam = "homologous_superfamily"
    types = (supfam, "domain", "family", "repeat")
    overlapping_entries = []
    for entry_acc, overlaps in num_overlaps.items():
        entry_cnt = num_proteins[entry_acc]

        for other_acc, (cnt1, cnt2) in overlaps.items():
            other_cnt = num_proteins[other_acc]

            # Independent coefficients
            coef1 = cnt1 / (entry_cnt + other_cnt - cnt1)
            coef2 = cnt2 / (entry_cnt + other_cnt - cnt2)

            # Final coefficient (average of independent coefficients)
            coef = (coef1 + coef2) * 0.5

            # Containment indices
            cont1 = cnt1 / entry_cnt
            cont2 = cnt2 / other_cnt

            if all(e < MIN_SIMILARITY for e in (coef, cont1, cont2)):
                continue

            # Entries are deemed similar
            type1 = entry2type[entry_acc]
            type2 = entry2type[other_acc]
            if ((type1 == supfam and type2 in types)
                    or (type2 == supfam and type1 in types)):
                overlapping_entries.append((entry_acc, other_acc))

    with open(output, "wb") as fh:
        pickle.dump(overlapping_entries, fh)

    logger.info("done")

def _init_entry_xrefs() -> dict:
    return {
        "dom_orgs": set(),
        "enzymes": set(),
        "genes": set(),
        "matches": 0,
        "reactome": set(),
        "proteins": [],
        "proteomes": set(),
        "structures": set(),
        "struct_models": {
            "alphafold": 0,
            "rosettafold": 0
        },
        "taxa": {}
    }

def _process_entries(proteins_file: str, matches_file: str,
                     alphafold_file: str, proteomes_file: str,
                     domorgs_file: str, pdb2matches_file: str,
                     evidences_file: str, protein2enzymes: dict,
                     protein2reactome: dict, start: str, stop: str | None,
                     workdir: Directory, queue: mp.Queue):
    entry2structures = unpack_pdb_matches(pdb2matches_file)
    proteins_store = KVStore(proteins_file)
    matches_store = KVStore(matches_file)
    alphafold_store = KVStore(alphafold_file)
    proteomes_store = KVStore(proteomes_file)
    domorgs_store = KVStore(domorgs_file)
    evidences_store = KVStore(evidences_file)

    i = 0
    tmp_stores = {}
    xrefs = {}
    for protein_acc, (signatures, entries) in matches_store.range(start, stop):
        protein = proteins_store[protein_acc]
        protein_id = protein["identifier"]
        taxon_id = protein["taxid"]
        proteome_id = proteomes_store.get(protein_acc)
        evidence, gene_name = evidences_store[protein_acc]

        try:
            domain = domorgs_store[protein_acc]
        except KeyError:
            domain_id = None
            domain_members = []
        else:
            domain_id = domain["id"]
            domain_members = domain["members"]

        in_alphafold = len(alphafold_store.get(protein_acc, [])) > 0

        for is_interpro, obj in [(False, signatures), (True, entries)]:
            for entry_acc, match in obj.items():
                if entry_acc in xrefs:
                    entry = xrefs[entry_acc]
                else:
                    entry = xrefs[entry_acc] = _init_entry_xrefs()

                entry["matches"] += len(match["locations"])
                entry["proteins"].append((protein_acc, protein_id,
                                          in_alphafold))

                if taxon_id in entry["taxa"]:
                    entry["taxa"][taxon_id] += 1
                else:
                    entry["taxa"][taxon_id] = 1

                if entry_acc in domain_members:
                    entry["dom_orgs"].add(domain_id)

                if proteome_id:
                    entry["proteomes"].add(proteome_id)

                """
                Use `pop()` instead of `get()` so we add structures once
                per signature
                """
                for pdb_id in entry2structures.pop(entry_acc, []):
                    entry["structures"].add(pdb_id)

                if gene_name:
                    entry["genes"].add(gene_name)

                if in_alphafold:
                    entry["struct_models"]["alphafold"] += 1

                if is_interpro:
                    for ecno in protein2enzymes.get(protein_acc, []):
                        entry["enzymes"].add(ecno)

                    pathways = protein2reactome.get(protein_acc, [])
                    for pathway_id, pathway_name in pathways:
                        entry["reactome"].add((pathway_id, pathway_name))

        i += 1
        if i == 1e5:
            dump_to_tmp(xrefs, tmp_stores, workdir)
            queue.put((False, i))
            i = 0

    dump_to_tmp(xrefs, tmp_stores, workdir)
    proteins_store.close()
    matches_store.close()
    alphafold_store.close()
    proteomes_store.close()
    domorgs_store.close()
    evidences_store.close()

    queue.put((False, i))
    queue.put((True, tmp_stores))

def export_xrefs(uniprot_uri: str, proteins_file: str, matches_file: str,
                 alphafold_file: str, proteomes_file: str, domorgs_file: str,
                 rosettafold_file: str, pdb2matches_file: str,
                 evidences_file: str, taxa_file: str, metacyc_file: str,
                 output: str, interpro_uri: str | None = None,
                 processes: int = 8, tempdir: str | None = None):
    """Export InterPro entries and member database signatures cross-references.
    For each entry or signature, the following information is saved:
        - proteins matched (and number of matches)
        - proteomes
        - PDBe structures
        - taxa
        - domain organisations
        - ENZYME numbers
        - MetaCyc and Reactome pathways

    :param uniprot_uri: UniProt Oracle connection string
    :param proteins_file: KVStore file of protein info
    :param matches_file: KVStore file of protein matches
    :param alphafold_file: KVStore file of proteins with AlphaFold models
    :param proteomes_file: KVStore file of protein-proteome mapping
    :param domorgs_file: KVStore file of domain organisations
    :param rosettafold_file: BasicStore file of RoseTTAFold predictions
    :param pdb2matches_file: File of PDB matches
    :param evidences_file: KVStore file of protein evidences/genes
    :param taxa_file: File of taxonomic information
    :param metacyc_file: MetaCyc tar archive
    :param output: Output BasicStore file
    :param interpro_uri: InterPro Oracle connection string. If provided,
    update database with pathways cross-references
    :param processes: Number of workers
    :param tempdir: Temporary directory
    """
    logger.info("loading Swiss-Prot data")
    protein2enzymes = uniprot.proteins.get_swissprot2enzyme(uniprot_uri)
    protein2reactome = uniprot.proteins.get_swissprot2reactome(uniprot_uri)

    logger.info("iterating proteins")
    processes = max(1, processes - 1)
    with KVStore(proteins_file) as store:
        keys = store.get_keys()

    chunksize = math.ceil(len(keys) / processes)
    queue = mp.Queue()
    workers = []
    for i in range(processes):
        start = keys[i*chunksize]
        try:
            stop = keys[(i+1)*chunksize]
        except IndexError:
            stop = None

        workdir = Directory(tempdir=tempdir)
        p = mp.Process(target=_process_entries,
                       args=(proteins_file, matches_file, alphafold_file,
                             proteomes_file, domorgs_file, pdb2matches_file,
                             evidences_file, protein2enzymes,
                             protein2reactome, start, stop, workdir, queue))
        p.start()
        workers.append((p, workdir))

    entry2stores = {}
    progress = 0
    milestone = step = 1e7
    work_done = 0
    while work_done < len(workers):
        is_done, obj = queue.get()
        if is_done:
            work_done += 1
            for entry_acc, entry_store in obj.items():
                if entry_acc in entry2stores:
                    entry2stores[entry_acc].append(entry_store)
                else:
                    entry2stores[entry_acc] = [entry_store]
        else:
            progress += obj
            if progress >= milestone:
                logger.info(f"{progress:>15,.0f}")
                milestone += step

    logger.info(f"{progress:>15,.0f}")
    for p, workdir in workers:
        p.join()

    logger.info("loading RoseTTAFold models")
    rosettafold_models = set()
    with BasicStore(rosettafold_file, mode="r") as models:
        for model in models:
            signature_acc, entry_acc = model[:2]

            rosettafold_models.add(signature_acc)
            if entry_acc:
                rosettafold_models.add(entry_acc)

    logger.info("loading MetaCyc pathways")
    ec2metacyc = metacyc.get_ec2pathways(metacyc_file)

    logger.info("loading taxonomy")
    with open(taxa_file, "rb") as fh:
        taxa = pickle.load(fh)

    """
    Define lineage but with major ranks only.
    Some ranks will stay empty (None) because not all clades
    exist (e.g. no family between an order and a genus).
    """
    logger.info("create lineage for main taxonomic ranks")
    for info in taxa.values():
        lineage = [None] * len(MAIN_RANKS)

        for node_id in info["lineage"]:
            node = taxa[node_id]

            try:
                i = MAIN_RANKS.index(node["rank"])
            except ValueError:
                pass
            else:
                lineage[i] = node_id

        info["main_ranks"] = lineage

    logger.info("writing final file")
    entry2pathways = {}
    with BasicStore(output, mode="w") as store:
        progress = 0
        total = len(entry2stores)
        milestone = step = math.ceil(0.1 * total)
        for entry_acc in sorted(entry2stores):
            # Merge cross-references
            entry_xrefs = {}
            for entry_store in entry2stores[entry_acc]:
                for xrefs in entry_store:
                    copy_dict(xrefs, entry_xrefs, concat_or_incr=True)

            """
            Propagate protein count to ancestors and build a tree of
            taxonomy distribution
            """
            all_taxa = {}
            tree = {}
            for taxon_id, num_proteins in entry_xrefs["taxa"].items():
                is_species = False
                node_id = taxon_id
                while node_id:
                    node = taxa[node_id]

                    try:
                        all_taxa[node_id] += num_proteins
                    except KeyError:
                        all_taxa[node_id] = num_proteins

                    if node["rank"] == "species":
                        """
                        The taxon (with mapped sequences)
                        or one of its ancestors is a species .
                        """
                        is_species = True

                    node_id = node["parent"]

                # Add lineage of major ranks in tree
                lineage = taxa[taxon_id]["main_ranks"]
                obj = tree
                unique_id = "1"  # default to root
                for i, (rank, node_id) in enumerate(zip(MAIN_RANKS, lineage)):
                    """
                    Since several nodes may have node_id set to None,
                    we need to create a unique identifier
                    """
                    if node_id:
                        unique_id = node_id
                    else:
                        unique_id += f"-{i}"

                    try:
                        node = obj[unique_id]
                    except KeyError:
                        if node_id:
                            sci_name = taxa[node_id]["sci_name"]
                        else:
                            sci_name = None

                        node = obj[unique_id] = {
                            "id": unique_id,
                            "rank": rank,
                            "name": sci_name,
                            "proteins": 0,
                            "species": 0,
                            "children": {}
                        }

                    node["proteins"] += num_proteins
                    if is_species:
                        node["species"] += 1

                    obj = node["children"]  # descends into children

            # Wraps superkingdoms in a "root" node
            num_proteins = 0
            num_species = 0
            children = []
            for node in tree.values():
                num_proteins += node["proteins"]
                num_species += node["species"]
                children.append(_format_node(node))

            entry_xrefs["taxa"] = {
                "all": all_taxa,
                "hit": entry_xrefs["taxa"],
                "tree": {
                    "id": "1",
                    "rank": None,
                    "name": "root",
                    "proteins": num_proteins,
                    "species": num_species,
                    "children": children
                }
            }

            # Adds MetaCyc pathways
            entry_xrefs["metacyc"] = set()
            for ecno in entry_xrefs["enzymes"]:
                for pathway_id, pathway_name in ec2metacyc.get(ecno, []):
                    entry_xrefs["metacyc"].add((pathway_id, pathway_name))

            entry2pathways[entry_acc] = [
                ("metacyc", entry_xrefs["metacyc"]),
                ("reactome", entry_xrefs["reactome"])
            ]

            if entry_acc in rosettafold_models:
                entry_xrefs["struct_models"]["rosettafold"] = 1

            store.write((entry_acc, entry_xrefs))

            progress += 1
            if progress == milestone:
                logger.info(f"{progress:>15,.0f} / {total:,}")
                milestone += step

        logger.info(f"{progress:>15,.0f} / {total:,}")

    size = 0
    for p, workdir, in workers:
        size += workdir.get_size()
        workdir.remove()

    logger.info(f"temporary files: {size / 1024 ** 2:.0f} MB")

    if interpro_uri:
        logger.info("updating ENTRY2PATHWAY")
        oracle.entries.update_pathways(interpro_uri, entry2pathways)

    logger.info("done")

def _format_node(node: dict) -> dict:
    children = []

    while node["children"]:
        child_id, child = node["children"].popitem()
        children.append(_format_node(child))

    node["children"] = children

    return node


import collections
import os

import numpy as np
import pandas as pd
import sklearn.ensemble
import sklearn.linear_model
import sklearn.metrics
import sklearn.naive_bayes
import sklearn.svm

Data = collections.namedtuple('Data', ['x_train', 'y_train', 'x_test', 'y_test', 'id_test'])

POOLING_TYPES = ['mean', 'sd', 'mean+sd']

def load_datasets(data_dir: str, split: str, vectors, pooling_type: str) -> Data:
    train_file = os.path.join(data_dir, "{}_train.csv".format(split))
    test_file = os.path.join(data_dir, "{}_test.csv".format(split))
    x_train, y_train, _ = load_dataset(train_file, vectors, pooling_type)
    x_test, y_test, id_test = load_dataset(test_file, vectors, pooling_type)
    return Data(x_train, y_train, x_test, y_test, id_test)

def load_dataset(index_file: str, vectors, pooling_type: str):
    index = pd.read_csv(index_file)
    dataset = pd.merge(index, vectors, on='file')
    dataset['label'] = dataset['label'].map(lambda x: 1 if x == 'VULNERABLE' else 0)
    if pooling_type == 'mean':
        dataset['vector'] = dataset['mean_vector']
    elif pooling_type == 'sd':
        dataset['vector'] = dataset['sd_vector']
    elif pooling_type == 'mean+sd':
        dataset['vector'] = dataset.apply(lambda row: np.concatenate([row['mean_vector'], row['sd_vector']]).tolist(), axis=1)
    else:
        raise ValueError("unsupported pooling type: %s", pooling_type)
    return df_to_x_y_id(dataset)

def df_to_x_y_id(dataset):
    ids = list(dataset['file'])
    x_tmp = np.array(dataset['vector'])
    x_concat = np.concatenate(x_tmp)
    x = np.reshape(x_concat, (x_tmp.shape[0], x_concat.shape[0] // x_tmp.shape[0]))
    y = np.array(dataset['label'])
    return x, y, ids

def train_and_evaluate(data: Data, spec: dict, n_jobs: int = None) -> dict:
    classifier = _make_classifier(spec['classifier'], n_jobs)
    sample_weight = data.y_train * spec['pos_class_weight'] + np.ones(data.y_train.shape[0]) - data.y_train
    classifier.fit(data.x_train, data.y_train, sample_weight=sample_weight)
    return dict(test=evaluate_classifier(classifier, data.x_test, data.y_test, data.id_test))

def _make_classifier(spec: dict, n_jobs: int):
    if spec['type'] == 'NaiveBayes':
        return sklearn.naive_bayes.GaussianNB()
    elif spec['type'] == 'LR':
        return sklearn.linear_model.LogisticRegression(penalty=spec['penalty'],
                                                       C=spec['C'],
                                                       solver='liblinear')
    elif spec['type'] == 'SVM':
        gamma = spec['kernel']['gamma'] if spec['kernel']['type'] == 'RBF' else 'auto'
        return sklearn.svm.SVC(C=spec['C'],
                               kernel=spec['kernel']['type'],
                               gamma=gamma,
                               probability=True)
    elif spec['type'] == 'RandomForest':
        return sklearn.ensemble.RandomForestClassifier(n_estimators=int(spec['n_estimators']),
                                                       criterion=spec['criterion'],
                                                       n_jobs=n_jobs)
    elif spec['type'] == 'AdaBoost':
        return sklearn.ensemble.AdaBoostClassifier(n_estimators=int(spec['n_estimators']))
    else:
        raise ValueError("invalid classifier type in spec: %s" % str(spec))

def evaluate_classifier(classifier, x_test, y_test, id_test) -> dict:
    y_prob = classifier.predict_proba(x_test)[:,1] # probability of class 1, i.e. vulnerable
    y_pred = np.round(y_prob)
    return dict(
        roc_auc=sklearn.metrics.roc_auc_score(y_test, y_prob),
        average_precision=sklearn.metrics.average_precision_score(y_test, y_prob),
        precision=sklearn.metrics.precision_score(y_test, y_pred),
        recall=sklearn.metrics.recall_score(y_test, y_pred),
        f1=sklearn.metrics.f1_score(y_test, y_pred),
        accuracy=sklearn.metrics.accuracy_score(y_test, y_pred),
        confusion_matrix=sklearn.metrics.confusion_matrix(y_test, y_pred).tolist(),
        examples=[(id_test[i], int(y_test[i]), float(y_prob[i])) for i in range(len(id_test))]
    )


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.utils import resample
from scipy.ndimage import gaussian_filter
from scipy import signal
import cv2

## plot the data classes as a circle to view the unbalance between the classes
def plot_num_of_classes(labels):
    plt.figure(figsize=(20, 10))
    my_circle = plt.Circle((0,0), 0.7, color="white")
    plt.pie(labels, labels= ['n', 'q', 'v', 's', 'f'], colors=
            ['red', 'green', 'blue', 'skyblue', 'orange'], autopct='%1.1f%%')
    p = plt.gcf()
    p.gca().add_artist(my_circle)
    plt.show()

## split the data into train, validation, and test
## validation and test each class has 100 samples
## input_size of the sample in the dataset
def split(dataset, input_size=256):

    input_size = input_size + 1   # plus the label
    test_label = []
    validation_label = []

    validation = []
    test = []
    train_index = []
    num_train_index = 0
    ## seed the split algorithm
    np.random.seed(0)
    ## for validation and test dataset which has 100 samples for each class
    num_classes = 5
    for i in range(num_classes):
        ind = np.where(dataset[:, -1] == i)[0]  ## return index
        print('number of class :', len(ind))

        idx = np.random.permutation(ind)
        rest = idx[:200]
        train_idx = idx[200:]
        print('number of train data per class', len(train_idx))
        train_index.append(train_idx)
        #         train.append(ecgsignal[train_idx, :])
        validation.append(dataset[rest[:100], :-1])
        test.append(dataset[rest[100:], :-1])

        validation_label.append(dataset[rest[:100], -1])
        test_label.append(dataset[rest[100:], -1])
        #         train_label.append(target[train_idx]) ### training data needs to be noted the number of dataset
        num_train_index += len(train_index[i])
        print(len(train_index[i]))
    train = np.zeros((num_train_index, input_size))
    train_label = np.zeros((num_train_index, 1))

    train[0:len(train_index[0]), :] = dataset[train_index[0], :]
    culm = len(train_index[0]) + len(train_index[1])
    train[len(train_index[0]):culm, :] = dataset[train_index[1], :]
    train[culm:(culm + len(train_index[2])), :] = dataset[train_index[2], :]
    culm += len(train_index[2])
    train[culm:(culm + len(train_index[3])), :] = dataset[train_index[3], :]
    culm += len(train_index[3])
    train[culm:(culm + len(train_index[4])), :] = dataset[train_index[4], :]
    culm = len(train_index[0]) + len(train_index[1])
    train_label[0:len(train_index[0]), 0] = dataset[train_index[0], -1]
    train_label[len(train_index[0]):culm, 0] = dataset[train_index[1], -1]
    train_label[culm:(culm + len(train_index[2])), 0] = dataset[train_index[2], -1]
    culm += len(train_index[2])
    train_label[culm:(culm + len(train_index[3])), 0] = dataset[train_index[3], -1]
    culm += len(train_index[3])
    train_label[culm:(culm + len(train_index[4])), 0] = dataset[train_index[4], -1]

    validation = np.concatenate(validation, 0)
    test = np.concatenate(test, 0)
    test_label = np.concatenate(test_label, 0)
    validation_label = np.concatenate(validation_label, 0)
    return (train, train_label), (validation, validation_label), (test, test_label)

## upsample function
## due to the unbalance of the classes
### according to https://elitedatascience.com/imbalanced-classes
def upsample(train, upsample_size=10000):
    df_1 = train[train[:, -1] == 1]
    df_2 = train[train[:, -1] == 2]
    df_3 = train[train[:, -1] == 3]
    df_4 = train[train[:, -1] == 4]
    idxs = np.random.choice(train[train[:, -1] == 0].shape[0], upsample_size, replace=False)
    df_0 = train[idxs]
    #df_0 = (train[train_label == 0]).sample(n=20000, random_state=42)
    df_1 = pd.DataFrame(df_1)
    df_2 = pd.DataFrame(df_2)
    df_3 = pd.DataFrame(df_3)
    df_4 = pd.DataFrame(df_4)
    df_0 = pd.DataFrame(df_0)
    df_1_upsample = resample(df_1, replace=True, n_samples=upsample_size, random_state=123)
    df_2_upsample = resample(df_2, replace=True, n_samples=upsample_size, random_state=124)
    df_3_upsample = resample(df_3, replace=True, n_samples=upsample_size, random_state=125)
    df_4_upsample = resample(df_4, replace=True, n_samples=upsample_size, random_state=126)
    train_df = pd.concat([df_0, df_1_upsample, df_2_upsample, df_3_upsample, df_4_upsample])
    return train_df

def ecg2fig(data):
    data = data.reshape(data.shape[0], data.shape[1])
    imgs = np.zeros((data.shape[0], 128, 128), dtype='uint8')
    for i in range(data.shape[0]):
        fig = plt.figure(frameon=False)
        plt.plot(data[i])
        plt.xticks([]), plt.yticks([])
        for spine in plt.gca().spines.values():
            spine.set_visible(False)
        # redraw the canvas
        fig.canvas.draw()

        # convert canvas to image
        img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
        img  = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
        # img is rgb, convert to opencv's default bgr
        img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#         im_gray = cv2.imread(img, cv2.IMREAD_GRAYSCALE)
        im_gray = cv2.resize(img, (128, 128), interpolation = cv2.INTER_LANCZOS4)
        imgs[i] = im_gray
        plt.close(fig)
    return imgs

def spectrogram(data):
    data = data.reshape(data.shape[0], data.shape[1])
#     img = np.zeros((data.shape[0], 129, 1), dtype='uint8')
    fs = 360
    f, t, Sxx = signal.spectrogram(data, fs=fs)
    print(Sxx.shape)
    Sx = Sxx[:, :, 0]
    print(Sx.shape)
    return Sx, Sxx


from typing import Any

import structlog

from confluent_kafka_helpers.message import Message

from eventsourcing_helpers import metrics
from eventsourcing_helpers.handler import Handler
from eventsourcing_helpers.utils import get_callable_representation

logger = structlog.get_logger(__name__)

class EventHandler(Handler):
    """
    Application service that calls the correct domain handler for an event.
    """

    def _can_handle_command(self, message: Message) -> bool:
        """
        Checks if the event is something we can handle.

        Args:
            message: Consumed message from the bus.

        Returns:
            bool: Flag to indicate if we can handle the event.
        """
        event_class = message.value['class']
        if event_class not in self.handlers:
            logger.debug("Unhandled event", event_class=event_class)
            return False

        return True

    def _handle_event(self, event: Any) -> None:
        """
        Get and call the correct event handler.

        Args:
            event: Event to be handled.
        """
        handler = self.handlers[event._class]

        handler_name = get_callable_representation(handler)
        handler_wrapper = metrics.timed(
            'eventsourcing_helpers.handler.handle',
            tags=['message_type:event', f'message_class:{event._class}', f'handler:{handler_name}']
        )(handler)

        handler_wrapper(event)

    def handle(self, message: dict) -> None:
        """
        Apply correct handler for received event.

        Args:
            message: Consumed message from the bus.
        """
        if not self._can_handle_command(message):
            return

        event = self.message_deserializer(message)
        logger.info("Handling event", event_class=event._class)

        self._handle_event(event)


from selenium import webdriver
import time
import os
import sys
class ebabot():
    def giris(self):
        self.browserprofile=webdriver.ChromeOptions()
        self.browserprofile.add_experimental_option('prefs',{'intl.accpet_languages':'en,en_US'})
        self.browser=webdriver.Chrome('chromedriver.exe',chrome_options=self.browserprofile)
        self.girisurl="https://giris.eba.gov.tr/EBA_GIRIS/giris.jsp"
        self.canli_dersurl="https://ders.eba.gov.tr/ders/proxy/VCollabPlayer_v0.0.772/index.html#/main/livesessionview?tab=liveLessons&pageNumber=1&pageSize=25"
        self.tc="tc"
        self.sifre="sifre"
        self.browser.get(self.girisurl)
        self.tcarea=self.browser.find_element_by_xpath("//*[@id='tckn']").send_keys(self.tc)
        self.passarea=self.browser.find_element_by_xpath("/html/body/div[2]/div/div[1]/div/div[2]/form/div[3]/div/input").send_keys(self.sifre)
        time.sleep(1)
        self.submit=self.browser.find_element_by_xpath("/html/body/div[2]/div/div[1]/div/div[2]/form/div[5]/button").click()
        time.sleep(3)
        self.browser.get(self.canli_dersurl)
        time.sleep(3)
    def tikla(self):
        self.tikla=self.browser.find_element_by_xpath("/html/body/div[1]/div[1]/div/div/div[1]/div/div[3]/div/div/div[2]/div/div[3]/div/div[3]/div[2]/div[2]/div/table/tbody/tr/td/div[2]/div/div[3]/table/tbody/tr/td[3]/div/div[2]/div[1]").click()
        time.sleep(3)
    def bot(self):

        self.katil=self.browser.find_element_by_xpath("/html/body/div[1]/div[1]/div/div/div[1]/div/div[3]/div/div/div[2]/div[1]/div/div/div/div[3]/div").get_attribute("class")
        if self.katil=="btn btn-md ng-binding btn-success disabled":
            print("katıl kapalı")
            time.sleep(10)
            self.browser.refresh()
            time.sleep(10)
            return False
        else:
            print("katıl açık")
            time.sleep(5)
            return True
    def derse_gir(self):
        print("derse girildi")
    def kappa(self):
        self.browser.close()

bot=ebabot()
bot.giris()
bot.tikla()
while True:
    bot.bot()
    if bot.bot==True:
        print("katıl aççık")
        break
    else:
        print("katıl kapalı")
        time.sleep(10)
bot.derse_gir()
bot.kappa()
os.execl(sys.executable, os.path.abspath(__file__), *sys.argv)


"""
自定义返回处理
"""

from rest_framework.renderers import JSONRenderer

class CustomerRenderer(JSONRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        print('CustomerRenderer data:', data)
        print('accepted_media_type:', accepted_media_type)
        print('renderer_context:', renderer_context)
        if renderer_context:
            detail = None
            # 如果返回的data为字典
            if isinstance(data, dict):
                message = data.pop('errorCode', 'success')
                detail = None
                if 'errorDetail' in data:
                    detail = data.pop('errorDetail')
                code = data.pop('code', renderer_context['response'].status_code)
            # 如果不是字典则将msg内容改为请求成功 code改为请求的状态码
            else:
                message = 'success'
                detail = None
                code = renderer_context['response'].status_code

            ret = {
                'errorCode': message,
                'errorDetail': detail,
                'code': code,
                'data': data
            }
            return super().render(ret, accepted_media_type, renderer_context)

        else:
            return super().render(data, accepted_media_type, renderer_context)


"""
views related to application user
"""

from django.contrib import messages
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse

from .forms import ProfileForm

def user_profile(request):
    """ return user profile """
    return render(
        request, 'User/profile.html', {})

def user_profile_edit(request):
    """ return page to edit user profile """

    user = request.user

    if request.method == 'POST':
        form = ProfileForm(request.POST)

        if 'save' in request.POST and form.is_valid():
            data = form.cleaned_data
            user.first_name = data['first_name']
            user.last_name = data['last_name']
            user.climber.middle_name = data['middle_name']
            user.climber.save()
            user.save()

            messages.success(request, 'Profile details updated.')

        return HttpResponseRedirect(reverse('user-profile'))

    data = {
        'username': user.username,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'middle_name': user.climber.middle_name,
    }
    form = ProfileForm(initial=data)

    return render(
        request, 'User/profile_edit.html', {'form': form})


#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author:jingtongyu
# datetime:2020/6/7 10:14 下午
# software: PyCharm

from flask import g
from flask_restful import Resource, inputs
from flask_restful.reqparse import RequestParser
from sqlalchemy.exc import SQLAlchemyError
from app import hash_ids
from common.utils import get_order_code
from common import code, pretty_result
from models.orders import OrdersModel
from models.products import ProductsModel
from models.mallUsers import MallUsersModel
from common.decorators import login_required
import math
import time
from config import setting

class OrdersResource(Resource):
    """
    示例orders list资源类
    """

    def __init__(self):
        self.parser = RequestParser()

    @login_required
    def get(self):
        self.parser.add_argument("email", type=inputs.regex(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)'),
                                 required=True, location="args",
                                 help='email format is incorrect')
        self.parser.add_argument("status", type=str, required=True, location="args",
                                 help='status format is incorrect')
        self.parser.add_argument("pageNo", type=int, required=True, location="args",
                                 help='pageNo format is incorrect')
        self.parser.add_argument("pageSize", type=int, required=True, location="args",
                                 help='pageSize format is incorrect')
        args = self.parser.parse_args()
        if args.status == "all":
            orderInfo = OrdersModel.paginate(OrdersModel, args.pageNo, args.pageSize)
        elif args.status == "noDelivery":
            orderInfo = OrdersModel.paginate_by_status(OrdersModel,'noDelivery', args.pageNo, args.pageSize)
        else:
            orderInfo = OrdersModel.paginate_by_status(OrdersModel,'delivered', args.pageNo, args.pageSize)
        data=[]
        if orderInfo.items:
            for item in orderInfo.items:
                OrderItemVOS = []
                productList = item.productList.split(',')
                for i in productList:
                    productInfo = ProductsModel.query.filter_by(id=i).first()
                    OrderItemVOS.append(productInfo.to_dict())
                data.append({
                    'no': item.no,
                    'totalPrice': item.totalPrice,
                    'username': item.username,
                    'phone': item.phone,
                    'payType': item.payType,
                    'status': item.status,
                    'productList': item.productList,
                    'addressId': item.addressId,
                    'createTime': item.createTime,
                    'OrderItemVOS': OrderItemVOS
                })
        totalCount = len(data)
        result = {
            'pageNo': args.pageNo,
            'pageSize': args.pageSize,
            'totalCount': totalCount,
            'items': data,
            'totalPage': math.ceil(totalCount/args.pageSize)
        }
        return pretty_result(code.OK, data=result, msg="get order info successful!")

    @login_required
    def post(self):
        self.parser.add_argument("email", type=inputs.regex(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)'),
                                 required=True, location="json",
                                 help='email format is incorrect')
        self.parser.add_argument("totalPrice", type=int, required=True, location="json", help='totalPrice format is incorrect')
        self.parser.add_argument("username", type=str, required=True, location="json",
                                 help='username format is incorrect')
        self.parser.add_argument("phone", type=str, required=True, location="json",
                                 help='phone format is incorrect')
        self.parser.add_argument("payType", type=str, required=True, location="json",
                                 help='payType format is incorrect')
        self.parser.add_argument("productList", type=list, required=True, location="json",
                                 help='productList format is incorrect')
        self.parser.add_argument("addressId", type=str, required=True, location="json",
                                 help='addressId format is incorrect')
        args = self.parser.parse_args()
        mallUsersInfo = MallUsersModel.query.filter_by(email=args.email).first()
        if mallUsersInfo.balance < args.totalPrice:
            return pretty_result(code.ERROR, msg="create order failed, balance ont enough!")
        else:
            for i in args.productList:
                proudctInfo = ProductsModel.query.filter_by(id=i).first()
                proudctInfo.status = "solded"
                ProductsModel.update(proudctInfo)
            mallUsersInfo.balance = mallUsersInfo.balance - args.totalPrice
            MallUsersModel.update(mallUsersInfo)
        order = OrdersModel(email=args.email,no=get_order_code(), username=args.username, totalPrice=args.totalPrice, phone=args.phone.replace("-", ""),
                                couponPrice=0, payType=args.payType, status="noDelivery", productList=','.join([str(x) for x in args.productList]),
                                addressId=args.addressId)
        OrdersModel.add(OrdersModel, order)
        return pretty_result(code.OK, msg="create order info successful!")

    @login_required
    def put(self):
        self.parser.add_argument("no", type=inputs.regex(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)'),
                                 required=True, location="json",
                                 help='no format is incorrect')
        self.parser.add_argument("status", type=str, required=True, location="json",
                                 help='status format is incorrect')
        args = self.parser.parse_args()
        orderInfo = OrdersModel.query.filter_by(no=args.no).first()
        orderInfo.status = args.status
        OrdersModel.update(orderInfo)
        return pretty_result(code.OK, msg="update order status info successful!")

class OrdersByNoResource(Resource):
    """
    示例orders list资源类
    """

    def __init__(self):
        self.parser = RequestParser()

    @login_required
    def get(self):
        self.parser.add_argument("no", type=str, required=True, location="args",
                                 help='no format is incorrect')
        args = self.parser.parse_args()
        orderInfo = OrdersModel.query.filter_by(no=args.no).first()
        OrderItemVOS = []
        productList = orderInfo.productList.split(',')
        for i in productList:
            productInfo = ProductsModel.query.filter_by(id=i).first()
            OrderItemVOS.append(productInfo.to_dict())
        data ={
            'no': orderInfo.no,
            'totalPrice': orderInfo.totalPrice,
            'phone': orderInfo.phone,
            'payType': orderInfo.payType,
            'status': orderInfo.status,
            'productList': orderInfo.productList,
            'addressId': orderInfo.addressId,
            "createTime": orderInfo.createTime,
            'OrderItemVOS': OrderItemVOS
        }
        return pretty_result(code.OK, data=data, msg="get order info successful!")


from django.http import HttpResponse
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.views import APIView
from django_filters.rest_framework import DjangoFilterBackend
from .serializers import *

class CountryList(generics.ListAPIView):
    queryset = Country.objects.all()
    serializer_class = CountrySerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['Name', 'Code']

class StateList(generics.ListAPIView):
    queryset = State.objects.all()
    serializer_class = StateSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['Name']

class AddressList(generics.ListAPIView):
    queryset = Address.objects.all()
    serializer_class = AddressSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['HouseNo', 'RoadNo']

class DetailAddressList(generics.ListAPIView):
    queryset = Address.objects.all()
    serializer_class = DetailAddressSerializer


#!/usr/bin/env python3

class Animal(object):
    def __init__(self):
        self.__age = 3
    @property
    def age(self):
        return self.__age
    @age.setter
    def age(self, value):
        if isinstance(value, int):
            self.__age = value
        else:
            raise ValueError
    @age.deleter
    def age(self):
        print('delete age')
        del self.__age

if __name__ == '__main__':
    cat = Animal()
    print('Initial value of cat.age\n')
    print(cat.age)
    cat.age = 6
    print('Change cat.age as \'cat.age = 6\'')
    print(cat.age)
    del cat.age
    print('After delete cat.age\n')
    print(cat.age)


# Use of for loop in calculating love score
# Instructions: https://replit.com/@terrykirungo/8-love-score-using-loop

# ðŸš¨ Don't change the code below ðŸ‘‡
print("Welcome to the Love Calculator!")
name1 = input("What is your name? \t")
name2 = input("What is their name? \t")
# ðŸš¨ Don't change the code above ðŸ‘†

#Write your code below this line ðŸ‘‡

#Converts names to UPPERCASE
new_name1 = name1.upper()
new_name2 = name2.upper()

#concatenates the two names to form one name
both_names = new_name1 + new_name2

#Initializes the counts of the number of times the letters of the word TRUE appear in the combined(Concatenated name)
true_count = 0

##Initializes the counts of the number of times the letters of the word LOVE appear in the combined(Concatenated name)
love_count = 0

#Loops through the combined name checking how many times the letters of the word TRUE appears. Everytime it appears true_count is increased by 1
for letter in both_names:
    if letter == "T":
        true_count = true_count + 1
    elif letter == "R":
        true_count = true_count + 1
    elif letter == "U":
        true_count = true_count + 1
    elif letter == "E":
        true_count = true_count + 1
#prints the total number of times the letters of TRUE appear in the combined name
print(true_count)

#Loops through the combined name checking how many times the letters of the word LOVE appears. Everytime it appears love_count is increased by 1
for character in both_names:
    if character == "L":
        love_count = love_count + 1
    elif character == "O":
        love_count = love_count + 1
    elif character == "V":
        love_count = love_count + 1
    elif character == "E":
        love_count = love_count + 1

# prints the total number of times the letters of LOVE appear in the combined name
print(love_count)

#Concatenates the love_score through conversion to str, e.g 5 and 8 become 58
love_score = str(true_count) + str(love_count)

#Converts the total love score to int
total_score = int(love_score)

#Checks the compatibility of the two people through their name
if total_score < 10 or total_score > 90:
    print(f"Your score is {total_score}, you go together like coke and mentos.")
elif total_score > 40 and total_score < 50:
    print(f"Your score is {total_score}, you are alright together.")
else:
    print(f"Your score is {total_score}.")

# Test it here: https://replit.com/@terrykirungo/8-love-score-using-loop#main.py


import json
import pandas as pd

def create_csv(file, header):
    with open(file, "r", encoding="utf-8") as json_file:
        data = json.load(json_file)
    df = pd.DataFrame(data, columns=header)
    file_name = file[:len(file) - 4] + "csv"
    df.to_csv(file_name, sep='\t', encoding='utf-8')

if __name__ == '__main__':
    create_csv("sources/result_hb.json", ["item_name", "item_url", "item_phones_list", "item_address", "item_site"])
    create_csv("sources/result_vl.json", ["item_name", "item_url", "item_phones_list", "item_address", "item_site"])
    create_csv("sources_dvhub/result_hb.json",
               ["item_name", "item_url", "item_email", "item_phone", "item_address", "item_site"])
    create_csv("sources_dvhub/result_vl.json",
               ["item_name", "item_url", "item_email", "item_phone", "item_address", "item_site"])


import sys
import os
from datetime import datetime, timedelta

import click
from xhtml2pdf import pisa
from jinja2 import Template

from trkr.data.connect import get_connection
from trkr.data.read import get_invoice_items

TEMPLATE_DIR = os.path.dirname(__file__) + '/../templates/'
REPORT_TEMPLATE = os.path.join(TEMPLATE_DIR, 'report.html')

TODAY = datetime.today()
TODAY_STR = TODAY.strftime('%Y-%m-%d')
THIRTY_DAYS_BACK = TODAY - timedelta(30)
THIRTY_DAYS_BACK_STR = THIRTY_DAYS_BACK.strftime('%Y-%m-%d')

@click.command()
@click.argument('output', nargs=1)
@click.option('-c', '--company-name', default=None,
              help='Company name to display on invoice')
@click.option('-i', '--invoice-id', default=None,
              help='ID to associate with the invoice')
@click.option('-t', '--client-name', default=None,
              help='Company to bill invoice to')
@click.option('--addr-line-1', default=None,
              help='Company name address line 1')
@click.option('--addr-line-2', default=None,
              help='Company name address line 2')
@click.option('--from-date', default=THIRTY_DAYS_BACK_STR, type=click.DateTime(),
              help='Beginning date for invoice (default, 30 days ago)')
@click.option('--to-date', default=TODAY_STR, type=click.DateTime(),
              help='Beginning date for invoice (default, today)')
@click.option('--hourly-rate', default=0, type=float,
              help='Hourly rate to charge across projects (defaults to 0)')
def report(**kwargs):
    """Generate reports from work logs"""
    output = kwargs.get('output', '')

    if not os.path.basename(output).lower().endswith('pdf'):
        click.echo("Please give output file *.pdf extension")
        sys.exit(1)

    conn = get_connection()
    cur = conn.cursor()

    with open(REPORT_TEMPLATE) as template:
        source_html = template.read()

    invoice_items = get_invoice_items(
        cur, kwargs.get('client_name'), kwargs.get('from_date'), kwargs.get('to_date')
    )
    today = datetime.today()
    today_str = today.strftime('%x')
    from_str = kwargs.get('from_date').strftime('%x')
    to_str = kwargs.get('to_date').strftime('%x')
    hourly_rate = kwargs.get('hourly_rate')
    total_amount = sum(x[1] * hourly_rate for x in invoice_items)
    total_hours = sum(x[1] for x in invoice_items)
    template = Template(source_html)
    html = template.render(
        invoice_items=invoice_items, today_str=today_str,
        from_str=from_str, to_str=to_str, total_amount=total_amount,
        total_hours=total_hours,
        **kwargs
    )

    with open(output, "w+b") as result_file:
        status = pisa.CreatePDF(
            html,
            dest=result_file
        )

    if status.err:
        click.echo("Errors while creating pdf")
        sys.exit(1)


"""

문제 유형 BFS, DFS

이번에는 DFS로 풀어보자.

가로, 세로, 대각선으로 연결되어 있다.

"""

import sys

input = sys.stdin.readline

sys.setrecursionlimit(10000)

def dfs(y,x) :
    visited[y][x] = 1

    for i in range(8) :
        ny = y + dy[i]
        nx = x + dx[i]

        if 0 <= ny < h and 0 <= nx < w :
            if board[ny][nx] == 1 and visited[ny][nx] == 0 :
                visited[ny][nx] = 1
                dfs(ny, nx)

while True :

    w, h = map(int, input().split())

    if w == 0 and h == 0 :
        break

    board = []

    for _ in range(h) :
        board.append(list(map(int, input().split())))

    dx = [1,1,0,-1,-1,-1,0,1]
    dy = [0,-1,-1,-1,0,1,1,1]

    visited = [[0] * w for _ in range(h)]

    answer = 0

    for i in range(h) :
        for j in range(w) :
            if board[i][j] == 1 and visited[i][j] == 0 :
                visited[i][j] = 1
                dfs(i,j)
                answer += 1

    print(answer)

AlgorithmStudy/백준/무지성 랜덤풀이/8월/8.28/4963 섬의 개수.py


# Instructions

# Write a program that calculates the Body Mass Index (BMI) from a user's weight and height.

# The BMI is a measure of someone's weight taking into account their height. e.g. If a tall person and a short person both weigh the same amount, the short person is usually more overweight.

# The BMI is calculated by dividing a person's weight (in kg) by the square of their height (in m):

# Warning you should convert the result to a whole number.
# Example Input

# weight = 80
# height = 1.75

# Example Output

# 80 ÷ (1.75 x 1.75) = 26.122448979591837
# 26

# BMI = WEIGHT(KG)/HEIGHT**2(m**2)

print("welcome to BMI Calculator")

weight = input("Please enter your weight = ")
height = input("Please enter your height = ")

bmi = int(weight) / float(height) ** 2
bmi_as_int = int(bmi)
print(bmi_as_int)


# -*- coding:utf-8 -*-
"""
@author:SiriYang
@file:urls.py
@time:2018/11/27 17:31
"""
from django.urls import path, re_path
from django.contrib.staticfiles.urls import staticfiles_urlpatterns

from . import views

urlpatterns = [
    re_path(r'^$', views.signin, name='signin'),
    re_path(r'^signin/$', views.signin_action, name='signin_action'),
    re_path(r'^mainpage$', views.mainpage, name='mainpage'),
    re_path(r'^student(?P<order>s_.*)/$', views.student, name='student'),
    re_path(r'^student/edit/(?P<s_no>[0-9]+)/$', views.student_edit, name='student_edit'),
    re_path(r'^student/edit/action$', views.student_edit_action, name='student_edit_action'),
    re_path(r'^student/delete/(?P<s_no>[0-9]+)/$', views.student_delete, name='student_delete'),
    re_path(r'^course/(?P<order>c_.*)/$', views.course, name='course'),
    re_path(r'^course/edit/(?P<c_no>[0-9]+)/$', views.course_edit, name='course_edit'),
    re_path(r'^course/edit/action$', views.course_edit_action, name='course_edit_action'),
    re_path(r'^course/delete/(?P<c_no>[0-9]+)/$', views.course_delete, name='course_delete'),
    re_path(r'^score/student/(?P<s_no>[0-9]+)/(?P<order>mainsite.*)/$', views.score_student, name='score_student'),
    re_path(r'^score/student/edit/(?P<s_no>[0-9]+)/(?P<c_no>[0-9]+)/$', views.score_student_edit,name='score_student_edit'),
    re_path(r'^score/student/edit/action$', views.score_student_edit_action,name='score_student_edit_action'),
    re_path(r'^score/student/add/(?P<s_no>[0-9]+)$', views.score_student_add,name='score_student_add'),
    re_path(r'^score/student/add/action$', views.score_student_add_action,name='score_student_add_action'),
    re_path(r'^score/student/delete/(?P<s_no>[0-9]+)/(?P<c_no>[0-9]+)/$', views.score_student_delete,name='score_student_delete'),
    re_path(r'^score/course/(?P<c_no>[0-9]+)/(?P<order>mainsite.*)/$', views.score_course, name='score_course'),
    re_path(r'^score/course/edit/(?P<c_no>[0-9]+)/(?P<s_no>[0-9]+)/$', views.score_course_edit,name='score_course_edit'),
    re_path(r'^score/course/edit/action$', views.score_course_edit_action,name='score_course_edit_action'),
    re_path(r'^score/course/add/(?P<c_no>[0-9]+)$', views.score_course_add,name='score_course_add'),
    re_path(r'^score/course/add/action$', views.score_course_add_action,name='score_course_add_action'),
    re_path(r'^score/course/delete/(?P<c_no>[0-9]+)/(?P<s_no>[0-9]+)/$', views.score_course_delete,name='score_course_delete'),
]

urlpatterns += staticfiles_urlpatterns()


# pygame
import pygame
from pygame.event import Event
from pygame.time import Clock
from pygame.surface import Surface
# numpy
import numpy as np
# numba
import numba
# standard
import os
from enum import Enum
import logging
# project
from player import Player
from game_map import Map
from data_manager import DataManager
from utility import rotation_matrix
from vector import Vector2
from map_renderer import MapRenderer
from game_renderer import GameRenderer
from ui_renderer import UIRenderer
from sprite import Sprite
from game_object import GameObject
from rat import Rat
from skeleton import Skeleton
from enemy import Enemy
from enemy_manager import EnemyManager
# typing
from typing import Callable

class RaycastInfo:
    def __init__(self, hit: bool, perp_wall_dist: float, collision: Vector2, ns_wall: bool, map_position: tuple[int, int]):
        self.hit = hit
        self.perp_wall_dist: float = perp_wall_dist
        self.collision: Vector2 = collision
        self.ns_wall: bool = ns_wall
        self.map_position: tuple[int, int] = map_position

@numba.jit(nopython=True)
def raycast(origin_x: float, origin_y: float, direction_x: float, direction_y: float, game_map: Map, distance: float = np.inf):
    # from https://lodev.org/cgtutor/raycasting.html

    map_x = int(origin_x)
    map_y = int(origin_y)

    delta_dist_x = np.inf if direction_x == 0 else abs(1 / direction_x)
    delta_dist_y = np.inf if direction_y == 0 else abs(1 / direction_y)

    if direction_x < 0:
        step_x = -1
        side_dist_x = delta_dist_x * (origin_x - map_x)
    else:
        step_x = 1
        side_dist_x = delta_dist_x * (map_x + 1 - origin_x)
    if direction_y < 0:
        step_y = -1
        side_dist_y = delta_dist_y * (origin_y - map_y)
    else:
        step_y = 1
        side_dist_y = delta_dist_y * (map_y + 1 - origin_y)

    hit = False
    ns_wall = True

    while not hit:
        if side_dist_x < side_dist_y:
            side_dist_x += delta_dist_x
            map_x += step_x
            ns_wall = True
        else:
            side_dist_y += delta_dist_y
            map_y += step_y
            ns_wall = False

        if ns_wall and side_dist_x - delta_dist_x > distance or not ns_wall and side_dist_y - delta_dist_y > distance:
            return False, None, None, None, None

        if map_x < 0 or map_x >= game_map.shape[1] or map_y < 0 or map_y >= game_map.shape[0]:
            return False, np.inf, (np.inf, np.inf), ns_wall, (map_x, map_y)

        hit = game_map[map_y, map_x] != 0

    if ns_wall:
        perp_wall_dist = side_dist_x - delta_dist_x
    else:
        perp_wall_dist = side_dist_y - delta_dist_y

    return (True,
            perp_wall_dist,
            (origin_x + direction_x * perp_wall_dist, origin_y + direction_y * perp_wall_dist),
            ns_wall,
            (map_x, map_y))

game_logger = logging.getLogger("game")

class RaycastingGame:
    class DrawMode(Enum):
        GAME = 0
        MAP = 1
        TITLE = 2
        GAMEOVER = 3

    class GameMode(Enum):
        UI = 0
        GAME = 1

    MOUSE_SPEED_FACTOR = 0.005
    WINDOW_TITLE: str = "Necrom"
    MUSIC_FILENAME: str = "twisting.mp3"

    DrawMethod = Callable[[Surface], None]
    UpdateMethod = Callable[[float], None]
    EventAction = Callable[[Event], None]

    def __init__(self, data: DataManager):
        self.data: DataManager = data

        self.clock: Clock = Clock()
        self.running: bool = False
        self.map: Map = self.data.maps["main"]
        self.player: Player = Player(
            self.data.config,
            self,
            position=np.array(self.map.shape, dtype=float) / 1.5,
        )
        self.sprites: list[Sprite] = []
        self.game_objects: list[GameObject] = []
        self.enemies: list[Enemy] = []
        Rat(np.array([5.5, 5.5], dtype=float), self).bind(self)
        Rat(np.array([2.5, 2.5], dtype=float), self).bind(self)
        Rat(np.array([11.5, 14.5], dtype=float), self).bind(self)
        self.map_renderer: MapRenderer = MapRenderer(self.map, self.player, self.sprites)
        self.game_renderer: GameRenderer = GameRenderer(self, self.data.textures["dusk-sky"].texture)
        self.ui_renderer: UIRenderer = UIRenderer(self)
        self.enemy_manager: EnemyManager = self.create_enemy_manager()
        self.game_mode: RaycastingGame.GameMode = RaycastingGame.GameMode.UI
        self.update_mode_map: dict[RaycastingGame.GameMode, RaycastingGame.UpdateMethod] = {
            RaycastingGame.GameMode.GAME: self.update_game,
            RaycastingGame.GameMode.UI: self.update_ui,
        }
        self.draw_mode: RaycastingGame.DrawMode = RaycastingGame.DrawMode.TITLE
        self.draw_mode_map: dict[RaycastingGame.DrawMode, RaycastingGame.DrawMethod] = {
            RaycastingGame.DrawMode.GAME: self.game_renderer.draw,
            RaycastingGame.DrawMode.MAP: self.map_renderer.draw,
            RaycastingGame.DrawMode.TITLE: self.ui_renderer.draw_title,
            RaycastingGame.DrawMode.GAMEOVER: self.ui_renderer.draw_gameover,
        }
        self.key_map: dict[int, RaycastingGame.EventAction] = {
            pygame.K_ESCAPE: self.handle_quit,
            pygame.K_m: self.handle_toggle_map,
        }

    def create_enemy_manager(self) -> EnemyManager:
        empty_position = np.empty((2, ), dtype=float)
        waves = [
            [
                Skeleton(empty_position, self),
                Skeleton(empty_position, self),
                Skeleton(empty_position, self)
            ],
            [
                Skeleton(empty_position, self),
                Skeleton(empty_position, self),
                Skeleton(empty_position, self)
            ]
        ]
        spawn_locations = [
            np.array([2.5, 2.5], dtype=float),
            np.array([9.5, 1.5], dtype=float),
            np.array([13.5, 3.5], dtype=float),
            np.array([2.5, 13.5], dtype=float),
            np.array([11.5, 14.5], dtype=float),
        ]
        for location in spawn_locations:
            self.sprites.append(Sprite(location, [self.data.textures["gravestone"]], height_offset=-0.2))
        return EnemyManager(self, spawn_locations, waves)

    def start_game(self):
        self.player: Player = Player(
            self.data.config,
            self,
            position=np.array(self.map.shape, dtype=float) / 1.5,
        )
        self.sprites: list[Sprite] = []
        self.game_objects: list[GameObject] = []
        self.enemies: list[Enemy] = []
        Rat(np.array([5.5, 5.5], dtype=float), self).bind(self)
        Rat(np.array([2.5, 2.5], dtype=float), self).bind(self)
        Rat(np.array([11.5, 14.5], dtype=float), self).bind(self)
        self.map_renderer.player = self.player
        self.map_renderer.sprites = self.sprites
        self.enemy_manager: EnemyManager = self.create_enemy_manager()
        self.game_mode_game()

    def game_over(self):
        self.game_mode_ui()
        self.draw_mode = RaycastingGame.DrawMode.GAMEOVER

    def quit(self):
        self.running = False
        self.data.save_config()

    def handle_quit(self, event: Event):
        if event.type == pygame.KEYUP:
            return
        escape_behaviour = self.data.config.get("Behaviour", "escape_behaviour")
        if escape_behaviour == "quit":
            self.quit()
        elif escape_behaviour == "unlock mouse":
            pygame.mouse.set_visible(True)
            pygame.event.set_grab(False)
        else:
            game_logger.warning("Escape behaviour configuration not recognised. Defaulting to quit.")
            self.quit()

    def handle_toggle_map(self, event: Event):
        if event.type == pygame.KEYUP:
            return
        if self.draw_mode == RaycastingGame.DrawMode.GAME:
            self.draw_mode = RaycastingGame.DrawMode.MAP
        elif self.draw_mode == RaycastingGame.DrawMode.MAP:
            self.draw_mode = RaycastingGame.DrawMode.GAME

    def process_game_events(self, events: list[Event]):
        for event in events:
            if event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
                if event.key in self.key_map.keys():
                    self.key_map[event.key](event)
            elif event.type == pygame.MOUSEMOTION:
                self.player.rotate(rotation_matrix(event.rel[0] * RaycastingGame.MOUSE_SPEED_FACTOR * self.data.config.getfloat("Input", "mouse_sensitivity")))
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == pygame.BUTTON_LEFT:
                    self.player.attack()

    def process_ui_events(self, events: list[Event]):
        for event in events:
            if event.type == pygame.MOUSEMOTION:
                self.ui_renderer.update_mouse(event.pos)
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == pygame.BUTTON_LEFT:
                    self.ui_renderer.handle_click()

    def resize(self, size):
        self.game_renderer.resize(size)
        self.ui_renderer.resize(size)

    def raycast(self, origin: Vector2, direction: Vector2, distance: float = np.inf) -> RaycastInfo:
        return RaycastInfo(*raycast(origin[0], origin[1], direction[0], direction[1], self.map, distance))

    def update_game(self, delta_time: float):
        self.process_game_events(pygame.event.get())
        self.player.update(delta_time)
        self.enemy_manager.update(delta_time)
        for obj in self.game_objects:
            obj.update(delta_time)

    def update_ui(self, delta_time: float):
        self.process_ui_events(pygame.event.get())

    def update(self, delta_time: float):
        self.update_mode_map[self.game_mode](delta_time)

    def draw(self, surface: Surface):
        self.draw_mode_map[self.draw_mode](surface)

    def init_window(self) -> pygame.Surface:
        video_config = self.data.config["Video"]
        if video_config.getboolean("fullscreen"):
            flags = pygame.FULLSCREEN
            if video_config.getboolean("scaled"):
                window = pygame.display.set_mode((video_config.getint("width"), video_config.getint("height")), flags=flags | pygame.SCALED)
            else:
                window = pygame.display.set_mode((0, 0), flags=flags)
        else:
            window = pygame.display.set_mode((video_config.getint("width"), video_config.getint("height")))

        pygame.display.set_caption(RaycastingGame.WINDOW_TITLE)

        return window

    def game_mode_game(self):
        self.game_mode = RaycastingGame.GameMode.GAME
        self.draw_mode = RaycastingGame.DrawMode.GAME
        pygame.mouse.set_visible(False)
        pygame.event.set_grab(True)

    def game_mode_ui(self):
        self.game_mode = RaycastingGame.GameMode.UI
        pygame.mouse.set_visible(True)
        pygame.event.set_grab(False)

    def mainloop(self):
        window = self.init_window()

        self.resize(window.get_size())

        self.running = True

        self.game_mode_ui()

        self.enemy_manager.start()

        pygame.mixer.music.load(os.path.join(self.data.sounds_path, self.MUSIC_FILENAME))
        pygame.mixer.music.play()

        while self.running:
            self.update(self.clock.tick() / 1000)
            self.draw(window)
            pygame.display.flip()


""""
มีรถไฟอยู่ขบวนหนึ่ง โดยรถไฟนั้นจะมีหมายเลขกำกับตู้แต่ละตู้อยู่และรถไฟก็มีหัวรถจักรอยู่

แต่หัวรถจักรดันไปต่อกับตู้รถไฟอยู่ พี่ต้องการให้น้อง ๆ ทำการแบ่งขบวนรถไฟออก

โดยให้หัวรถจักรอยู่ข้างหน้าสุด และส่วนตู้ที่เหลือให้ทำการต่อกับตู้สุดท้ายโดยไม่มีการเปลี่ยนลำดับของตู้

ซึ่งพี่จะให้หมายเลข 0 แทนเป็นหัวรถจักร ส่วน หมายเลขอื่นจะเป็นตู้รถไฟ

เช่น 2 <- 3 <- 1 <- 0 <- 4 <- 5 <- 6

เป็น 0 <- 4 <- 5 <- 6 <- 2 <- 3 <- 1 ( ให้ใช้ singly linked list)

 *** Locomotive ***
Enter Input : 2 3 1 0 4 5 6
Before : 2 <- 3 <- 1 <- 0 <- 4 <- 5 <- 6
After : 0 <- 4 <- 5 <- 6 <- 2 <- 3 <- 1

 *** Locomotive ***
Enter Input : 5 4 3 2 1 0 9 8 7 6
Before : 5 <- 4 <- 3 <- 2 <- 1 <- 0 <- 9 <- 8 <- 7 <- 6
After : 0 <- 9 <- 8 <- 7 <- 6 <- 5 <- 4 <- 3 <- 2 <- 1

 *** Locomotive ***
Enter Input : 1 0
Before : 1 <- 0
After : 0 <- 1

*** Locomotive ***
Enter Input : 0 1 2 3 4 5 6 7 8 9
Before : 0 <- 1 <- 2 <- 3 <- 4 <- 5 <- 6 <- 7 <- 8 <- 9
After : 0 <- 1 <- 2 <- 3 <- 4 <- 5 <- 6 <- 7 <- 8 <- 9

 *** Locomotive ***
Enter Input : 1 2 3 0
Before : 1 <- 2 <- 3 <- 0
After : 0 <- 1 <- 2 <- 3

 *** Locomotive ***
Enter Input : 2 0 1
Before : 2 <- 0 <- 1
After : 0 <- 1 <- 2

"""
class LinkedList:
    class Node:
        def __init__(self, data, next = None):
            self.data = data
            if next == None:
                self.next = None
            else:
                self.next = next

        def  __str__(self):
            return str(self.data)
    def __init__(self):
        self.head = None
    def append(self, data):
        node = self.Node(data)
        if self.head == None:
            self.head = node
        else:
            t = self.head
            # ตัวแปร ที่มี pointer ชี้ไปยัง node หัว
            while t.next != None: # t ที่ชี้ไปยังตัวถัดไปของ node ปัจจุบัน
            # ถ้า node ต่อไปก็ให้ t ชี้ไปยัง node ต่อไป ทำไปเรื่อยๆ จนเจอ node สุดท้ายที่ไม่มี next
                t = t.next # t ชี้ไปยัง t ตัวต่อไป
            # เมื่อเจอ next ของ node สุดท้ายที่เป็น None หรือไม่มี next ให้ next ของ node สุดท้ายขี้ไปยัง node ที่เพิ่มเข้ามา
            t.next = node  # t ตัวที่ผ่านมาก็จะสร้าง next ที่ชี้ไปยัง node ต่อไป วนทำซ้ำเรื่อยๆจนครบ
            # node ที่พึ่งสร้างมาต่อเป็น node สุดท้าย ดังนั้นทางก็ต้องเป็น node ที่พึ่งสร้าง
    def printList(self):
        t = self.head
        while t.next != None:
            print(t.data,end=" <- ")
            t = t.next
        if t.next == None:
            print(t)
    def switch(self):
        print('Before : ',end="")
        self.printList()
        t = self.head
        if t.data != 0:
            while t.next != None:
                t = t.next
                if t.data == 0:
                    new_head = t
            # หา 0 ให้เจอเพื่อเก็บไว้เป็นหัวใหม่
            t.next = self.head
            while t.next.data != 0:
                t = t.next
            t.next = None
            # หา t.next ว่าเป็น 0 ไหม ถ้าใช่ก็ตัดตัวชี้ทิ้ง
            self.head = new_head
            # เราค่อยสร้างหัวใหม่ที่ 0

        print('After : ',end="")
        self.printList()
# list = [4,3,1,0,4,5,6]
# list = [5,4,3,2,1,0,9,8,7,6]
# list = [0,1,2,3,4,5]
# list = [1,2,3,0]
# list = [2,0,1]
lists = LinkedList()
list = input(' *** Locomotive ***\nEnter Input : ').split(" ")
for number in list:
    number = int(number)
    lists.append(number)
lists.switch()


#!/usr/bin/env python3

TEXT = """
3Z 4Z UZ3N37 4Z7 4 C3L7 5Z0LG4LJ4, H0GY B3B1Z0NY1754
M1LY3N C50D4L4705 D0LG0KR4 K3P35 4Z 3LM3.
3LK3P35Z70 D0LG0KR4! N3H3Z V0L7 3L05Z0R 3L0LV45N0D
3Z7, D3 M1R3 1D33R5Z 3HH3Z 4 50RH0Z, 4Z 3LM3D
4U70M471KU54N 3L 7UDJ4 0LV45N1.
4N3LKUL H0GY G0ND0LK0DN0D K3LL3N3 R4J74.
L3GY BU5ZK3! C54K K3V35 3MB3R K3P35 3L0LV45N1 3Z7.
H4 7375Z377, 05ZD M3G M450KK4L 15!
"""

DECODE_T = ['3', 'E','4', 'A', '7', 'T', '5', 'S', '1', 'I']

def decode_me(text):
    # Szótáras megoldás a DECODE_T lista a szótár
    my_text = list(TEXT)
    for i in my_text:
        if (i.isdigit()) and (i in DECODE_T):
            my_text[my_text.index(i)] = DECODE_T[DECODE_T.index(i) + 1]
    result = ""
    for x in my_text:
        result += x
    return result

    # Manuális replace az összes karakterre
    #return text.replace('3', 'E').replace('4', 'A').replace('7', 'T').replace('5', 'S').replace('0', 'O').replace('1', 'I')

def main():
    print('process TEXT...')
    print(decode_me(TEXT))

##############################################################################

if __name__ == "__main__":
    main()