from comparison_sol import str_path
#from Global_alignment_MM_functions import seq_to_alignement
from matplotlib import colors
import argparse
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import os

# This is a script to visualize SCRaMbLEd chromosomes using an arrow plot.
# Created by Marco Monti. email address: marcomonti.mm94@gmail.com
# Last updated on 17/04/2022
# ---------------------------------------------------------------

def reverse_path(path):
    rev_path = []
    for i in path:
        rev_path.insert(0, i)
    return rev_path

def arrowplot(path, max_LU=0, essential=[], CEN=[], names="", essential_col=True, filename="Arrowplot", REF=False, Show=True):
    if isinstance(path, str):
        path = str_path(path)
    if isinstance(path[0], int):  # There is only one path in the list
        path = [path]
    # This will reverse the order of the paths. It is useful to plot the paths from the top to the bottom.
    path = reverse_path(path)

    if names == "":
        names = range(len(path))
    names = reverse_path(names)

    # Create the folder where the output will be created
    if not os.path.exists("arrow_plots"):
        os.makedirs("arrow_plots")

    # get discrete colormap
    # Find the biggest LUs in the list.
    if max_LU == 0:
        #max_LU = max([max(x) for x in path])
        path_join = []
        for P in path:
            path_join = path_join + P
        path_abs = [abs(x) for x in path_join]
        max_LU = max(path_abs)
    # You can choose different gradients here: https://matplotlib.org/stable/tutorials/colors/colormaps.html
    colors_non_esse = cm.Blues(np.linspace(0, 1, max_LU - len(essential)))
    if CEN != []:
        colors_esse = cm.Reds(np.linspace(0, 1, len(essential)-1))      # -1 because there is one centromere in yellow
    else:
        colors_esse = cm.Reds(np.linspace(0, 1, len(essential)))
    # Choose the colour gradient. I like gist_rainbow and jet. jet might be a little be better for color blindness. Other options are: jet, gist_rainbow, hsv, viridis, plasma, magma, gnuplot2, rainbow
    colors_rainbow = cm.jet(np.linspace(0, 1, max_LU))
    ALL_colour = np.zeros(shape=(max_LU, 4))
    counter_esse = 0
    counter_non_esse = 0

    # Add the reference in the first line
    if REF:
        path.append(range(1, max_LU + 1))
        if names != "":
            names.append("ref")

    # Plot the arrows
    for LU in range(0, max_LU):
        if LU in CEN:
            ALL_colour[LU] = [1., 1., 0., 1.]   # this is yellow
        elif LU in essential:
            ALL_colour[LU] = colors_esse[counter_esse]
            counter_esse += 1
        else:
            ALL_colour[LU] = colors_non_esse[counter_non_esse]
            counter_non_esse += 1
    #print("ALL_colour =", ALL_colour)

    # Plot the arrow plot
    longest_path = max([len(x) for x in path])
    dpi = 250
    plt.figure(figsize=(longest_path, len(path)*1.8))
    #plt.figure(figsize=(8, len(path)*0.6), dpi=dpi)     # 8 inches
    for i in range(len(path)):  # y-axis
        #plt.scatter(range(len(path[i])), [i for _ in path[i]], color="black", label=">", s=50, zorder=3)
        for j in range(len(path[i])):  # x-axis
            if essential_col:
                colour = ALL_colour[abs(path[i][j]) - 1]
            else:
                colour = colors_rainbow[abs(path[i][j]) - 1]
            if [abs(path[i][j])] == CEN:    # If the triangle is the centromere, change the colour of the edge
                edgecolor = "red"
                linewidth = 4
            else:
                edgecolor = "dimgrey"
                linewidth = 2

            if path[i][j] >= 0:
                #plt.scatter(j, i, color=colour, marker=">", s=100, zorder=-1, edgecolor="dimgrey", label=abs(path[i][j]))
                # Use this if you want to center the triangles in each point (e.g. center at x=1)
                #triangle = plt.Polygon([[j-0.5,i+0.25], [j-0.5,i-0.25], [j+0.5,i]], facecolor=colour, edgecolor="dimgrey")
                # Use this if you want to center the triangles between two points (e.g. center at x=0.5)
                triangle = plt.Polygon([[j, i+0.25], [j, i-0.25], [j+1, i]], facecolor=colour, edgecolor=edgecolor, label=abs(path[i][j]), linewidth=linewidth)
                plt.gca().add_patch(triangle)
            else:
                #plt.scatter(j, i, color=colour, marker="<", s=100, zorder=-1, edgecolor="dimgrey", label=abs(path[i][j]))
                #triangle = plt.Polygon([[j+0.5,i+0.25], [j+0.5,i-0.25], [j-0.5,i]], facecolor=colour, edgecolor="dimgrey")
                triangle = plt.Polygon([[j+1, i+0.25], [j+1, i-0.25], [j, i]], facecolor=colour, edgecolor=edgecolor, label=abs(path[i][j]), linewidth=linewidth)
                plt.gca().add_patch(triangle)

    # Font size
    SMALL_SIZE = 35     #12
    MEDIUM_SIZE = 45    #15
    BIGGER_SIZE = 50    #18
    plt.rc('font', size=SMALL_SIZE)
    plt.rc('axes', titlesize=SMALL_SIZE)
    plt.rc('axes', labelsize=MEDIUM_SIZE)
    plt.rc('xtick', labelsize=SMALL_SIZE)
    plt.rc('ytick', labelsize=SMALL_SIZE)
    plt.rc('legend', fontsize=SMALL_SIZE)
    plt.rc('figure', titlesize=BIGGER_SIZE)
    # Axis
    plt.yticks(ticks=range(len(path)), labels=names)
    plt.ylim([-0.5, len(path)-0.5])
    plt.xlim([-0.5, longest_path+0.5])
    plt.xlabel("LoxPsym Units (LUs)")
    # This will make sure that the labels in the legend don't get duplicated
    #handles, labels = plt.gca().get_legend_handles_labels()
    #by_label = dict(zip(labels, handles))
    #plt.legend(by_label.values(), by_label.keys())
    if essential_col:
        esse = "_essential"
    else:
        esse = ""
    plt.savefig("arrow_plots/" + filename + esse + "_arrowplot.png", format="png", dpi=dpi, bbox_inches='tight')
    plt.savefig("arrow_plots/" + filename + esse + "_arrowplot.svg", format="svg", dpi=dpi, bbox_inches='tight')
    if Show:
        plt.show()
    plt.close()
    return None

if __name__ == '__main__':
    # These are for global alignment
    match_score = 2
    mismatch_score = -1
    gap_penalty = -2  # gap penalty (gamma)

    A = [1,2,3,9,4,5]
    B = [2,3,5,-1,7,4,5]
    #arrowplot([A,B], essential_col=False, REF=False)
    #print(seq_to_alignement(A,B, match_score, mismatch_score, gap_penalty))
    JS731_SR = [1, 2, 3, 4, 5, 6, 7, -13, -12, -1, -44, -43, -42, -41, -40, 39, -38, -37, -36, 8, 9, 11, 14, 15, 16, 17, 19, 20, 21, -37, -36, 19, 20, 14, 15, 16, -24, -23, -22, 17, 18, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -17, -16, -15, -14, -11, -10, -9, -8, 36, 37, 38, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, -18, -17, 22, 23, 24, -16, -15, -14, -20, -19, 36, 37, 38, -39, 40, 41, 42, 43, 44]
    JS731_LR = [1, 2, 3, 4, 5, 6, 7, -13, -12, -1, -44, -43, -42, -41, -40, 39, -38, -37, -36, 8, 9, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, -18, -17, 22, 23, 24, -16, -15, -14, -20, -19, 36, 37, -21, -20, -19, -17, -38, -37, -36, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, -18, -17, 22, 23, 24, -16, -15, -14, -20, -19, 36, 37, 38, -39, 40, 41, 42, 43, 44]

    # Syn9R SCRaMbLE
    synIXR = list(range(1, 45, 1))
    essential = [2, 7, 9, 10, 12, 20]
    CEN = [2]
    names = ["synIXR", "JS731_SR", "JS731_LR"]
    #arrowplot([synIXR], max_LU=44, essential=essential, CEN=CEN, names=["synIXR"], essential_col=False, filename="synIXR0", REF=False)
    #arrowplot([synIXR, JS731_SR, JS731_LR], max_LU=44, essential=essential, CEN=CEN, names=names, essential_col=False, filename="JS731", REF=False)
    #arrowplot([synIXR, JS731_SR, JS731_LR], max_LU=44, essential=essential, CEN=CEN, essential_col=False, filename="A_test")

    # Syn3 SCRaMbLE
    syn3 = list(range(1, 100, 1))
    essential_3 = [7, 9, 13, 20, 28, 36, 37, 48, 70, 73, 74, 84, 97]
    CEN3 = [37]


# -*- coding: utf-8 -*-
"""
Created on Wed Apr 29 16:40:47 2020

@author: Eric Bianchi
"""
import shutil
import os
import numpy as np
import tensorflow as tf
import cv2

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Try except statements
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def checkDirTryCatch(path):
    try:
        shutil.rmtree(path)
    except:
        print(path + " already removed")

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Remove folder contents
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
def removeCon(base_path):

    # Remove the existing folders
    checkDirTryCatch(base_path + '/EMF')
    checkDirTryCatch(base_path + '/GIF')
    checkDirTryCatch(base_path + '/TIFF')
    checkDirTryCatch(base_path + '/WDP')
    checkDirTryCatch(base_path + '/WMF')
    checkDirTryCatch(base_path + '/UnableToOpen')

    os.mkdir(base_path + '/EMF')
    os.mkdir(base_path + '/GIF')
    os.mkdir(base_path + '/TIFF')
    os.mkdir(base_path + '/WDP')
    os.mkdir(base_path + '/WMF')
    os.mkdir(base_path + '/UnableToOpen')

def writeResultOnImage(openCVImage, resultText):
    # ToDo: this function may take some further fine-tuning to show the text well given any possible image size

    imageHeight, imageWidth, sceneNumChannels = openCVImage.shape

    # choose a font
    fontFace = cv2.FONT_HERSHEY_TRIPLEX

    # chose the font size and thickness as a fraction of the image size
    if imageWidth < 800:
        fontScale = imageWidth/800
    else:
        fontScale = 1

    fontThickness = .5

    # make sure font thickness is an integer, if not, the OpenCV functions that use this may crash
    fontThickness = int(fontThickness)

    upperLeftTextOriginX = int(imageWidth * 0.05)
    upperLeftTextOriginY = int(imageHeight * 0.05)

    textSize, baseline = cv2.getTextSize(resultText, fontFace, fontScale, fontThickness)
    textSizeWidth, textSizeHeight = textSize

    # calculate the lower left origin of the text area based on the text area center, width, and height
    lowerLeftTextOriginX = upperLeftTextOriginX
    lowerLeftTextOriginY = upperLeftTextOriginY + textSizeHeight

    rectangle_bgr = (255,255,0)
    box_coords = ((upperLeftTextOriginX - 5, upperLeftTextOriginY - 5), (upperLeftTextOriginX + textSizeWidth + 5, upperLeftTextOriginY + textSizeHeight + 5))
    cv2.rectangle(openCVImage, box_coords[0], box_coords[1], rectangle_bgr, cv2.FILLED)

    # write the text on the image
    cv2.putText(openCVImage, resultText, (lowerLeftTextOriginX, lowerLeftTextOriginY), fontFace, fontScale, (255, 0, 0) , fontThickness)
# end function

def overwrite(original, output):
    try:
        os.rename(original, output)
    except WindowsError:
        os.remove(output)
        os.rename(original, output)

def confidenceSort(onMostLikelyPrediction,confidence,strClassification,cur_name,image_path,DRIVE,image_names,countList, sort_ID, sort_ID_string ,upperBound,lowerBound,x,y):
    if onMostLikelyPrediction and (upperBound > confidence > lowerBound):
        string_upperBound = str(int(100*upperBound))
        string_lowerBound = str(int(100*lowerBound))
        scoreAsAPercent = confidence * 100.0
        # print("the object appears to be a " + strClassification + ", " +
        #       "{0:.2f}".format(scoreAsAPercent) + "% confidence  (" + str(cur_name) + ")")

        if strClassification == (sort_ID.lower()):
            shutil.copyfile(image_path, DRIVE + "DATA/Extraction/Sorted Data/" +
                            sort_ID_string + "/#" + sort_ID +"/" + string_lowerBound +
                            "%-" + string_upperBound + "%/" + image_names[cur_name])
            countList[x][y] = countList[x][y] + 1

        else:
            shutil.copyfile(image_path, DRIVE + "DATA/Extraction/Sorted Data/" +
                            sort_ID_string + "/#Non" + sort_ID +"/" + string_lowerBound +
                            "%-" + string_upperBound + "%/" + image_names[cur_name])
            countList[x+1][y] = countList[x+1][y] + 1

        onMostLikelyPrediction = False
        cur_name = cur_name + 1
    return cur_name, onMostLikelyPrediction

def confidenceSort_(image_path,BASE,image_name,confidence, sort_ID, sort_ID_string, upperBound,lowerBound):
    string_upperBound = str(int(100*upperBound))
    string_lowerBound = str(int(100*lowerBound))
    dest = BASE + "DATA/Extraction/Sorted Data/" + sort_ID_string + "/#" + sort_ID + "/" + string_lowerBound + "%-" + string_upperBound + "%/" + image_name

    from os import path

    if path.exists(dest):
        print(image_name + ': already exists')
    else:
        shutil.copyfile(image_path, dest)
        print('sorted data: ' + image_name + 'to #' + sort_ID + ' ' + string_upperBound)

def buildImageFileList(TEST_IMAGES_DIR):

    imageFilePaths = []
    image_names = []

    for imageFileName in os.listdir(TEST_IMAGES_DIR):
        if imageFileName.endswith(".jpg"):
            imageFilePaths.append(TEST_IMAGES_DIR + imageFileName)
            image_names.append(imageFileName)
        elif imageFileName.endswith(".JPG"):
            imageFilePaths.append(TEST_IMAGES_DIR + imageFileName)
            image_names.append(imageFileName)
        elif imageFileName.endswith(".png"):
            imageFilePaths.append(TEST_IMAGES_DIR + imageFileName)
            image_names.append(imageFileName)
        elif imageFileName.endswith(".jpeg"):
            imageFilePaths.append(TEST_IMAGES_DIR + imageFileName)
            image_names.append(imageFileName)

    return imageFilePaths, image_names

def makePrediction(sess, openCVImage, classifications):
    # get the final tensor from the graph
    finalTensor = sess.graph.get_tensor_by_name('final_result:0')
    activations = sess.graph.get_tensor_by_name('mixed_10/join:0')

    # convert the OpenCV image (numpy array) to a TensorFlow image
    tfImage = np.array(openCVImage)[:, :, 0:3]

    # run the network to get the predictions
    predictions = sess.run(finalTensor, {'DecodeJpeg:0': tfImage})

    activations = sess.run(activations, {'DecodeJpeg:0': tfImage})
    # sort predictions from most confidence to least confidence
    sortedPredictions = predictions[0].argsort()[-len(predictions[0]):][::-1]

    prediction = sortedPredictions[0]
    #*****print("---------------------------------------")
    # keep track of if we're going through the next for loop for the first time so we can show more info about
    # the first prediction, which is the most likely prediction (they were sorted descending above)
    onMostLikelyPrediction = True

    strClassification = classifications[prediction]

    # get confidence, then get confidence rounded to 2 places after the decimal
    confidence = predictions[0][prediction]

    return prediction, onMostLikelyPrediction, sortedPredictions, strClassification, confidence

def addResultToImList(image_path, openCVImage, strClassification, confidence, cur_name):
    # get the score as a %
    scoreAsAPercent = confidence * 100.0
    # show the result to std out
    writeResultOnImage(openCVImage, strClassification + ", " + "{0:.2f}".format(scoreAsAPercent) + "% confidence.")

    return openCVImage

def showResultOnImage(image_path, openCVImage, strClassification, confidence, cur_name):
    # get the score as a %
    scoreAsAPercent = confidence * 100.0
    # show the result to std out
    print("the object appears to be a " + strClassification + ", " + "{0:.2f}".format(scoreAsAPercent) + "% confidence.  (" + str(cur_name) + ")")
    writeResultOnImage(openCVImage, strClassification + ", " + "{0:.2f}".format(scoreAsAPercent) + "% confidence.")

    # finally we can show the OpenCV image
    cv2.imshow(image_path, openCVImage)
    # mark that we've show the most likely prediction at this point so the additional information in
    # this if statement does not show again for this image
    cv2.waitKey()
    # after a key is pressed, close the current window to prep for the next time around
    cv2.destroyAllWindows()

def makeCountList():
    non0 = 0
    non25 = 0
    non65 = 0
    non75 = 0
    non90 = 0
    non95 = 0

    yes0 = 0
    yes25 = 0
    yes65 = 0
    yes75 = 0
    yes90 = 0
    yes95 = 0

    countList = [[0, 0, 0, 0, 0, 0, 0],
                       [0,yes0,yes25, yes65, yes75, yes90, yes95],
                       [0,non0,non25, non65, non75, non90, non95]]
    return countList

def sortPrediction_(image_path, BASE, confidence,strClassification,image_name, sort_ID, sort_ID_string):

    if confidence < 0.2:
        confidenceSort_(image_path,BASE,image_name,confidence,sort_ID,sort_ID_string, 0.2,0)
    elif 0.2 < confidence < 0.4:
        confidenceSort_(image_path,BASE,image_name,confidence,sort_ID,sort_ID_string ,0.4,0.2)
    elif 0.4 < confidence < 0.6:
        confidenceSort_(image_path,BASE,image_name,confidence,sort_ID,sort_ID_string ,0.6,0.4)
    elif 0.6 < confidence < 0.8:
        confidenceSort_(image_path,BASE,image_name,confidence,sort_ID,sort_ID_string ,0.8,0.6)
    elif 0.8 < confidence < 1.0:
        confidenceSort_(image_path,BASE,image_name,confidence,sort_ID,sort_ID_string ,1.0,0.8)

def sortPrediction(onMostLikelyPrediction, confidence,strClassification,image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string, cur_name):

    cur_name, onMostLikelyPrediction = confidenceSort(
        onMostLikelyPrediction, confidence,
        strClassification, cur_name, image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string ,0.2,0.0,1,2)

    cur_name, onMostLikelyPrediction = confidenceSort(
        onMostLikelyPrediction, confidence,
        strClassification, cur_name, image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string ,0.4,0.2,1,3)

    cur_name, onMostLikelyPrediction = confidenceSort(
        onMostLikelyPrediction, confidence,
        strClassification, cur_name, image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string ,0.6,0.4,1,4)

    cur_name, onMostLikelyPrediction = confidenceSort(
        onMostLikelyPrediction, confidence,
        strClassification, cur_name, image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string ,0.8,0.6,1,5)

    cur_name, onMostLikelyPrediction = confidenceSort(
        onMostLikelyPrediction, confidence,
        strClassification, cur_name, image_path,
        BASE, image_names, countList, sort_ID, sort_ID_string ,1.0,0.8,1,6)

def saveAndPrintHistogram(sort_ID, countList):
    text = ( "\n"
    "\n"
    "================== " + sort_ID + " =============" + "\n"
    + sort_ID + " <25%    : " + str(countList[1][1]) + "\n"
    + sort_ID + " 25%-50% : " + str(countList[1][2]) + "\n"
    + sort_ID + " 65%-75% : " + str(countList[1][3]) + "\n"
    + sort_ID + " 75%-90% : " + str(countList[1][4]) + "\n"
    + sort_ID + " 90%-95% : " + str(countList[1][5]) + "\n"
    + sort_ID + " >95%    : " + str(countList[1][6]) + "\n"
    "================== Non-" + sort_ID + " ==================" + "\n"
    + "non" + sort_ID + " <25%        : " + str(countList[2][1]) + "\n"
    + "non" + sort_ID + " 25%-50%     : " + str(countList[2][2]) + "\n"
    + "non" + sort_ID + " 65%-75%     : " + str(countList[2][3]) + "\n"
    + "non" + sort_ID + " 75%-90%     : " + str(countList[2][4]) + "\n"
    + "non" + sort_ID + " 90%-95%     : " + str(countList[2][5]) + "\n"
    + "non" + sort_ID + " >95%        : " + str(countList[2][6]) + "\n")

    print(text)
    histogram = open(sort_ID + ".txt","w")
    lines = [text]
    histogram.writelines(lines)
    histogram.close()

def prettyLabel(classDirectory):
    for class_ in classDirectory:

        for im in directoryPath:
            shutil.copyfile(TEST_IMAGE_DIR + im, FN_PATH + im)
        print('done')

def confusionMatrix(pred, gt):

    if gt == 0 and pred == 0:
        result = 'TP'
    if gt == 1 and pred == 1:
        result = 'TN'
    if gt == 0 and pred == 1:
        result = 'FN'
    if gt == 1 and pred == 0:
        result = 'FP'
    return result

def sortRandomImages(src, dst, number):

    imageFilePaths, image_names = buildImageFileList(src, '')

    import random
    for i in range(0,number):
        randNumber = random.randrange(0, len(imageFilePaths), 1)
        print (randNumber)
        src_rand = imageFilePaths[randNumber]
        shutil.copy(src_rand, dst)
        imageFilePaths.remove(src_rand)

def sortImages(src, dst, image_names):

    if not os.path.exists(dst): # if it doesn't exist already
        os.makedirs(dst)

    for i in range(0,len(image_names)):
        print(image_names[i][0])
        image = image_names[i][0]

        shutil.copy(src+image, dst)

def sortXML(src, dst, image_names):

    if not os.path.exists(dst): # if it doesn't exist already
        os.makedirs(dst)

    for i in range(0,len(image_names)):
        print(image_names[i][0])
        xml = image_names[i][0].split('.')[0]+'.xml'

        shutil.copy(src+xml, dst)

def verboseConfusion(FN, FP, TN, TP):
    print("FALSE NEGATIVE: " + str(FN))
    print("FALSE POSITIVE: " + str(FP))
    print("TRUE NEGATIVE: " + str(TN))
    print("TRUE POSITIVE: " + str(TP))
    Accuracy = (TP + TN)/(TP+TN+FP+FN)
    Precision = TP/(TP + FN)
    Recall = TP/(TP + FP)

    print("Accruacy: " + str(Accuracy))
    print("Precision: " + str(Precision))
    print("Recall: " + str(Recall))

def confusionMatrixValues(eval_gt, eval_pred, imageFilePaths):
    TP = 0
    TN = 0
    FP = 0
    FN = 0

    TP_path = []
    TN_path = []
    FP_path = []
    FN_path = []

    for image in imageFilePaths:
        head, imageName = os.path.split(image)
        gt = eval_gt[imageName]
        prediction = eval_pred[imageName]

        if gt == 0 and prediction == 0:
            TP = TP + 1
            TP_path.append(imageName)
        if gt == 1 and prediction == 1:
            TN = TN + 1
            TN_path.append(imageName)
        if gt == 0 and prediction == 1:
            FN = FN + 1
            FN_path.append(imageName)
            # cv2.imshow("false negative", imagePaths[i])
            # cv2.waitKey()
            # cv2.destroyAllWindows()
        if gt == 1 and prediction == 0:
            FP = FP + 1
            FP_path.append(imageName)
            # cv2.imshow("false positive", imagePaths[i])
            # cv2.waitKey()
            # cv2.destroyAllWindows()
    return FN, FP, TN, TP, FN_path, FP_path, TN_path, TP_path

def presentResults(eval_gt, eval_pred, imageFilePaths):
    FN, FP, TN, TP, FN_path, FP_path, TN_path, TP_path = confusionMatrixValues(eval_gt, eval_pred, imageFilePaths)
    verboseConfusion(FN, FP, TN, TP)
    return FN_path, FP_path, TN_path, TP_path

def saveResults(FN_path, FP_path, CONF_MATRIX_PATH, TEST_IMAGE_DIR, meta_data):
    import csv

    # CONF_MATRIX_PATH = 'D://DATA/Datasets/Detail-NonDetail/confusionMatrix/ensemble/'

    FN_PATH = CONF_MATRIX_PATH + 'FN/'
    for im in FN_path:
        shutil.copyfile(TEST_IMAGE_DIR + im, FN_PATH + im)
    print('FN done')

    FP_PATH = CONF_MATRIX_PATH + 'FP/'
    for im in FP_path:
        shutil.copyfile(TEST_IMAGE_DIR + im, FP_PATH + im)
    print('FP done')

    # field names
    fields = ['Image Name', 'Classifier Prediction', 'Class', 'Classifier Score', 'Ground Truth']

    # name of csv file
    filename = "meta_data_predictions.csv"

    with open(TEST_IMAGE_DIR + filename, 'w', newline='') as f:
        thewriter = csv.DictWriter(f, fieldnames=fields)
        thewriter.writeheader()
        for meta in meta_data:
            thewriter.writerow(meta)
    print('Meta Data done')

def evaluateBinaryClassifier(classifier1, TEST_IMAGE_DIR, eval_gt, sort_ID, classIdx):

    print("starting program . . .")

    # Classifier 1:
    classification_c1, detection_graph_cla1 = classifier1.prepareGraphs()

    sess2 = tf.Session(graph=detection_graph_cla1)

    # Load in file paths
    imageFilePaths, image_names = buildImageFileList(TEST_IMAGE_DIR)

    imageFilePaths.sort()
    cur_name = 0
    eval_pred = {}
    meta_data = []
    for image_path in imageFilePaths:

        head, imageName = os.path.split(image_path)
        openCVImage = cv2.imread(image_path)
        openCVImage = cv2.resize(openCVImage,(400,400))
        # if we were not able to successfully open the image, continue with the next iteration of the for loop
        if openCVImage is None:
            print("unable to open " + image_path + " as an OpenCV image")
            cur_name = cur_name + 1
            continue
        # end if

        prediction, onMostLikelyPrediction, sortedPredictions, strClassification, confidence = makePrediction(sess2,
                                                                                openCVImage,
                                                                                classification_c1)
        head, imageName = os.path.split(image_path)
        gt = eval_gt[imageName]
        #=============================================================================
        if strClassification == (sort_ID.lower()):
            score_class_conf = (confidence-.50)*2
            eval_pred.update({imageName:classIdx(strClassification)})
            meta_data.append({'Image Name':imageName, 'Classifier Prediction':0,'Class':strClassification,
                              'Classifier Score':score_class_conf, 'Ground Truth':gt, 'Conf. Matrix':confusionMatrix(classIdx(strClassification), gt)})
        else:
            score_class_conf = (confidence-.50)*2
            eval_pred.update({imageName:classIdx(strClassification)})
            meta_data.append({'Image Name':imageName, 'Classifier Prediction':classIdx(strClassification),'Class':strClassification,
                              'Classifier Score':score_class_conf, 'Ground Truth':gt, 'Conf. Matrix':confusionMatrix(classIdx(strClassification), gt)})
        #print("==============================================================")
        cur_name = cur_name + 1
        if (cur_name % 100) == 0:
            print ("logging: ..." + str(cur_name))
    # end for
    return eval_pred, imageFilePaths, meta_data
# end main

def sortBinaryClassifier(classifier1, TEST_IMAGE_DIR, eval_gt, sort_ID, classIdx, BASE):

    print("starting program . . .")

    # Classifier 1:
    classification_c1, detection_graph_cla1 = classifier1.prepareGraphs()

    sess2 = tf.Session(graph=detection_graph_cla1)

    # Load in file paths
    imageFilePaths, image_names = buildImageFileList(TEST_IMAGE_DIR)

    imageFilePaths.sort()
    cur_name = 0
    for image_path in imageFilePaths:

        head, imageName = os.path.split(image_path)
        openCVImage = cv2.imread(image_path)
        openCVImage = cv2.resize(openCVImage,(300,300))
        # if we were not able to successfully open the image, continue with the next iteration of the for loop
        if openCVImage is None:
            print("unable to open " + image_path + " as an OpenCV image")
            cur_name = cur_name + 1
            continue
        # end if

        prediction, onMostLikelyPrediction, sortedPredictions, strClassification, confidence = makePrediction(sess2,
                                                                                openCVImage,
                                                                                classification_c1)
        head, imageName = os.path.split(image_path)
        #=============================================================================
        if strClassification == (sort_ID.lower()):
            score_class_conf = (confidence-.50)*2
            sortPrediction_(image_path, BASE, score_class_conf,
                     strClassification, imageName, sort_ID, sort_ID + "-Non" + sort_ID)
        else:
            score_class_conf = (confidence-.50)*2
            sortPrediction_(image_path, BASE, score_class_conf,
                     strClassification, imageName, sort_ID, sort_ID + "-Non" + sort_ID)
        #print("==============================================================")
        cur_name = cur_name + 1
        if (cur_name % 100) == 0:
            print ("logging: ..." + str(cur_name))
# end main

def binary_sort_positive_images(classifier1, SEARCH_DIRECTORY, search_ID, POSITIVE_DESINTATION_DIRECTORY):
    print("starting program . . .")

    # Classifier 1:
    classification_c1, detection_graph_cla1 = classifier1.prepareGraphs()

    sess1 = tf.Session(graph=detection_graph_cla1)

    # Load in file paths
    imageFilePaths, image_names = buildImageFileList(SEARCH_DIRECTORY)

    imageFilePaths.sort()
    cur_name = 0
    for image_path in imageFilePaths:

        head, imageName = os.path.split(image_path)
        openCVImage = cv2.imread(image_path)
        openCVImage = cv2.resize(openCVImage,(300,300))

        # if we were not able to successfully open the image, continue with the next iteration of the for loop
        if openCVImage is None:
            print("unable to open " + image_path + " as an OpenCV image")
            cur_name = cur_name + 1
            continue
        # end if

        prediction, onMostLikelyPrediction, sortedPredictions, strClassification, confidence = makePrediction(sess1,
                                                                                openCVImage,
                                                                                classification_c1)
        head, imageName = os.path.split(image_path)
        #=============================================================================
        if strClassification == (search_ID.lower()):
            print('Found a: ' + search_ID)
            shutil.copy(image_path, POSITIVE_DESINTATION_DIRECTORY + imageName)
        cur_name = cur_name + 1
        if (cur_name % 100) == 0:
            print ("logging: ..." + str(cur_name))
# end main
import csv
def findHeightWidth(directory, csv_file):
    fields = ['filename', 'width', 'height']

    print('starting program...')
    with open(directory + csv_file, 'w', newline='') as f:
        thewriter = csv.writer(f)
        thewriter.writerow(fields)
        print('=================================================================')
        for imageFileName in os.listdir(directory):
            if imageFileName.endswith(".png"):
                print(imageFileName)
                height = cv2.imread(directory+imageFileName).shape[0]
                width = cv2.imread(directory+imageFileName).shape[1]
                thewriter.writerow([imageFileName, width, height])

# def checkAndChangeHeightandWidth(directory, csv_file):
#     print('starting program...')
#     with open(directory + csv_file, 'w', newline='') as f_read:
#         reader = csv.reader(f_read, delimiter=',')
#         with open(directory + csv_file, 'w', newline='') as f:
#             thewriter = csv.writer(f)
#             thewriter.writerow(fields)
#          for row in reader:

#         print('=================================================================')
#         for imageFileName in os.listdir(directory):
#             if imageFileName.endswith(".png"):
#                 print(imageFileName)
#                 height = cv2.imread(directory+imageFileName).shape[0]
#                 width = cv2.imread(directory+imageFileName).shape[1]
#                 thewriter.writerow([imageFileName, width, height])


import RPi.GPIO as GPIO
import time
import os
from numpy import interp

class ServoManager(object):
	# self.current stores rot (degrees)

	def __init__(self, pin):
		# init GPIO
		GPIO.setwarnings(False)
		GPIO.setmode(GPIO.BOARD)
		GPIO.setup(pin, GPIO.OUT)

		# default to center
		self.pin = pin
		self.currentAngle = 90
		self.setAngleInDegrees(self.currentAngle)
		#time.sleep(1)

	# set angle using degrees
	def setAngleInDegrees(self, degrees):
		if (degrees < 0 or degrees > 180):
			print("Angle must be between 0 and 180 degrees")
		else:
			self.currentAngle = degrees
			self.servo = GPIO.PWM(self.pin, 50)
			self.servo.start(self.degreesToCycle(self.currentAngle))
			time.sleep(1)

		self.servo.stop()

	# takes degrees, returns duty cycle
	def degreesToCycle(self, degrees):
		return float(interp(degrees,[0,180],[2.5,12.5]))

	def cleanup(self):
		self.servo.stop()
		GPIO.cleanup()


import math
from torch import nn
import torch.nn.init as init
from .common import AdaptiveFM
from .dgr import DGR
import torch
import torch.nn.functional as F

def make_model(args, parent=False):
    return ESPCN(args)

def get_valid_padding(kernel_size, dilation):
    kernel_size = kernel_size + (kernel_size - 1) * (dilation - 1)
    padding = (kernel_size - 1) // 2
    return padding

def espcn_conv(input,prefix, weights_dict):
    x = F.conv2d(input, weights_dict[prefix + '.weight'], weights_dict[prefix + '.bias'], stride=1, padding=1)
    return x

class AdaptiveFM(nn.Module):
    # hello ckx
    def __init__(self, in_channel, kernel_size):

        super(AdaptiveFM, self).__init__()
        padding = get_valid_padding(kernel_size, 1)
        self.transformer = nn.Conv2d(in_channel, in_channel, kernel_size,
                                     padding=padding, groups=in_channel//2)
        self.gamma = nn.Parameter(torch.zeros(1), requires_grad=True)
    def forward(self, x):
        return self.transformer(x) * self.gamma + x

class ESPCN(nn.Module):
    def __init__(self, args):
        super(ESPCN, self).__init__()
        # self.act_func = nn.LeakyReLU(negative_slope=0.2)
        self.act_func = nn.ReLU(inplace=True)
        self.scale = int(args.scale[0])  # use scale[0]
        self.n_colors = args.n_colors
        self.args = args
        if self.args.new_espcn:
            self.conv1 = nn.Conv2d(self.n_colors, 64, (3, 3), (1, 1), (1, 1))
            self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
            self.conv3 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
            self.conv4 = nn.Conv2d(64, 3 * (self.scale ** 2), (3, 3), (1, 1), (1, 1))
        else:
            self.conv1 = nn.Conv2d(self.n_colors, 64, (3, 3), (1, 1), (1, 1))
            self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
            self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
            self.conv4 = nn.Conv2d(32, 3 * (self.scale ** 2), (3, 3), (1, 1), (1, 1))
        self.pixel_shuffle = nn.PixelShuffle(self.scale)

        self._initialize_weights()

    def forward(self, x, num, weights_dict=None):
        if weights_dict!=None:
            #print(3333333333333333333333)
            out = self.act_func(espcn_conv(x, 'model.conv1', weights_dict))
            out = self.act_func(espcn_conv(out, 'model.conv2', weights_dict))
            out = self.act_func(espcn_conv(out, 'model.conv3', weights_dict))
            out = self.pixel_shuffle(espcn_conv(out, 'model.conv4', weights_dict))
            return out
        else:
            #print(1111111111111111111111)
            if self.args.new_espcn:
                res = self.act_func(self.conv1(x))
                out = self.act_func(self.conv2(res))
                out = self.conv3(out)
                out = res+out
                out = self.pixel_shuffle(self.conv4(out))
                return out
            else:
                out = self.act_func(self.conv1(x))
                out = self.act_func(self.conv2(out))
                out = self.act_func(self.conv3(out))
                out = self.pixel_shuffle(self.conv4(out))
                return out

    def _initialize_weights(self):
        init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv4.weight)

    def load_state_dict(self, state_dict, strict=True):
        own_state = self.state_dict()
        for name, param in state_dict.items():
            if name in own_state:
                if isinstance(param, nn.Parameter):
                    param = param.data
                own_state[name].copy_(param)


from django.db.models import Manager
from .exceptions import TenantError
from .utils import state

FIELD_NAME = "shop"

class TenantManager(Manager):
    def __init__(self):
        self.state = state
        super().__init__()

    def get_queryset(self):
        current_state = self.state.get_state()
        queryset = super().get_queryset()

        if not current_state.get("enabled", True):
            return queryset

        filter_kwargs = {FIELD_NAME: self.state.get_current_tenant()}

        return queryset.filter(**filter_kwargs)

    def bulk_create(self, objs):
        tenant = self.state.get_current_tenant()

        for obj in objs:
            setattr(obj, FIELD_NAME, tenant)

        return super().bulk_create(objs)


pref = input("Do you prefer Dogs or Cats? ")
def function(dogs, cats, pref):
    print(f"You have {dogs} dogs")
    print(f"You have {cats} cats.")
    print(f"you prefer {pref}.\n")
function(10,15,pref)

function(10 - 5, 20 - 8,pref)

meow = 6
woof = 10
function(woof, meow,pref)

function(9,6,pref)


from __future__ import absolute_import
from __future__ import print_function
import os
import sys
import re
from builtins import str as text
import wx

# -----------------------------------------------------------------------------
# Global variables
# ----------------
#

__author__ = "Pierre Rouleau"
__version__ = "$Revision: 1.5 $"

# -----------------------------------------------------------------------------

def getSupportedLanguageDict(appname):
    """
    Returns dictionary with languages already supported
    by given application

    param: appname:
        name of application
    """
    languageDict = {}
    ext = '.po'
    files = [x for x in os.listdir('.')
             if x.startswith(appname) and x.endswith(ext)]

    langs = [x.split(appname + '_')[1].split(ext)[0] for x in files]
    for lang in langs:
        languageDict[lang] = lang

    return languageDict

def getlanguageDict():
    languageDict = {}
    getSupportedLanguageDict('Beremiz')
    if wx.VERSION >= (3, 0, 0):
        _app = wx.App()
    else:
        _app = wx.PySimpleApp()

    for lang in [x for x in dir(wx) if x.startswith("LANGUAGE")]:
        i = wx.Locale(wx.LANGUAGE_DEFAULT).GetLanguageInfo(getattr(wx, lang))
        if i:
            languageDict[i.CanonicalName] = i.Description

    return languageDict

def verbosePrint(verbose, str):
    if verbose:
        print(str)

def processCustomFiles(filein, fileout, regexp, prefix=''):
    appfil_file = open(filein, 'r')
    messages_file = open(fileout, 'r')
    messages = messages_file.read()
    messages_file.close()
    messages_file = open(fileout, 'a')
    messages_file.write('\n')
    messages_file.write('#: %s\n' % prefix)
    messages_file.write('\n')

    words_found = {}
    for filepath in appfil_file.readlines():
        code_file = open(filepath.strip(), 'r')
        for match in regexp.finditer(code_file.read()):
            word = match.group(1)
            if not words_found.get(word, False) and messages.find("msgid \"%s\"\nmsgstr \"\"" % word) == -1:
                words_found[word] = True
                messages_file.write('\n')
                messages_file.write("msgid \"%s\"\n" % word)
                messages_file.write("msgstr \"\"\n")
        code_file.close()

    messages_file.close()
    appfil_file.close()

# -----------------------------------------------------------------------------
# m a k e P O ( )         -- Build the Portable Object file for the application --
# ^^^^^^^^^^^^^^^
#
def makePO(applicationDirectoryPath,  applicationDomain=None, verbose=0):
    """Build the Portable Object Template file for the application.

    makePO builds the .pot file for the application stored inside
    a specified directory by running xgettext for all application source
    files.  It finds the name of all files by looking for a file called 'app.fil'.
    If this file does not exists, makePo raises an IOError exception.
    By default the application domain (the application
    name) is the same as the directory name but it can be overridden by the
    'applicationDomain' argument.

    makePO always creates a new file called messages.pot.  If it finds files
    of the form app_xx.po where 'app' is the application name and 'xx' is one
    of the ISO 639 two-letter language codes, makePO resynchronizes those
    files with the latest extracted strings (now contained in messages.pot).
    This process updates all line location number in the language-specific
    .po files and may also create new entries for translation (or comment out
    some).  The .po file is not changed, instead a new file is created with
    the .new extension appended to the name of the .po file.

    By default the function does not display what it is doing.  Set the
    verbose argument to 1 to force it to print its commands.
    """

    if applicationDomain is None:
        applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
    else:
        applicationName = applicationDomain
    currentDir = os.getcwd()
    os.chdir(applicationDirectoryPath)
    filelist = 'app.fil'
    if not os.path.exists(filelist):
        raise IOError(2, 'No module file: %s' % filelist)

    fileout = 'messages.pot'
    # Steps:
    #  Use xgettext to parse all application modules
    #  The following switches are used:
    #
    #   -s                          : sort output by string content (easier to use when we need to merge several .po files)
    #   --files-from=app.fil        : The list of files is taken from the file: app.fil
    #   --output=                   : specifies the name of the output file (using a .pot extension)
    cmd = 'xgettext -s --no-wrap --language=Python --files-from=' + filelist + ' --output=' + fileout + ' --package-name ' + applicationName
    verbosePrint(verbose, cmd)
    os.system(cmd)

    XSD_STRING_MODEL = re.compile(r"<xsd\:(?:element|attribute) name=\"([^\"]*)\"[^\>]*\>")
    processCustomFiles(filelist, fileout, XSD_STRING_MODEL, 'Extra XSD strings')

    XML_TC6_STRING_MODEL = re.compile(r"<documentation>\s*<xhtml\:p><!\[CDATA\[([^\]]*)\]\]></xhtml\:p>\s*</documentation>", re.MULTILINE | re.DOTALL)
    processCustomFiles(filelist, fileout, XML_TC6_STRING_MODEL, 'Extra TC6 documentation strings')

    # generate messages.po
    cmd = 'msginit --no-wrap --no-translator -i %s -l en_US.UTF-8 -o messages.po' % (fileout)
    verbosePrint(verbose, cmd)
    os.system(cmd)

    languageDict = getSupportedLanguageDict(applicationName)

    for langCode in languageDict.keys():
        if langCode == 'en':
            pass
        else:
            langPOfileName = "%s_%s.po" % (applicationName, langCode)
            if os.path.exists(langPOfileName):
                cmd = 'msgmerge -s --no-wrap "%s" %s > "%s.new"' % (langPOfileName, fileout, langPOfileName)
                verbosePrint(verbose, cmd)
                os.system(cmd)
    os.chdir(currentDir)

def catPO(applicationDirectoryPath, listOf_extraPo, applicationDomain=None, targetDir=None, verbose=0):
    """Concatenate one or several PO files with the application domain files.
    """

    if applicationDomain is None:
        applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
    else:
        applicationName = applicationDomain
    currentDir = os.getcwd()
    os.chdir(applicationDirectoryPath)

    languageDict = getSupportedLanguageDict(applicationName)

    for langCode in languageDict.keys():
        if langCode == 'en':
            pass
        else:
            langPOfileName = "%s_%s.po" % (applicationName, langCode)
            if os.path.exists(langPOfileName):
                fileList = ''
                for fileName in listOf_extraPo:
                    fileList += ("%s_%s.po " % (fileName, langCode))
                cmd = "msgcat -s --no-wrap %s %s > %s.cat" % (langPOfileName, fileList, langPOfileName)
                verbosePrint(verbose, cmd)
                os.system(cmd)
                if targetDir is None:
                    pass
                else:
                    mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir, langCode)
                    cmd = "msgfmt --output-file=%s/%s.mo %s_%s.po.cat" % (mo_targetDir, applicationName, applicationName, langCode)
                    verbosePrint(verbose, cmd)
                    os.system(cmd)
    os.chdir(currentDir)

def makeMO(applicationDirectoryPath, targetDir='./locale', applicationDomain=None, verbose=0, forceEnglish=0):
    """Compile the Portable Object files into the Machine Object stored in the right location.

    makeMO converts all translated language-specific PO files located inside
    the  application directory into the binary .MO files stored inside the
    LC_MESSAGES sub-directory for the found locale files.

    makeMO searches for all files that have a name of the form 'app_xx.po'
    inside the application directory specified by the first argument.  The
    'app' is the application domain name (that can be specified by the
    applicationDomain argument or is taken from the directory name). The 'xx'
    corresponds to one of the ISO 639 two-letter language codes.

    makeMo stores the resulting files inside a sub-directory of `targetDir`
    called xx/LC_MESSAGES where 'xx' corresponds to the 2-letter language
    code.
    """

    if targetDir is None:
        targetDir = './locale'

    verbosePrint(verbose, "Target directory for .mo files is: %s" % targetDir)

    if applicationDomain is None:
        applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
    else:
        applicationName = applicationDomain
    currentDir = os.getcwd()
    os.chdir(applicationDirectoryPath)

    languageDict = getSupportedLanguageDict(applicationName)

    for langCode in languageDict.keys():
        if (langCode == 'en') and (forceEnglish == 0):
            pass
        else:
            langPOfileName = "%s_%s.po" % (applicationName, langCode)
            if os.path.exists(langPOfileName):
                mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir, langCode)
                if not os.path.exists(mo_targetDir):
                    mkdir(mo_targetDir)
                cmd = 'msgfmt --output-file="%s/%s.mo" "%s_%s.po"' % (mo_targetDir, applicationName, applicationName, langCode)
                verbosePrint(verbose, cmd)
                os.system(cmd)
    os.chdir(currentDir)

def printUsage(errorMsg=None):
    """Displays how to use this script from the command line."""
    print("""
    ##################################################################################
    #   mki18n :   Make internationalization files.                                  #
    #              Uses the GNU gettext system to create PO (Portable Object) files  #
    #              from source code, coimpile PO into MO (Machine Object) files.     #
    #              Supports C,C++,Python source files.                               #
    #                                                                                #
    #   Usage: mki18n {OPTION} [appDirPath]                                          #
    #                                                                                #
    #   Options:                                                                     #
    #     -e               : When -m is used, forces English .mo file creation       #
    #     -h               : prints this help                                        #
    #     -m               : make MO from existing PO files                          #
    #     -p               : make PO, update PO files: Creates a new messages.pot    #
    #                        file. Creates a dom_xx.po.new for every existing        #
    #                        language specific .po file. ('xx' stands for the ISO639 #
    #                        two-letter language code and 'dom' stands for the       #
    #                        application domain name).  mki18n requires that you     #
    #                        write a 'app.fil' file  which contains the list of all  #
    #                        source code to parse.                                   #
    #     -v               : verbose (prints comments while running)                 #
    #     --domain=appName : specifies the application domain name.  By default      #
    #                        the directory name is used.                             #
    #     --moTarget=dir : specifies the directory where .mo files are stored.       #
    #                      If not specified, the target is './locale'                #
    #                                                                                #
    #   You must specify one of the -p or -m option to perform the work.  You can    #
    #   specify the path of the target application.  If you leave it out mki18n      #
    #   will use the current directory as the application main directory.            #
    #                                                                                #
    ##################################################################################""")
    if errorMsg:
        print("\n   ERROR: %s" % errorMsg)

def fileBaseOf(filename, withPath=0):
    """fileBaseOf(filename,withPath) ---> string

    Return base name of filename.  The returned string never includes the extension.
    Use os.path.basename() to return the basename with the extension.  The
    second argument is optional.  If specified and if set to 'true' (non zero)
    the string returned contains the full path of the file name.  Otherwise the
    path is excluded.

    [Example]
    >>> fn = 'd:/dev/telepath/tvapp/code/test.html'
    >>> fileBaseOf(fn)
    'test'
    >>> fileBaseOf(fn)
    'test'
    >>> fileBaseOf(fn,1)
    'd:/dev/telepath/tvapp/code/test'
    >>> fileBaseOf(fn,0)
    'test'
    >>> fn = 'abcdef'
    >>> fileBaseOf(fn)
    'abcdef'
    >>> fileBaseOf(fn,1)
    'abcdef'
    >>> fn = "abcdef."
    >>> fileBaseOf(fn)
    'abcdef'
    >>> fileBaseOf(fn,1)
    'abcdef'
    """
    pos = filename.rfind('.')
    if pos > 0:
        filename = filename[:pos]
    if withPath:
        return filename
    else:
        return os.path.basename(filename)

def mkdir(directory):
    """Create a directory (and possibly the entire tree).

    The os.mkdir() will fail to create a directory if one of the
    directory in the specified path does not exist.  mkdir()
    solves this problem.  It creates every intermediate directory
    required to create the final path. Under Unix, the function
    only supports forward slash separator, but under Windows and MacOS
    the function supports the forward slash and the OS separator (backslash
    under windows).
    """

    # translate the path separators
    directory = unixpath(directory)
    # build a list of all directory elements
    aList = filter(lambda x: len(x) > 0, directory.split('/'))
    theLen = len(aList)
    # if the first element is a Windows-style disk drive
    # concatenate it with the first directory
    if aList[0].endswith(':'):
        if theLen > 1:
            aList[1] = aList[0] + '/' + aList[1]
            del aList[0]
            theLen -= 1
    # if the original directory starts at root,
    # make sure the first element of the list
    # starts at root too
    if directory[0] == '/':
        aList[0] = '/' + aList[0]
    # Now iterate through the list, check if the
    # directory exists and if not create it
    theDir = ''
    for i in range(theLen):
        theDir += aList[i]
        if not os.path.exists(theDir):
            os.mkdir(theDir)
        theDir += '/'

def unixpath(thePath):
    r"""Return a path name that contains Unix separator.

    [Example]
    >>> unixpath(r"d:\test")
    'd:/test'
    >>> unixpath("d:/test/file.txt")
    'd:/test/file.txt'
    >>>
    """
    thePath = os.path.normpath(thePath)
    if os.sep == '/':
        return thePath
    else:
        return thePath.replace(os.sep, '/')

# -----------------------------------------------------------------------------

# S c r i p t   e x e c u t i o n               -- Runs when invoked from the command line --
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
if __name__ == "__main__":
    # command line parsing
    import getopt    # pylint: disable=wrong-import-order,wrong-import-position
    argc = len(sys.argv)
    if argc == 1:
        printUsage('Missing argument: specify at least one of -m or -p (or both).')
        sys.exit(1)
    # If there is some arguments, parse the command line
    validOptions = "ehmpv"
    validLongOptions = ['domain=', 'moTarget=']
    option = {}
    option['forceEnglish'] = 0
    option['mo'] = 0
    option['po'] = 0
    option['verbose'] = 0
    option['domain'] = None
    option['moTarget'] = None
    optionKey = {
        '-e':         'forceEnglish',
        '-m':         'mo',
        '-p':         'po',
        '-v':         'verbose',
        '--domain':   'domain',
        '--moTarget': 'moTarget',
    }
    exit_code = 1
    try:
        optionList, pargs = getopt.getopt(sys.argv[1:], validOptions, validLongOptions)
    except getopt.GetoptError as e:
        printUsage(e)
        sys.exit(1)
    for (opt, val) in optionList:
        if opt == '-h':
            printUsage()
            sys.exit(0)
        option[optionKey[opt]] = 1 if val == '' else val
    if len(pargs) == 0:
        appDirPath = os.getcwd()
        if option['verbose']:
            print("No project directory given. Using current one:  %s" % appDirPath)
    elif len(pargs) == 1:
        appDirPath = pargs[0]
    else:
        printUsage('Too many arguments (%u).  Use double quotes if you have space in directory name' % len(pargs))
        sys.exit(1)
    if option['domain'] is None:
        # If no domain specified, use the name of the target directory
        option['domain'] = fileBaseOf(appDirPath)
    if option['verbose']:
        print("Application domain used is: '%s'" % option['domain'])
    if option['po']:
        try:
            makePO(appDirPath, option['domain'], option['verbose'])
            exit_code = 0
        except IOError as e:
            printUsage(text(e) + '\n   You must write a file app.fil that contains the list of all files to parse.')
    if option['mo']:
        makeMO(appDirPath, option['moTarget'], option['domain'], option['verbose'], option['forceEnglish'])
        exit_code = 0
    sys.exit(exit_code)

# -----------------------------------------------------------------------------


import torch
import torchvision
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
from torch.utils.data import DataLoader
from torch.optim import Adam, SGD
from torch.optim.lr_scheduler import ChainedScheduler, LinearLR, MultiStepLR
import argparse
import os
import math
import shutil

from resnet import MakeResnet
from helper_functions import CreateModelName
from conf import get_args
from imagenet_loader import ImagenetDataset
from tiny_imagenet_loader import TinyImagenetDataset
from create_model import CreateBlockwiseResnet

# from helper_functions import CreateModelName
# from imagenet_loader import ImagenetDataset
# from tiny_imagenet_loader import TinyImagenetDataset

def CreateDataLoaderlocal(args):

    if args.dataset == "cifar10":
        mean_dataset_norm = [0.4914, 0.4822, 0.4465]
        std_dataset_norm = [0.247, 0.2434, 0.2615]

    if args.dataset == "cifar100":
        mean_dataset_norm = [0.5071, 0.4867, 0.4408]
        std_dataset_norm = [0.2675, 0.2565, 0.2761]

    if args.dataset == "imagenet":
        mean_dataset_norm = [0.485, 0.456, 0.406]
        std_dataset_norm = [0.229, 0.224, 0.225]

    # must recompute imagenet values for now
    if args.dataset == "tiny_imagenet":
        mean_dataset_norm = [0.485, 0.456, 0.406]
        std_dataset_norm = [0.229, 0.224, 0.225]

    # train_transform = transforms.Compose([transforms.ToTensor(),
    #                                       transforms.Resize((32, 32)),
    #                                       transforms.RandomCrop(32, padding=4),
    #                                       transforms.Normalize(mean=mean_dataset_norm, std=std_dataset_norm),
    #                                       transforms.RandomHorizontalFlip(0.5)])

    test_transform = transforms.Compose([transforms.ToTensor(),
                                         transforms.Resize((32, 32)),
                                         transforms.Normalize(mean=mean_dataset_norm, std=std_dataset_norm)])

    # Defined transforms
    if args.dataset == "cifar10":
        train_dataset = torchvision.datasets.CIFAR10(root='./data', train=True, transform=test_transform)
        test_dataset = torchvision.datasets.CIFAR10(root='./data', train=False, transform=test_transform)

    if args.dataset == "cifar100":
        train_dataset = torchvision.datasets.CIFAR100(root='./data', train=True, transform=test_transform)
        test_dataset = torchvision.datasets.CIFAR100(root='./data', train=False, transform=test_transform)

    if args.dataset == "imagenet":
        train_dataset = ImagenetDataset(split='train', transforms=test_transform)
        test_dataset = ImagenetDataset(split='val', transforms=test_transform)

    # must recompute imagenet values for now
    if args.dataset == "tiny_imagenet":
        train_dataset = TinyImagenetDataset(split='train', transforms=test_transform)
        test_dataset = TinyImagenetDataset(split='val', transforms=test_transform)

    train_dataloader = DataLoader(train_dataset, batch_size=args.batch_size, shuffle=True)
    test_dataloader = DataLoader(test_dataset, batch_size=args.batch_size, shuffle=False)

    return train_dataloader, test_dataloader

def ConLoss(features1, features2, labels):

    temperature = 0.1

    features = torch.cat((features1, features2), dim=0)
    features = torch.nn.functional.normalize(features, dim=1)
    features = features.view(features.shape[0], features.shape[1], -1)

    labels = labels.view(-1, 1)
    mask = torch.eq(labels, labels.T).float().to(device)
    mask = torch.cat((mask, mask), dim=1)
    mask = torch.cat((mask, mask), dim=0)
    mask = mask - (torch.eye(mask.shape[0]).float().to(device).detach()).detach()

    contrast_feature = torch.cat(torch.unbind(features, dim=1), dim=0) ## reshaped such that first bsz rows are first channel of all inputs, second bsz rows is 2nd channel ...  torch.unbind(features, dim=1) has shape (bsz, feature.shape[-1])

    f_dot_f = torch.matmul(contrast_feature, contrast_feature.T)/temperature

    f_max, _ = torch.max(f_dot_f, dim=1, keepdim=True)
    f_dot_f = f_dot_f - f_max.detach()

    # norm = torch.sqrt(torch.sum(torch.square(f_dot_f), dim=1, keepdim=True)).detach()
    # f_dot_f = f_dot_f/norm

    mask = torch.tile(mask, (features.shape[1], features.shape[1]))
    anchor_dot_pos = torch.mul(f_dot_f, mask)

    mask_all = (torch.ones_like(f_dot_f) - torch.eye(f_dot_f.shape[0]).to(device)).detach()
    anchor_dot_all = torch.exp(torch.mul(f_dot_f, mask_all))

    # print(features.shape, mask.shape, contrast_feature.shape, f_dot_f.shape, anchor_dot_all.shape)
    # print()
    # exit()

    loss = anchor_dot_pos - torch.log(torch.sum(anchor_dot_all, dim=1, keepdim=True))
    loss = loss * (-1/torch.sum(mask, dim=1, keepdim=True))

    loss = loss.mean()

    return loss

def train():

    train_loss = 0
    train_acc = 0
    num_train_images = 0
    for idx, (images, labels) in enumerate(train_dataloader):

        optim.zero_grad()
        images = images.to(device)
        labels = labels.to(device)

        images1 = transform_extra(images)
        images2 = transform_extra(images)

        out1 = model(images1)
        out2 = model(images2)

        pred1 = torch.argmax(out1, dim=1)
        pred2 = torch.argmax(out2, dim=1)

        ce_loss = (cross_entropy_loss(out1, labels) + cross_entropy_loss(out2, labels))/2
        con_loss = ConLoss(out1, out2, labels)
        loss = (ce_loss + con_loss)/2

        train_acc += (torch.sum(torch.where(pred1==labels, 1, 0)) + torch.sum(torch.where(pred2==labels, 1, 0)))/2
        train_loss += loss.item()
        num_train_images += images.shape[0]

        loss.backward()
        optim.step()

    train_acc = train_acc/num_train_images
    # train_loss = train_loss/num_train_images_set

    return train_acc, train_loss, ce_loss, con_loss

def test():

    test_loss = 0
    test_acc = 0
    num_test_images = 0

    for idx,  (images, labels) in enumerate(test_dataloader):

        images = images.to(device)
        labels = labels.to(device)

        images1 = transform_extra(images)
        images2 = transform_extra(images)

        out1 = model(images1)
        out2 = model(images2)

        pred1 = torch.argmax(out1, dim=1)
        pred2 = torch.argmax(out2, dim=1)

        ce_loss = (cross_entropy_loss(out1, labels) + cross_entropy_loss(out2, labels))/2
        con_loss = ConLoss(out1, out2, labels)
        loss = (ce_loss + con_loss)/2

        test_acc += (torch.sum(torch.where(pred1==labels, 1, 0)) + torch.sum(torch.where(pred2==labels, 1, 0)))/2
        test_loss += loss.item()
        num_test_images += images.shape[0]

        # num_test_images += images.shape[0]
        # num_test_images_set += 1

    test_acc = test_acc/num_test_images
    # test_loss = test_loss/num_test_images_set

    return test_acc, test_loss, ce_loss, con_loss

if __name__ == "__main__":
    device = 'cuda' if torch.cuda.is_available() else 'cpu'

    args = get_args()
    parameters = CreateModelName(args)
    writer = SummaryWriter('./runs/{}/{}/'.format(args.dataset, args.model_name))

    train_dataloader, test_dataloader = CreateDataLoaderlocal(args)

    model = parameters['model']
    optim_parameters = parameters['optim_parameters']
    num_layers_below = parameters['num_layers_below']
    base_size = parameters['base_size']
    layer_increase = parameters['layer_increase']
    share_pos = parameters['share_pos']
    num_epochs_per_each_block = parameters['num_epochs_per_each_block']
    output_size = parameters['output_size']

    transform_extra = transforms.Compose([transforms.RandomCrop(32, padding=4),
                                          transforms.RandomHorizontalFlip(0.5),
                                          transforms.RandomVerticalFlip(0.5)])

    model = model.to(device)
    cross_entropy_loss = nn.CrossEntropyLoss(reduction='mean')

    # Set the optimizer and scheduler for non-blockwise training
    if not args.train_solo_layers:
        if not args.share_weights:
            optim = Adam(optim_parameters, lr=args.lr, weight_decay=1e-5)
            lr_scheduler = MultiStepLR(optim, milestones=[0.3*args.n_epochs, 0.6*args.n_epochs, 0.8*args.n_epochs], gamma=0.2, last_epoch=-1)
        else:
            ## Warmup when weight sharing
            optim = Adam(optim_parameters, lr=args.lr, weight_decay=1e-5)
            lr_scheduler = ChainedScheduler([MultiStepLR(optim, milestones=[0.3*args.n_epochs, 0.6*args.n_epochs, 0.8*args.n_epochs], gamma=0.2, last_epoch=-1),
                                             LinearLR(optim, start_factor=1, end_factor=1, total_iters=0.1*args.n_epochs)])

    model.train()
    test_loss_max = 1e9
    prev_epoch = 0

    for epoch in range (args.n_epochs):

        # If adding and training layers sequentially, update the optimizer, scheduler, and num epochs accordingly
        if args.train_solo_layers and args.share_weights and (share_pos == -1 or (share_pos != -1 and epoch-prev_epoch >= num_epochs_per_each_block[share_pos])):
            test_loss_max = 1e9
            prev_epoch = epoch
            share_pos += 1

            if share_pos > 0:
                base_size[share_pos] += layer_increase[share_pos]
                model, optim_parameters = CreateBlockwiseResnet(args, base_size, output_size, './weights/{}/{}/model.pth'.format(args.dataset, args.model_name), share_pos)
                model.to(device)

            for key, value in model.named_parameters():
                print(key, value.requires_grad)

            optim = Adam(optim_parameters, lr=args.lr, weight_decay=1e-5)

            # Warmup
            lr_scheduler = ChainedScheduler([MultiStepLR(optim, milestones=[int(0.3*num_epochs_per_each_block[share_pos]), int(0.6*num_epochs_per_each_block[share_pos]), int(0.8*num_epochs_per_each_block[share_pos])], gamma=0.2, last_epoch=-1),
                                             LinearLR(optim, start_factor=1, end_factor=1, total_iters=0.2*num_epochs_per_each_block[share_pos])])

        train_acc, train_loss, ce_loss_train, con_loss_train = train()
        test_acc, test_loss, ce_loss_test, con_loss_test = test()

        if test_loss < test_loss_max:

            test_loss_max = test_loss
            torch.save(model.state_dict(), './weights/{}/{}/model.pth'.format(args.dataset, args.model_name))

            if args.share_weights:
                # Because of warmup
                torch.save({'train_loss': train_loss,
                            'train_acc': train_acc,
                            'test_loss': test_loss,
                            'test_acc': test_acc,
                            'ce_loss_train': ce_loss_train,
                            'con_loss_train': con_loss_train,
                            'ce_loss_test': ce_loss_test,
                            'con_loss_test': con_loss_test,
                            'epoch': epoch,
                            'lr': lr_scheduler._schedulers[-1].get_last_lr()}, './weights/{}/{}/info.pth'.format(args.dataset, args.model_name))

            else:
                # Because of no warmup
                torch.save({'train_loss': train_loss,
                            'train_acc': train_acc,
                            'test_loss': test_loss,
                            'test_acc': test_acc,
                            'ce_loss_train': ce_loss_train,
                            'con_loss_train': con_loss_train,
                            'ce_loss_test': ce_loss_test,
                            'con_loss_test': con_loss_test,
                            'epoch': epoch,
                            'lr': lr_scheduler.get_last_lr()}, './weights/{}/{}/info.pth'.format(args.dataset, args.model_name))

        if args.share_weights:
            print("Epoch: {}/{}, model: {}, lr multi step: {}, lr final: {}".format(epoch, args.n_epochs, args.model_name, lr_scheduler._schedulers[0].get_last_lr()[0], lr_scheduler._schedulers[-1].get_last_lr()[0]))
        else:
            print("Epoch: {}/{}, model: {}, lr: {}".format(epoch, args.n_epochs, args.model_name, lr_scheduler.get_last_lr()[0]))

        writer.add_scalar('Train Loss', train_loss, epoch)
        writer.add_scalar('Train Acc', train_acc, epoch)
        writer.add_scalar('Val Loss', test_loss, epoch)
        writer.add_scalar('Val Acc', test_acc, epoch)

        lr_scheduler.step()

        if mc.block[mc.cur_pos][-1] == -1:

            # images = torch.cat((images[0], images[1]), dim=0)
            # labels = torch.cat((labels, labels), dim=0)

            # images = images.to(device)
            # labels = labels.to(device)

            # out, features = model(images)

            # _, features1 = model(images1)
            # _, features2 = model(images2)

            # features = torch.stack((features1, features2), dim=1)

            bsz = labels.shape[0]
            images = torch.cat((images[0], images[1]), dim=0)

            images = images.to(device)
            labels = labels.to(device)

            _, f = model(images)

            f1, f2 = torch.split(f, [bsz, bsz], dim=0)
            features = torch.cat([f1.unsqueeze(1), f2.unsqueeze(1)], dim=1)

            ce_loss = torch.tensor(0.).to(device)
            train_acc = torch.tensor(0.).to(device)

            con_loss = contrastive_loss(features, labels)

            loss = con_loss


from getmac import get_mac_address as gma
import sys
import os
import getopt

#varibles
mac = None
mac_vendor = ""
#argv
argv = sys.argv[1:]
opts, args = getopt.getopt(argv, "i:m:h", ["ip=", "mac=", "help"])

archivo = open("archivo.txt", "r")
def getmac(ipadress):
    mac = gma(ip=ipadress)
    return mac

def Vendor_Check(mac):
    lista = mac.split(sep=":")
    mac_vendor = ""
    for x in range(4):
        mac_vendor = mac_vendor + lista[x] + ":"
    print(mac_vendor)

for opt, arg in opts:
    if opt in ('-i', '--ip'):
        Vendor_Check(getmac(arg))

def vendors():
    lineas = archivo.read()
    for linea in lineas:
        print(linea)

vendors()


#!/usr/bin/env python3

import rospy
from std_msgs.msg import String, Float32MultiArray, Bool
import time

class small_demo:
    def __init__(self):
        rospy.init_node('head_neck_screen_demo')
        rospy.Subscriber("cmd_frm_tablet", String, self.demo_callback)
        rospy.Subscriber('/battery_info', Float32MultiArray, self.battery_info_callback)
        rospy.Subscriber('/environmental_info', Float32MultiArray, self.environmental_info_callback)
        rospy.Subscriber('/column_button', Bool, self.button_callback)
        self.pub=rospy.Publisher("/feedback_to_tablet", String, queue_size=10)
        self.battery_percentage = 0
        self.temperature = 0
        self.button_state = False
        self.button_pressed_times = []
        self.button_pressed_count = 0

    def environmental_info_callback(self, msg):
        self.temperature = msg.data[5]

    # Callback function to handle incoming messages
    def button_callback(self, msg):
        self.button_state = msg.data
        if msg.data:  # If the button is pressed (message is True)
            current_time = time.time()
            self.button_pressed_times.append(current_time)
            # Remove timestamps older than 3 seconds
            self.button_pressed_times = [t for t in self.button_pressed_times if current_time - t <= 3][-4:]
            #print(self.button_pressed_times)

            self.button_pressed_count = len(self.button_pressed_times)

            if self.button_pressed_count == 1:
                rospy.set_param('/led_1_set', "green")
                rospy.set_param('/led_2_set', "off")

            elif self.button_pressed_count == 2:
                rospy.set_param('/led_1_set', "off")
                rospy.set_param('/led_2_set', "red")
            elif self.button_pressed_count == 3:
                rospy.set_param('/led_1_set', "off")
                rospy.set_param('/led_2_set', "off")
                rospy.set_param('/neck_cmd', "2")
                screen_msg = "hello,"+"Hi How are you,10"
                self.pub.publish(screen_msg)
                rospy.sleep(8)
                screen_msg = "hello,"+"Battery is "+str(int(self.battery_percentage))+"%"+ "   Temperature is "+str(int(self.temperature))+ "°C"+",10"
                self.pub.publish(screen_msg)
                rospy.sleep(1)

    def battery_info_callback(self, msg):
        self.battery_percentage = msg.data[3]

    def demo_callback(self, msg):
        global pub
        string_values = msg.data.split(',')
        if string_values[1] == "goto":
            if string_values[4]== "5":
                #print("got text")
                screen_msg = "hello,Hello to you,10"
                rospy.set_param('/neck_cmd', "2")
                self.pub.publish(screen_msg)
                rospy.sleep(5)
                rospy.set_param('/neck_cmd', "6")
                rospy.sleep(10)
                rospy.set_param('/neck_cmd', "2")
                rospy.sleep(1)
                screen_msg = "hello,"+"Battery = "+str(int(self.battery_percentage))+"%"+ "   Temperature = "+str(int(self.temperature))+ "°C"+",10"
                self.pub.publish(screen_msg)
                rospy.sleep(1)

            if string_values[4]== "6":
                rospy.set_param('/neck_cmd', "1")
                rospy.sleep(1)

        if string_values[1] == "turnaround":
            screen_msg = "image,1821126_edit.jpg,5"
            self.pub.publish(screen_msg)
            rospy.sleep(1)

if __name__ == '__main__':
    autonav_node = small_demo()
    rospy.spin()


from functools import wraps

import numpy as np

def handle_0D_1D_input(
    patched_kwargs: [], patched_argpos: [], return_scalar=False
):
    """
    A decorator that handles 0D, 1D inputs and transforms them to 2D.

    Parameters
    ----------
    kwarg : list of str
        The names of the keyword arguments that should be handeled.
    argpos : list of int
        The positions of the arguments that should be handeled.
    return_scalar : bool, optional
        If the input is 1D the function should return a scalar,
        by default False.
    """

    def decorator(function):
        @wraps(function)
        def wrapper(self, *args, **kwargs):
            for idx, patched_kwarg in enumerate(patched_kwargs):
                if patched_kwarg in kwargs:
                    # for keyword arguments
                    input_dims = np.ndim(kwargs.get(patched_kwarg))
                    kwargs[patched_kwarg] = np.atleast_2d(
                        kwargs.get(patched_kwarg)
                    )

                elif len(args) > patched_argpos[idx]:
                    # for positional arguments
                    arg_list = list(args)
                    input_dims = np.ndim(args[patched_argpos[idx]])
                    arg_list[patched_argpos[idx]] = np.atleast_2d(
                        args[patched_argpos[idx]]
                    )
                    args = tuple(arg_list)

            res = function(self, *args, **kwargs)

            # return value 1D or scalar when boolean set
            if input_dims == 1:
                # handle functions with multiple return values
                if type(res) is tuple:
                    returnvalues = list(res)
                    returnvalues = [o.ravel() for o in returnvalues]
                    if return_scalar:
                        returnvalues = [o[0] for o in returnvalues]
                    return tuple(returnvalues)

                elif return_scalar and np.ndim(res) != 0:
                    return res.ravel()[0]
                elif np.ndim(res) != 0:
                    return res.ravel()

            return res

        return wrapper

    return decorator


import pandas as pd
import numpy as np
import datetime
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import colors
import seaborn as sns
from sklearn.preprocessing import LabelEncoder, OneHotEncoder, OrdinalEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt, numpy as np
from mpl_toolkits.mplot3d import Axes3D
from sklearn.cluster import AgglomerativeClustering
from matplotlib.colors import ListedColormap
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.svm import SVR
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error,mean_absolute_error,mean_absolute_percentage_error,r2_score
from sklearn.metrics import f1_score, accuracy_score
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
import pickle

data=pd.read_csv("data/Fraud Claims.csv")
req_col=['Month', 'WeekOfMonth', 'DayOfWeek',
       'DayOfWeekClaimed', 'MonthClaimed', 'WeekOfMonthClaimed', 'Fault',
       'FraudFound_P', 'RepNumber', 'Days_Policy_Accident',
       'Days_Policy_Claim', 'PoliceReportFiled', 'WitnessPresent', 'AgentType',
       'NumberOfSuppliments', 'AddressChange_Claim', 'BasePolicy',
       'Vehicle Class', 'AccidentArea', 'Age', 'Product Name', 'VehiclePrice',
       'DriverRating', 'AgeOfVehicle']
reduced_data=data[req_col]
def var_sep(x):
    categorical_columns=[]
    numerical_columns=[]
    data_type=pd.DataFrame(x.dtypes).reset_index()
    data_type.columns=["variable_name","data_type"]
    for i in range(0,len(data_type)):
        if data_type.data_type[i]=="object":
            categorical_columns.append(data_type.variable_name[i])
        else:
            numerical_columns.append(data_type.variable_name[i])
    return categorical_columns,numerical_columns

cat_col,num_col=var_sep(reduced_data)
outlier_cols=["Age"]
def outlier_treatment():
    for i in range(0, len(outlier_cols)):
        pecentile10 = np.percentile(data[outlier_cols[i]], 10)
        percentile90 = np.percentile(data[outlier_cols[i]], 90)
        for j in range(0, len(data[outlier_cols[i]])):
            data[outlier_cols[i]][j] = np.where(data[outlier_cols[i]][j] > percentile90, percentile90,
                                                data[outlier_cols[i]][j])
            data[outlier_cols[i]][j] = np.where(data[outlier_cols[i]][j] < pecentile10, pecentile10,
                                                data[outlier_cols[i]][j])
outlier_treatment()

def label_encoding():
    global enc_data
    le = LabelEncoder()
    enc_data = reduced_data.copy()
    for i in cat_col:
        label_encoding = le.fit_transform(enc_data[i])
        enc_data[i] = label_encoding
label_encoding()

def x_y():
    global X
    global Y
    X = enc_data.drop(columns=["FraudFound_P"])
    Y = enc_data["FraudFound_P"]
x_y()

gaussian_pipeline=Pipeline([('Gaussian Naive Bayes',GaussianNB())])
SVC_pipeline=Pipeline([('Support Vector Classifier',SVC(kernel = 'rbf', probability = True))])
DTC_pipeline=Pipeline([('Decision Tree Classifier',DecisionTreeClassifier(random_state = 0))])
RFC_pipeline=Pipeline([('Random Forest Classifier',RandomForestClassifier(n_estimators = 100, random_state = 0))])
GBC_pipeline=Pipeline([('Gradient Boosting Classifier',GradientBoostingClassifier(random_state = 0))])
KNN_pipeline=Pipeline([('K-Nearest Neighbours',KNeighborsClassifier(n_neighbors=5))])

classifier_list=[gaussian_pipeline,SVC_pipeline,DTC_pipeline,RFC_pipeline,GBC_pipeline,KNN_pipeline]
classifiers = [GaussianNB(),
               SVC(kernel = 'rbf', probability = True),
               DecisionTreeClassifier(random_state = 0),
               RandomForestClassifier(n_estimators = 100, random_state = 0),
               GradientBoostingClassifier(random_state = 0),
               KNeighborsClassifier(n_neighbors=5)
              ]
classifier_names = ["Gaussian Naive Bayes",
                    "Support Vector Classifier",
                    "Decision Tree Classifier",
                    "Random Forest Classifier",
                    "Gradient Boosting Classifier",
                   "K-Nearest Neighbours"]
accuracies = []
x_train,x_test,y_train,y_test=train_test_split(X,Y,test_size=0.2)
pred_df2=pd.DataFrame()
def fit_predict():
    for i in range(len(classifier_list)):
        classifier_list[i].fit(x_train, y_train)
        y_pred = classifier_list[i].predict(x_test)
        pred_df2[i] = y_pred

fit_predict()

def acc():
    for i in range(len(classifiers)):
        accuracy = accuracy_score(y_test, pred_df2[i]) * 100
        accuracies.append(accuracy)

acc()

def model_selection():
    for i in range(0, len(accuracies)):
        if accuracies[i] == pd.Series(accuracies).max():
            pickle.dump(classifier_list[i], open('best_fraud_classification_model.pkl', 'wb'))

model_selection()


# count number of items brought in total

allGuests = {'Alice': {'apples': 5, 'pretzels': 12},
             'Bob': {'ham sandwiches': 3, 'apples': 2},
             'Carol': {'cups': 3, 'apple pies': 1}}

# create definition
def totalBrought(guests, product):
    numBrought = 0

    for k, v in guests.items():
        numBrought = numBrought + v.get(product, 0)

    return numBrought

print('number of things brought:')
print('Apples: ' + str(totalBrought(allGuests, 'apples')))
print('Cakes: ' + str(totalBrought(allGuests, 'cakes')))


import torch
import numpy as np
from scipy import interpolate

def load_pretrained(checkpoint_path, model, simmim):

    if not simmim:
        load_pretrained_swin(checkpoint_path, model)
    else:
        load_pretrained_simmim(checkpoint_path, model)

def load_pretrained_swin(checkpoint_path, model):
    checkpoint = torch.load(checkpoint_path, map_location='cpu')
    model_key = 'model' if 'model' in checkpoint else 'model_state'
    ckpt_state_dict = checkpoint[model_key]

    # delete relative_position_index since we always re-init it
    relative_position_index_keys = [k for k in ckpt_state_dict.keys() if "relative_position_index" in k]
    for k in relative_position_index_keys:
        del ckpt_state_dict[k]

    # delete relative_coords_table since we always re-init it
    relative_position_index_keys = [k for k in ckpt_state_dict.keys() if "relative_coords_table" in k]
    for k in relative_position_index_keys:
        del ckpt_state_dict[k]

    # delete attn_mask since we always re-init it
    attn_mask_keys = [k for k in ckpt_state_dict.keys() if "attn_mask" in k]
    for k in attn_mask_keys:
        del ckpt_state_dict[k]

    # bicubic interpolate relative_position_bias_table if not match
    relative_position_bias_table_keys = [k for k in ckpt_state_dict.keys() if "relative_position_bias_table" in k]
    for k in relative_position_bias_table_keys:
        relative_position_bias_table_pretrained = ckpt_state_dict[k]
        relative_position_bias_table_current = model.state_dict()[k]
        L1, nH1 = relative_position_bias_table_pretrained.size()
        L2, nH2 = relative_position_bias_table_current.size()

        assert nH1 == nH1, "Number of heads should be the same"
        if L1 != L2:
            # bicubic interpolate relative_position_bias_table if not match
            S1 = int(L1 ** 0.5)
            S2 = int(L2 ** 0.5)
            relative_position_bias_table_pretrained_resized = torch.nn.functional.interpolate(
                relative_position_bias_table_pretrained.permute(1, 0).view(1, nH1, S1, S1), size=(S2, S2),
                mode='bicubic')
            ckpt_state_dict[k] = relative_position_bias_table_pretrained_resized.view(nH2, L2).permute(1, 0)

    # bicubic interpolate absolute_pos_embed if not match
    absolute_pos_embed_keys = [k for k in ckpt_state_dict.keys() if "absolute_pos_embed" in k]
    assert absolute_pos_embed_keys == [], "Absolute pos embedings should be zero"

    # changing head
    head_bias_pretrained = ckpt_state_dict['head.bias']
    Nc1 = head_bias_pretrained.shape[0]
    Nc2 = model.head.bias.shape[0]
    in_features = model.head.in_features
    # changing head for loading model
    if Nc1 != Nc2:
        model.head = torch.nn.Linear(in_features, Nc1)
    model.load_state_dict(ckpt_state_dict, strict=False)

    del checkpoint
    torch.cuda.empty_cache()

def load_pretrained_simmim(checkpoint_path, model):
    checkpoint = torch.load(checkpoint_path, map_location='cpu')
    model_key = 'model' if 'model' in checkpoint else 'model_state'
    ckpt_state_dict = checkpoint[model_key]

    # remove [encoder.] prefix.
    if any([True if 'encoder.' in k else False for k in ckpt_state_dict.keys()]):
        ckpt_state_dict = {k.replace('encoder.', ''): v for k, v in ckpt_state_dict.items() if k.startswith('encoder.')}

    ckpt_state_dict = remap_pretrained_keys_swin(model, ckpt_state_dict)
    model.load_state_dict(ckpt_state_dict, strict=False)

    del checkpoint
    torch.cuda.empty_cache()

def remap_pretrained_keys_swin(model, checkpoint_model):
    state_dict = model.state_dict()

    # Geometric interpolation when pre-trained patch size mismatch with fine-tuned patch size
    all_keys = list(checkpoint_model.keys())
    for key in all_keys:
        if "relative_position_bias_table" in key:
            relative_position_bias_table_pretrained = checkpoint_model[key]
            relative_position_bias_table_current = state_dict[key]
            L1, nH1 = relative_position_bias_table_pretrained.size()
            L2, nH2 = relative_position_bias_table_current.size()

            assert nH1 == nH1, "Number of heads should be the same"
            # Interpolate relative_position_bias_table using geo.
            if L1 != L2:
                src_size = int(L1 ** 0.5)
                dst_size = int(L2 ** 0.5)

                def geometric_progression(a, r, n):
                    return a * (1.0 - r ** n) / (1.0 - r)

                left, right = 1.01, 1.5
                while right - left > 1e-6:
                    q = (left + right) / 2.0
                    gp = geometric_progression(1, q, src_size // 2)
                    if gp > dst_size // 2:
                        right = q
                    else:
                        left = q

                # if q > 1.090307:
                #     q = 1.090307

                dis = []
                cur = 1
                for i in range(src_size // 2):
                    dis.append(cur)
                    cur += q ** (i + 1)

                r_ids = [-_ for _ in reversed(dis)]

                x = r_ids + [0] + dis
                y = r_ids + [0] + dis

                t = dst_size // 2.0
                dx = np.arange(-t, t + 0.1, 1.0)
                dy = np.arange(-t, t + 0.1, 1.0)
                all_rel_pos_bias = []

                for i in range(nH1):
                    z = relative_position_bias_table_pretrained[:, i].view(src_size, src_size).float().numpy()
                    f_cubic = interpolate.interp2d(x, y, z, kind='cubic')
                    all_rel_pos_bias.append(torch.Tensor(f_cubic(dx, dy)).contiguous().view(-1, 1).to(
                        relative_position_bias_table_pretrained.device))

                new_rel_pos_bias = torch.cat(all_rel_pos_bias, dim=-1)
                checkpoint_model[key] = new_rel_pos_bias

    # delete relative_position_index since we always re-init it
    relative_position_index_keys = [k for k in checkpoint_model.keys() if "relative_position_index" in k]
    for k in relative_position_index_keys:
        del checkpoint_model[k]

    # delete relative_coords_table since we always re-init it
    relative_coords_table_keys = [k for k in checkpoint_model.keys() if "relative_coords_table" in k]
    for k in relative_coords_table_keys:
        del checkpoint_model[k]

    # re-map keys due to name change
    rpe_mlp_keys = [k for k in checkpoint_model.keys() if "rpe_mlp" in k]
    for k in rpe_mlp_keys:
        checkpoint_model[k.replace('rpe_mlp', 'cpb_mlp')] = checkpoint_model.pop(k)

    # delete attn_mask since we always re-init it
    attn_mask_keys = [k for k in checkpoint_model.keys() if "attn_mask" in k]
    for k in attn_mask_keys:
        del checkpoint_model[k]

    return checkpoint_model


import os
import click
import requests
from .utils import prepare_path, save_list_and_cache, write_to, get_result
from .help import BRANDING

prepare_path()

# @click.group()
@click.command()
@click.argument('ignore', required=False)
@click.version_option(message=BRANDING)
@click.option('-a', '--listall', help='Get all available terms', default=False, is_flag=True)
# @click.pass_context
def cli(listall, ignore):
    """ AzatAI Addignore Automation tool. Searches for a proper .gitignore file for your project and adds to the
        local .gitignore file.
        Search for operating systems, IDEs, languages and other environmental terms. Use ',' to separate multiple items.
        Usage: addignore python """
    # ensure that ctx.obj exists and is a dict (in case `cli()` is called
    # by means other than the `if` block below)
    # ctx.ensure_object(dict)
    prepare_path()
    if ignore:
        here = os.getcwd()
        file_path = os.path.join(here, '.gitignore')
        write_to(get_result(ignore), file_path, mode='file')
    elif not ignore and listall:
        click.secho(save_list_and_cache())
    else:
        with click.get_current_context() as context:
            click.echo(context.get_help())

# @cli.command()
# @click.pass_context
# def list(ctx):
#     """Prints all the available results."""
#     click.secho('Hello')

if __name__ == '__main__':
    cli()


#load matplotlib.pyplot as plt
import matplotlib.pyplot as plt

#load numpy as np
import numpy as np

#x range: [-pi, pi]
x = np.linspace(-np.pi, np.pi, 256, endpoint = True)

#y = sin(x)
y_sin = np.sin(x)
#y = cos(x)
y_cos = np.cos(x)

#Figure & subplot
fig = plt.figure(figsize = (12,8))
ax = fig.add_subplot(1,1,1)

#Graph
ax.plot(x, y_sin, 'r', linewidth = 2.0, label = 'sin')
ax.plot(x, y_cos, 'b', linewidth = 2.0, label = 'cos')

#Set limits
ax.set_xlim(-4,4)
ax.set_ylim(-1.5,1.5)

#Set ticks
ax.set_xticks(np.linspace(-np.pi, np.pi, 5, endpoint = True))
ax.set_yticks(np.linspace(-1.5, 1.5, 5, endpoint = True))

#Set spines
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',0))

#Set labels
ax.set_title('trigonometric function')
ax.set_xlabel('X')
ax.set_ylabel('Y')

#Set legend
ax.legend(loc = 'best')

#no margin
plt.tight_layout()
plt.show() ## Figure_1


from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

from data_processing.transformers.CommonSimilarity import CommonSimilarity
from data_processing.transformers.ToPandas import ToPandas
from recommend.transformers.CosSimilarity import CosSimilarity
from recommend.transformers.FetchSimilarItems import FetchSimilarItems

def recommend(instance, dataset_processed, dataset_preprocessed, num_recommendations):
    """
    Provides recommendations for a specific instance based on processed Steam game dataset.

    This function takes an instance from the dataset and calculates its similarity with other instances
    in the dataset, both numerical and categorical. It then returns a set number of items most similar
    to the given instance.

    Parameters:
    instance (Series): The instance for which recommendations are to be made.
    dataset_processed (DataFrame): The processed dataframe used to calculate similarities.
    dataset_preprocessed (DataFrame): The preprocessed dataframe to fetch recommendation details.
    num_recommendations (int): The number of recommendations to be returned.

    Pipeline steps:
    1. Similarity_preprocessor: Calculates cosine similarity for numerical and categorical columns.
    2. ToPandas1: Converts the numpy array to a pandas dataframe with similarity scores.
    3. CommonSimilarity: Calculates a common similarity score based on numerical and categorical similarity scores.
    4. ToPandas2: Converts the numpy array with common similarity scores back to a pandas dataframe.
    5. FetchSimilarItems: Fetches the required number of items most similar to the given instance.

    Returns:
    DataFrame: A dataframe with the recommended items, including their URL, title, and steam_id.
    """
    print('Recommending...')

    similarity_calc_numerical_columns = ['price_eur', 'release_date', 'steam_rating', 'total_overall_reviews',
                                          'positive_overall_reviews']
    similarity_calc_categorical_columns = [col for col in dataset_processed.columns if 'app_tags' in col]
    columns_to_place_back = similarity_calc_numerical_columns.copy()
    columns_to_place_back.append('num_similarity')
    columns_to_place_back.extend(similarity_calc_categorical_columns)
    columns_to_place_back.append('cat_similarity')
    columns_to_place_back.append('com_similarity')

    index_to_place_back = dataset_processed.index

    instance_index = instance.index
    instance = dataset_processed.loc[instance_index]

    recommendation_pipeline = Pipeline([
        ('similarity_preprocessor', ColumnTransformer(transformers=[
            ('num', CosSimilarity(instance, 'num'), similarity_calc_numerical_columns),
            ('cat', CosSimilarity(instance, 'cat'), similarity_calc_categorical_columns)
        ],
            remainder='passthrough')),
        ('to_pandas1', ToPandas(columns=columns_to_place_back, index=index_to_place_back)),
        ('common_similarity', CommonSimilarity(numerical_weight=1, categorical_weight=0.6)),
        ('to_pandas2', ToPandas(columns=columns_to_place_back, index=index_to_place_back)),
        ('fetch_similar_items', FetchSimilarItems(num_recommendations=num_recommendations))
    ])

    recommended_items = recommendation_pipeline.fit_transform(dataset_processed)
    recommended_items_index = recommended_items.index
    recommended_items['url'] = dataset_preprocessed.loc[recommended_items_index]['url']
    recommended_items['title'] = dataset_preprocessed.loc[recommended_items_index]['title']
    recommended_items['steam_id'] = dataset_preprocessed.loc[recommended_items_index]['steam_id']

    print('Recommending: Done.\n')
    return recommended_items


import cPickle as pickle

import scipy.io

import numpy as np

import theano.tensor as T
import theano
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams

from utils import *

#this scrip is designed to produce prediction results from the pickled
#models generated by the utils and cnnlearning scripts

def load_dataset_test():
    """Open the file located at ../train/test.mat and extracts a tuple
    CNNDat,HogDat,FullDat"""
    train = scipy.io.loadmat('../train/test.mat')
    data = train['test'][0,0]
    xcnndat = data[0]
    xhogdat = data[1]
    xfulldat = np.concatenate((xhogdat, xcnndat),axis=1)
    return xcnndat,xhogdat,xfulldat

def model(X, w_h, b_h, w_h2, b_h2, w_o, b_o, p1, p2):
    """Define the output tensor of the model given its inputs and
    parameters."""
    X = dropout(X, srng, p1)
    h = rectify(T.dot(X, w_h)+b_h)

    h = dropout(h, srng, p2)
    h2 = rectify(T.dot(h, w_h2)+b_h2)

    h2 = dropout(h2, srng, p2)
    py_x = softmax(T.dot(h2, w_o)+b_o)
    return py_x

if __name__=='__main__':
    srng = RandomStreams()
    #switch between mult and bin to have results for multiclass or binary
    #classification.
    tog = 'mult'
    #this variable gives the version of the pickled parameters you want to
    #use
    suff = '900'
    if tog == 'mult':
        input_dir = 'models/'
        dmap = {3:np.array([1,0,0,0]),4:np.array([0,1,0,0]),
                2:np.array([0,0,1,0]),1:np.array([0,0,0,1])}
        rmap = {0:3,1:4,2:2,3:1}
        filename = 'pred_multiclass'
    else:
        input_dir = 'models_bin/'
        dmap = {1:np.array([1,0]),2:np.array([1,0]),3:np.array([1,0]),
                4:np.array([0,1])}
        filename = 'pred_binary'
    _,_,x = load_dataset_test()

    #usual theano stuffs
    teX = theano.shared(floatX(x))

    w_h = theano.shared(floatX(pickle.load(open(input_dir+'w_h'+suff,'rb'))))
    w_h2 = theano.shared(floatX(pickle.load(open(input_dir+'w_h2'+suff,'rb'))))
    b_h = theano.shared(floatX(pickle.load(open(input_dir+'b_h'+suff,'rb'))))
    b_h2 = theano.shared(floatX(pickle.load(open(input_dir+'b_h2'+suff,'rb'))))
    w_o = theano.shared(floatX(pickle.load(open(input_dir+'w_o'+suff,'rb'))))
    b_o = theano.shared(floatX(pickle.load(open(input_dir+'b_o'+suff,'rb'))))

    X = T.dmatrix()

    py_x = model(X,w_h,b_h,w_h2,b_h2,w_o,b_o,0.,0.)
    y_x = T.argmax(py_x,axis=1)

    predict = theano.function(inputs=[],outputs=y_x,
                              givens={
                                  X:teX
                              })
    tres = predict()
    res = np.zeros((tres.shape[0],1))
    if tog=='mult':
        for i,it in enumerate(tres):
            res[i] = rmap[tres[i]]
    else:
        for i,it in enumerate(tres):
            res[i] = 1-tres[i]
    scipy.io.savemat(filename+'.mat',mdict={'Ytest':res})


from fastapi import FastAPI
from models import User, UserBet, VerifyRequest

app = FastAPI()

@app.post("/server_seed")
def get_hashed_server_seed(request: User):
    resp = request.get_server_seed()
    return resp

@app.post("/bet")
def bet(request: UserBet):
    resp = request.process()
    return resp

@app.post("/verify")
def verify(request: VerifyRequest):
    resp = request.process()
    return resp